如何获得核心以利用MySQL主/从配置?


21

我读了这个问题,MySQL主/从复制不起作用,其答案是:

在Drupal核心中几乎没有实现使用从属数据库。如果要开发自己的模块,则对db_query的调用需要使用$ options数组指定它们要使用从数据库。有关如何设置此数组的信息,请参见DatabaseConnection :: defaultOptions。

有没有一种方法杀死小猫黑客攻击核心,以获得db_query()db_select()让更多的奴隶SELECT查询?

默认情况下,这些功能将查询主服务器,除非明确要求查询从服务器(请参阅其API)。您必须编写db_query($query, $args, array('target' => 'slave'))命令才能查询从站,而内核(和所有模块)并未编写来实现此目的。

只有搜索(请参阅从属部分)和聚合器似乎可以利用此功能。

编辑: 10月25日,
我看到pressflow 7退出了,但是我不确定现在是否有很大帮助。
我还没有找到相关的内容,因此让我们尝试一些赏金以帮助获得答案。

编辑: 10月31日,
我主要担心Crell对此主题的评论与奴隶怎么办?
主要是,如果我将SELECT查询发送到从属服务器,会遇到麻烦,复制延迟会发生什么情况,以及我可能想node_load()在保存新节点后立即执行操作。

Answers:


17

这是我目前实现的方式。

首先,您需要像这样设置一个SelectQueryExtender类:

class SlaveTarget extends SelectQueryExtender {
  public function __construct(SelectQueryInterface $query, DatabaseConnection $connection) {
    if ($connection->getTarget() != 'slave') {
      $connection = Database::getConnection('slave', $connection->getKey());
    }
    parent::__construct($query, $connection);
    $this->addTag('SlaveTarget');
  }
}

一旦有了这些,您要做的就是获取所有其他查询以扩展扩展程序。:)如果有道理。这是代码段。

/**
 * Implements hook_query_alter().
 */
function example_query_alter(QueryAlterableInterface $query) { 
  if (is_a($query, 'SelectQuery') && !$query->hasTag('SlaveTarget')) {
    $query->extend('SlaveTarget');
  }
}

现在,您所有的SelectQuery都击中了奴隶;-)这是我能够完成此任务的唯一方法。无论如何,它都很棒。

另外,如果在自定义模块上具有此功能,则可以将SlaveTarget设置为位于文件SlaveTarget.inc上,然后将files [] = SlaveTarget.inc添加到模块信息文件中。


嗨,埃里克(Eric),谢谢您的回答,这个线程主要让我担心的是:与奴隶怎么办?以及Crell关于slave的评论。那么,在任何情况下您的解决方案安全吗?您是否限制某些SELECT查询?您如何处理复制中的延迟以及在保存节点后立即加载节点会造成麻烦的事实?
tostinni 2011年

这仅在选择查询时将数据库更改为从属。仅当查询是使用SelectQuery而不是db_query编写的时,才会发生这种情况,因此无需担心,插入或更新针对从属服务器的情况。我们正在3个巨大的生产环境上运行此程序,而没有任何问题。我并不太担心mysql复制的即时性(就我而言),但我可以看到在某些环境下这可能是一个小问题。
ericduran 2011年

感谢您的回答,这是一个很好的解决方案,我将看看这在我们的环境中是否可行。
tostinni

Eric,此代码是否以contrib或sandbox模块的形式存在?
paul-m

@ paul-m:请参阅drupal.org/project/autoslave
smokris

5

AutoSlave模块重定向SELECT查询到只读复制人数据库,以及它考虑复制滞后。

根据模块文档,仅当满足以下所有条件时,它才使用只读副本:

  1. 该查询是一个选择查询
  2. 在查询期间和假定的复制滞后内未将选择查询中的表写入
  3. 交易尚未开始
  4. 选择查询中的表未在驱动程序设置的“表”选项中指定
  5. 锁尚未启动(支持核心数据库锁和内存缓存锁)

1

从最近在Drupal BADcamp Pressflow上听到的信息来看,如果您要进行主/从配置,则该走的路。您将只能以Mysql作为数据库。另外,签出“ 高性能小组


1
目前,Pressflow 7 = D7,没有(但)Pressflow可以做到D7不做的事情:(
tostinni 2011年

1

尽管在Drupal 7的数据库抽象层上完成了所有令人惊奇的工作,但要使用现成的Drupal核心仍然很难做到这一点。正如其他人提到的那样,AutoSlave是一种选择,尽管由于我顽固地拒绝相信这样做很难,所以我没有尝试过。

我发现一个更简单的解决方案如下。要将所有 SELECT s 路由到从属服务器,请select.inc在核心includes/database/mysql目录中创建一个标题为以下内容的文件:

<?php

/**
 * @file
 * Select builder for MySQL database engine, routing all SELECTs to the slave.
 */

/**
 * @addtogroup database
 * @{
 */

class SelectQuery_mysql extends SelectQuery {
  public function __construct($table, $alias = NULL, DatabaseConnection $connection, $options = array()) {
    $key = $connection->getKey();
    $connection = Database::getConnection('slave', $key);
    $options['target'] = 'slave';
    parent::__construct($table, $alias, $connection, $options);
  }
}

/**
 * @} End of "addtogroup database".
 */

此方法存在一些风险:

  1. 此方法将劫持所有 SELECT s并将它们定向到从属,如果复制存在任何滞后,无疑会引起问题。再次阅读该句子。
  2. 升级Drupal核心时,可能会删除该文件。
  3. 如果Drupal核心曾经开始使用它自己的版本includes/database/mysql/select.inc,则在升级过程中您的文件将被覆盖,并且您将必须开始维护您自己的Drupal核心附带的补丁版本。

如果您在settings.php中没有指定任何从属服务器,则上面的代码不会引起问题。它仍将正常降级以使用服务器。


是的,即使可以将连接设置为“从属”,它也会出现,如果查询本身未target => 'slave'设置选项,它仍将在默认连接上运行。痛苦的是,在query_alter级别上更轻松地设置连接目标并不容易。
大卫·托马斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.