Wie kann der Core eine MySQL-Master / Slave-Konfiguration nutzen?

21

Ich habe diese Frage gelesen MySQL Master / Slave-Replikation funktioniert nicht und seine Antwort:

Die Verwendung von Slave-Datenbanken ist im Drupal-Kern kaum implementiert. Wenn Sie Ihre eigenen Module entwickeln, müssen Aufrufe von db_query angeben, dass sie die Slave-Datenbank mit dem Array $ options verwenden möchten. Informationen zum Festlegen dieses Arrays finden Sie unter DatabaseConnection :: defaultOptions.

Gibt es eine Möglichkeit , Kätzchen zu töten, die den Kern hacken , um mehr Slave-SELECT-Abfragen zu erhalten db_query()und db_select()zu machen?

Standardmäßig fragen diese Funktionen den Master ab, es sei denn, sie werden ausdrücklich aufgefordert, den Slave abzufragen (siehe deren API). Sie müssen schreiben db_query($query, $args, array('target' => 'slave')), um den Slave abzufragen, und der Kern (und alle Module) werden nicht geschrieben, um dies zu erreichen.

Nur die Suche (siehe Slave-Teil) und der Aggregator scheinen dies zu nutzen.

Edit: 25. Oktober
Ich habe gesehen, dass Pressflow 7 nicht verfügbar ist, aber ich bin mir nicht sicher, ob es im Moment viel hilft.
Ich habe nichts Relevantes gefunden, also versuchen wir es mit ein wenig Kopfgeld, um eine Antwort zu bekommen.

Edit: 31. Oktober
Ich mache mir hauptsächlich Sorgen um Crells Kommentare zu diesem Thema: Was tun mit Sklaven? .
Hauptsächlich gibt es Probleme, wenn ich SELECTAnfragen an den Slave sende , was mit Verzögerungen bei der Replikation und der Tatsache passiert, dass ich node_load()einen neuen Knoten kurz nach dem Speichern machen möchte .

tostinni
quelle

Antworten:

17

So setze ich das aktuell um.

Zuerst müssen Sie eine SelectQueryExtender-Klasse wie folgt einrichten:

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');
  }
}

Sobald Sie das haben, müssen Sie nur noch alle anderen Abfragen durchführen, um den Extender zu erweitern. :) wenn das Sinn macht. Hier ist der Ausschnitt.

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

Und jetzt hat all deine SelectQuery den Sklaven getroffen ;-) Nur so konnte ich das erreichen. Sowieso funktioniert es großartig.

Wenn Sie dies auf einem benutzerdefinierten Modul haben, können Sie das SlaveTarget so einrichten, dass es sich in der Datei SlaveTarget.inc befindet, und Ihrer Modul-Infodatei die Datei [] = SlaveTarget.inc hinzufügen.

Ericduran
quelle
Hallo Eric, danke für deine Antwort, was mich hauptsächlich beunruhigt ist dieser Thread: Was tun mit Sklaven? und Crells Kommentar zum Sklaven . Ist Ihre Lösung also in jedem Fall sicher? Beschränken Sie einige SELECTFragen? Wie gehen Sie mit Verzögerungen bei der Replikation um und der Tatsache, dass das Laden eines Knotens unmittelbar nach dem Speichern Probleme verursachen kann?
tostinni
Dadurch wird die Datenbank nur bei Select-Abfragen in Slave geändert. Dies geschieht nur, wenn die Abfrage mit SelectQuery und nicht mit db_query geschrieben wurde. Sie müssen sich also keine Sorgen machen, dass das Einfügen oder Aktualisieren auf den Slave abzielt. Wir arbeiten problemlos in drei großen Produktionsumgebungen. Ich habe mir nicht viel Gedanken über die MySQL-Replikation gemacht, da sie (in meinem Fall) fast sofort ausgeführt wird, aber ich kann sehen, dass dies in bestimmten Umgebungen ein kleines Problem sein kann.
Ericduran
Vielen Dank für Ihre Antworten, es ist eine großartige Lösung. Ich werde sehen, ob dies für unsere Umwelt tragfähig ist.
tostinni
Eric, gibt es diesen Code irgendwo als Contrib- oder Sandbox-Modul?
Paul-M
@ paul-m: siehe drupal.org/project/autoslave .
Smokris
5

Das AutoSlave- Modul leitet SELECTAbfragen an schreibgeschützte replizierende Datenbanken um und berücksichtigt die Replikationsverzögerung.

Gemäß den Moduldokumenten wird der schreibgeschützte Replikant nur verwendet, wenn alle folgenden Bedingungen erfüllt sind:

  1. Die Abfrage ist eine Auswahlabfrage
  2. Die Tabellen in der Auswahlabfrage wurden während der Anforderung und innerhalb der angenommenen Replikationsverzögerung nicht beschrieben
  3. Eine Transaktion wurde nicht gestartet
  4. Die Tabellen in der Auswahlabfrage sind in den Treibereinstellungen nicht in der Option 'tables' angegeben
  5. Eine Sperre wurde nicht gestartet (Core-DB-Sperre und Memcache-Sperre werden unterstützt)
Smokris
quelle
1

Nach dem, was ich auf dem letzten Drupal BADcamp Pressflow gehört habe, ist dies der richtige Weg, wenn Sie Master / Slave-Konfigurationen wünschen. Sie sind auf MySQL als Datenbank beschränkt. Schauen Sie sich auch die " Hochleistungsgruppe " an

uwe
quelle
1
Momentan ist Pressflow 7 = D7, es gibt (noch) nichts, was Pressflow nicht tut :(
tostinni
1

Trotz all der erstaunlichen Arbeit, die auf der Datenbankabstraktionsschicht in Drupal 7 geleistet wurde, ist dies mit Drupal Core Out-of-the-Box immer noch erstaunlich schwierig. Wie andere bereits erwähnt haben, ist AutoSlave eine Option, obwohl ich es aufgrund meiner hartnäckigen Weigerung, zu glauben, dass es so schwierig sein sollte, nicht versucht habe, dies zu tun.

Eine einfachere Lösung, die ich gefunden habe, ist die folgende. Um alle SELECT s an den Slave-Server weiterzuleiten, erstellen Sie eine Datei select.incim Core- includes/database/mysqlVerzeichnis mit folgendem Inhalt:

<?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".
 */

Diese Methode birgt einige Risiken:

  1. Diese Methode hijackt alle SELECT s und leitet sie an den Slave weiter, was zweifellos zu Problemen führt, wenn Sie eine Verzögerung bei der Replikation haben. Lesen Sie diesen Satz noch einmal.
  2. Wenn Sie Drupal Core aktualisieren, wird diese Datei möglicherweise gelöscht.
  3. Wenn der Drupal-Kern jemals mit einem eigenen Kern ausgeliefert werden sollte includes/database/mysql/select.inc, würde Ihre Datei während des Upgrades überschrieben und Sie müssten damit beginnen, Ihre eigene gepatchte Version von select.inc zu pflegen, die mit dem Drupal-Kern ausgeliefert wird.

Wenn in settings.php keine Slave-Server angegeben sind, verursacht der obige Code kein Problem. Die Verwendung des Masterservers wird weiterhin ordnungsgemäß beeinträchtigt .

q0rban
quelle
Ja, obwohl die Verbindung auf "Slave" target => 'slave'eingestellt werden kann, wird sie auf der Standardverbindung ausgeführt , wenn für die Abfrage selbst keine Option festgelegt ist. Es ist ein Schmerz, es ist nicht einfacher, das Verbindungsziel auf der query_alterEbene leichter zu setzen .
David Thomas