Як отримати ядро ​​для використання конфігурації головного / підлеглого MySQL?


21

Я читав це запитання, що реплікація майстра / підлеглого не працює, і його відповідь:

Використання рабських баз даних ледве реалізовано в ядрі Drupal. Якщо ви розробляєте власні модулі, то для викликів db_query потрібно вказати, що вони хочуть використовувати підлеглий базу даних, використовуючи масив $ options. Див. DatabaseConnection :: defaultOptions, як встановити цей масив.

Чи є спосіб, не вбиваючи кошенят, що зламали серцевину, отримати db_query()та db_select()зробити більше рабів SELECT запитів?

За замовчуванням ці функції будуть запитувати ведучого, якщо спеціально не вказано запитувати ведений (див. Їх API). Ви повинні писати db_query($query, $args, array('target' => 'slave')), щоб запитувати ведений і ядро ​​(і всі модулі) не написані для цього.

Тільки пошук (див. Рабовласницьку частину) та агрегатор, схоже, підтримують це.

Редагувати: 25 жовтня.
Я побачив, що прес-потік 7 не працює, але я не впевнений, чи він зараз дуже допомагає.
Я не знайшов щось відповідне, тож давайте спробуємо трохи нагородити, щоб допомогти цьому отримати відповідь.

Редагувати: 31 жовтня
Мене в основному турбують коментарі Крела щодо цієї теми: Що робити з рабами? .
В основному, чи є проблеми, якщо я надсилаю SELECTзапити до підлеглого, що відбувається із затримками реплікації та тим, що я, можливо, захочу зробити node_load()щойно після збереження нового вузла.

Відповіді:


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 у файл інформації про ваш модуль.


Привіт Еріку, дякую за твою відповідь, що мене найбільше хвилює, це нитка: Що робити з рабами? і коментар Крела щодо раба . Тож чи безпечне ви рішення в будь-яких випадках? Ви обмежуєте деякі SELECTзапити? Як ви маєте справу з затримками реплікації та тим, що завантаження вузла відразу після його збереження може спричинити проблеми?
tostinni

Це змінює базу даних на підлеглий лише для вибору запитів. Це трапляється лише тоді, коли запит був написаний SelectQuery не db_query, тому не потрібно турбуватися і вставляти або оновлювати націлені на підлеглого. Ми працюємо з цим у 3 величезних виробничих середовищах без проблем. Я не дуже хвилювався з приводу реплікації mysql як її майже миттєвої (в моєму випадку), але я можу побачити, як це може бути невеликою проблемою в певних умовах.
ericduran

Дякую за ваші відповіді, це чудове рішення, я побачу, чи це можливо в нашому середовищі.
тостінні

Еріку, чи є цей код десь як модуль "contrib" або "пісочниця"?
paul-m

@ paul-m: див. drupal.org/project/autoslave .
smokris

5

Модуль AutoSlave перенаправляє SELECTзапити до баз даних лише реплікантів, і він враховує відставання реплікації.

Згідно з документами модуля, він використовує реплікант, доступний лише для читання, коли виконуються всі наступні умови:

  1. Запит - це обраний запит
  2. Таблиці в запиті вибору не записувались під час запиту та у межах передбачуваного відставання реплікації
  3. Угода не була розпочата
  4. Таблиці в запиті вибору не вказані в опції 'таблиці' в налаштуваннях драйвера
  5. Блокування не було запущено (підтримується основний db-lock та memcache-lock)

1

з того, що я чув на недавньому друкарському BADcamp Pressflow - це шлях, якщо ви хочете конфігурації master / slave. Ви будете обмежені Mysql як БД. Крім того, огляньте " групу з високою ефективністю " на виконання


1
В даний час Pressflow 7 = D7, немає нічого (поки що), що Pressflow робити це D7 не робити :(
tostinni

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 і спрямовує їх на підлеглого, що, безсумнівно, спричинить проблеми, якщо у вас є відставання в реплікації. Прочитайте це речення ще раз.
  2. Під час оновлення ядра Drupal можливо, цей файл буде видалений.
  3. Якщо ядро ​​Drupal коли-небудь почне надсилати свою власну includes/database/mysql/select.inc, ваш файл буде перезаписаний під час оновлення, і вам доведеться почати підтримувати власну виправлену версію select.inc, що постачається з ядром Drupal.

Якщо у вас немає жодного підлеглого сервера, вказаного в settings.php, наведений вище код не спричинить проблем. Він все одно витончено перейде до використання головного сервера.


Так, це відображається, навіть якщо з'єднання можна встановити на "підлеглий", якщо сам запит не має target => 'slave'набору параметрів, він все одно працюватиме за замовчуванням. Це не просто простіше встановити ціль з'єднання на query_alterрівні.
Девід Томас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.