Как заставить ядро ​​использовать конфигурацию master / slave MySQL?

21

Я прочитал этот вопрос MySQL master / slave replication, и его ответ:

Использование ведомых баз данных практически не реализовано в ядре Drupal. Если вы разрабатываете свои собственные модули, то вызовы db_query должны указать, что они хотят использовать подчиненную базу данных с помощью массива $ options. Посмотрите DatabaseConnection :: defaultOptions для того, как установить этот массив.

Есть ли способ без убийства котят взломать ядро, чтобы получить db_query()и db_select()сделать больше подчиненных запросов SELECT?

По умолчанию эти функции будут запрашивать мастер, если специально не указано, что нужно запросить подчиненное устройство (см. Их API). Вы должны написать db_query($query, $args, array('target' => 'slave')), чтобы запросить подчиненное устройство, а ядро ​​(и все модули) не написаны для достижения этого.

Только поиск (см. Ведомая часть) и агрегатор, кажется, используют это.

Редактирование: 25 октября.
Я видел, что pressflow 7 вышел, но я не уверен, что это сильно помогает сейчас.
Я не нашел что-то подходящее, поэтому давайте попробуем немного щедрости, чтобы помочь получить ответ.

Изменить: 31 октября
Я в основном беспокоюсь о комментариях Крелла по этой теме: Что делать с рабами? ,
Главным образом, есть ли проблемы, если я отправляю SELECTзапросы подчиненному, что происходит с задержками в репликации и тем фактом, что я могу захотеть сделать это node_load()сразу после сохранения нового узла.

tostinni
источник

Ответы:

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, и добавить файлы [] = SlaveTarget.inc в файл информации о вашем модуле.

ericduran
источник
Привет, Эрик, спасибо за твой ответ. Меня больше всего волнует эта тема: что делать с рабами? и комментарий Крелла относительно раба . Так вы в любом случае безопасны? Вы ограничиваете некоторые SELECTзапросы? Как вы справляетесь с задержками в репликации и тем фактом, что загрузка узла сразу после сохранения может вызвать проблемы?
Тостинни
Это изменяет базу данных на ведомую только по запросам Select. Это происходит только тогда, когда запрос был написан с помощью SelectQuery, а не db_query, поэтому не нужно беспокоиться о вставке или обновлении, ориентированном на подчиненное устройство. Мы выполняем это на 3 огромных производственных средах без каких-либо проблем. Я не очень беспокоился о репликации mysql, поскольку она почти мгновенная (в моем случае), но я вижу, как это может быть небольшой проблемой в определенных средах.
Эрикдуран
Спасибо за ваши ответы, это отличное решение, я посмотрю, будет ли оно жизнеспособным в нашей среде.
Тостинни
Эрик, этот код где-то в виде модуля contrib или песочницы?
paul-m
@ paul-m: см. drupal.org/project/autoslave .
Smokris
5

Модуль AutoSlave перенаправляет SELECTзапросы в реплицируемые базы данных, доступные только для чтения, и учитывает задержку репликации.

Согласно документам модуля, он использует репликант только для чтения, когда выполняются все следующие условия:

  1. Запрос является запросом выбора
  2. Таблицы в запросе выбора не были записаны во время запроса и в пределах предполагаемой задержки репликации
  3. Транзакция не была начата
  4. Таблицы в запросе выбора не указаны в параметре «таблицы» в настройках драйвера.
  5. Блокировка не была запущена (поддерживается блокировка ядра db и memcache-lock)
smokris
источник
1

Из того, что я слышал в недавнем Drupal BADcamp Pressflow, есть путь, если вам нужны конфигурации master / slave. Вы будете ограничены Mysql в качестве базы данных. Также ознакомьтесь с « группой высокой производительности » на сайте

Уве
источник
1
В настоящее время Pressflow 7 = D7, пока нет ничего, что Pressflow делает, а D7 не делает :(
tostinni
1

Несмотря на всю удивительную работу, проделанную на уровне абстракции базы данных в Drupal 7, это все равно удивительно сложно сделать с ядром Drupal из коробки. Как уже упоминали другие, AutoSlave - это вариант, хотя я и не пытался из-за моего упрямого отказа полагать, что это должно быть так трудно сделать.

Более простое решение, которое я нашел, заключается в следующем. Чтобы направить все SELECT файлы на подчиненный сервер, вы создаете файл с именем 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, ваш файл будет перезаписан во время обновления, и вам придется начать поддерживать свою собственную исправленную версию select.inc, которая поставляется с ядром Drupal.

Если в файле settings.php не указаны подчиненные серверы, приведенный выше код не вызовет проблем. Это все еще будет постепенно снижаться до использования главного сервера.

q0rban
источник
Да, он появляется, даже если соединение может быть установлено как «ведомое», если в самом запросе не target => 'slave'задана опция, он все равно будет работать на соединении по умолчанию. Это боль, легче установить цель соединения на query_alterуровне.
Дэвид Томас