关于Drupal性能的优化,文章Drupal高性能经验漫谈中提及多种方法,但在数据库的架构方面,我们还没有讨论到MySQL的主从架构,即Master/Slave如何在Drupal中应用。
众所周知,MySQL的master/slave模式对于提高数据库访问层的性能是非常有效的,本文就在Drupal中如何应用mysql当master/slave做一下简单介绍。
默认情况下Drupal6并不支持master/slave结构,即使是Drupal的Pressflow版本,也是只提供相关函数,并不能把已有的db_query定向到slave数据库,因此有必要在drupal到query机制中加入router的功能。
根据Drupal.org上面这篇文章的讨论,笔者总结了一下,并作了相应的改良,http://drupal.org/node/469274
比如sql过滤中会出现过滤掉某些字段中含有update的字段,此外由于主从数据库的延迟问题,我们需要一个锁定到master数据库的机制,所以添加了一个函数用于锁定主数据库。
首先,修改settings.php,添加default和readonly数据库的设置。
2 3 | $db_url['default'] = 'mysql://username:password@localhost/databasename'; $db_url['readonly'] = 'mysql://username:password@localhost/databasename'; |
其次,修改和添加如下代码在/includes/database.mysql-common.inc 中,
注意:
1. db_query是修改drupal核心。
2. db_lock_master是保持db一直锁定在master数据库上。(不同步的情况下使用,有时我们不能保证主从完全同步,就需要一直在master上操作,比如Drupal的核心函数user_save/node_save,在保存之后立即load一个对象,这种情况主从没有同步导致莫名其妙的数据bug,笔者以前在项目中经常遇到,大家多注意)。
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | function db_query($query) { $args = func_get_args(); array_shift($args); $query = db_prefix_tables($query); if (isset($args[0]) and is_array($args[0])) { // 'All arguments in one array' syntax $args = $args[0]; } _db_query_callback($args, TRUE); $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query); /* * Integrating multiple read/write databases */ if(!db_lock_master() && strpos(strtolower($query), "select") === 0 && strpos(strtolower($query), "last_insert_id") === FALSE){ $commits = array('alter', 'insert', 'update', 'delete', 'flush', 'lock','create'); $is_commit = false; foreach($commits as $type) { if((strpos(strtolower($query), "$type "))){//[insert|update|create] xxxx, need a space, otherwise, some field which is like 'user_updated' will be filter as commits $is_commit = true; } } if($is_commit){ db_set_active('default'); //drupal_set_message('default'); } else{ db_set_active('readonly'); //drupal_set_message('readonly'); } } else { db_set_active('default'); } /* * End read/write router */ return _db_query($query); } function db_lock_master($lock = null) { static $lock_master = false; if (is_null($lock)) { return $lock_master; } else { $lock_master = $lock; return $lock_master; } } |
最后,该代码只能支持一个slave数据库,如果我们有多个slave db,那么有两个办法。
1. 修改上面到php代码,在应用slave db的代码中,再用一个函数分配slave数据库。
2. 用haproxy做一个mysql db代理。参考这篇文章 http://www.oschina.net/question/17_4131
参考文章
Using multiple slave MySQL databases as ‘read only’ DBs
How does Drupal.org split MySQL read/write queries to a master/slave
声明:
本站所有文章欢迎转载,所有文章未说明,均属于原创,转载均请注明出处。
本文有效链接:
http://www.drupal001.com/2011/09/drupal-mysql-master-slave/
版权所有:
Drupal与高性能网站架构
http://www.drupal001.com
评论:7
发表评论