Moodle ist eine sehr beliebte Plattform zur Durchführung von Online-Kursen. Mit der Situation, die wir im Jahr 2020 sehen, bildet Moodle zusammen mit Kommunikatoren wie Zoom das Rückgrat der Dienste, die Online-Lernen und Bildung zu Hause ermöglichen. Die Nachfrage nach Moodle-Plattformen ist im Vergleich zu den Vorjahren deutlich gestiegen. Neue Plattformen wurden gebaut, zusätzliche Last wurde auf die Plattformen gelegt, die historisch nur als Hilfswerkzeug fungierten und nun dazu bestimmt sind, die gesamten Bildungsbemühungen voranzutreiben. Wie skaliert man das Moodle? Wir haben einen Blog zu diesem Thema. Wie skaliere ich das Datenbank-Backend für Moodle? Nun, das ist eine andere Geschichte. Werfen wir einen Blick darauf, da das Hochskalieren von Datenbanken nicht die einfachste Sache ist, besonders wenn Moodle seine eigene kleine Wendung hinzufügt.
Als Einstiegspunkt verwenden wir die in einem unserer früheren Posts beschriebene Architektur. MariaDB-Cluster mit ProxySQL und Keepalived an der Spitze.
Wie Sie sehen können, haben wir einen MariaDB-Cluster mit drei Knoten und ProxySQL trennt sichere Lesevorgänge basierend auf dem Benutzer vom Rest des Datenverkehrs.
<?php // Moodle configuration file
unset($CFG);
global $CFG;
$CFG = new stdClass();
$CFG->dbtype = 'mysqli';
$CFG->dblibrary = 'native';
$CFG->dbhost = '192.168.1.222';
$CFG->dbname = 'moodle';
$CFG->dbuser = 'moodle';
$CFG->dbpass = 'pass';
$CFG->prefix = 'mdl_';
$CFG->dboptions = array (
'dbpersist' => 0,
'dbport' => 6033,
'dbsocket' => '',
'dbcollation' => 'utf8mb4_general_ci',
'readonly' => [
'instance' => [
'dbhost' => '192.168.1.222',
'dbport' => 6033,
'dbuser' => 'moodle_safereads',
'dbpass' => 'pass'
]
]
);
$CFG->wwwroot = 'http://192.168.1.200/moodle';
$CFG->dataroot = '/var/www/moodledata';
$CFG->admin = 'admin';
$CFG->directorypermissions = 0777;
require_once(__DIR__ . '/lib/setup.php');
// There is no php closing tag in this file,
// it is intentional because it prevents trailing whitespace problems!
Benutzer, wie oben gezeigt, wird in der Moodle-Konfigurationsdatei definiert. Dadurch können wir Schreibvorgänge und alle SELECT-Anweisungen, die Datenkonsistenz erfordern, automatisch und sicher an den Writer-Knoten senden, während wir dennoch einige der SELECTs an die verbleibenden Knoten im MariaDB-Cluster senden.
Nehmen wir an, dass uns dieses spezielle Setup nicht ausreicht. Welche Möglichkeiten haben wir? Wir haben zwei Hauptelemente im Setup – MariaDB Cluster und ProxySQL. Wir werden Probleme auf beiden Seiten berücksichtigen:
- Was kann getan werden, wenn die ProxySQL-Instanz den Datenverkehr nicht bewältigen kann?
- Was kann getan werden, wenn MariaDB Cluster den Datenverkehr nicht bewältigen kann?
Beginnen wir mit dem ersten Szenario.
ProxySQL-Instanz ist überladen
In der aktuellen Umgebung kann nur eine ProxySQL-Instanz den Datenverkehr verarbeiten - diejenige, auf die Virtual IP zeigt. Dies lässt uns mit einer ProxySQL-Instanz zurück, die als Standby fungiert – betriebsbereit, aber nicht für irgendetwas verwendet wird. Wenn die aktive ProxySQL-Instanz der CPU-Sättigung nahe kommt, gibt es ein paar Dinge, die Sie vielleicht tun sollten. Erstens können Sie natürlich vertikal skalieren – das Erhöhen der Größe einer ProxySQL-Instanz ist möglicherweise der einfachste Weg, um höheren Datenverkehr bewältigen zu können. Bitte beachten Sie, dass ProxySQL standardmäßig für die Verwendung von 4 Threads konfiguriert ist.
Wenn Sie mehr CPU-Kerne nutzen möchten, ist dies die Einstellung müssen Sie ebenfalls ändern.
Alternativ können Sie versuchen, horizontal zu skalieren. Anstatt zwei ProxySQL-Instanzen mit VIP zu verwenden, können Sie ProxySQL mit Moodle-Hosts kombinieren. Dann möchten Sie Moodle neu konfigurieren, um eine Verbindung zu ProxySQL auf dem lokalen Host herzustellen, idealerweise über den Unix-Socket - dies ist die effizienteste Art, eine Verbindung zu ProxySQL herzustellen. Es gibt nicht viel von einer Konfiguration, die wir mit ProxySQL verwenden, daher sollte die Verwendung mehrerer Instanzen von ProxySQL nicht zu viel Overhead hinzufügen. Wenn Sie möchten, können Sie jederzeit einen ProxySQL-Cluster einrichten, der Ihnen dabei hilft, die ProxySQL-Instanzen bezüglich der Konfiguration synchron zu halten.
MariaDB-Cluster ist überlastet
Jetzt sprechen wir über ein ernsteres Problem. Natürlich hilft es wie üblich, die Größe der Instanzen zu erhöhen. Andererseits ist die horizontale Skalierung aufgrund der „Safe Reads“-Beschränkung etwas eingeschränkt. Sicher, Sie können dem Cluster weitere Knoten hinzufügen, aber Sie können sie nur für die sicheren Lesevorgänge verwenden. Inwieweit Sie damit skalieren können, hängt von der Arbeitslast ab. Für reinen Read-Only-Workload (Browsing durch die Inhalte, Foren etc.) sieht es ganz nett aus:
MySQL [(none)]> SELECT hostgroup, srv_host, srv_port, status, queries FROM stats_mysql_connection_pool WHERE hostgroup IN (20, 10) AND status='ONLINE';
+-----------+---------------+----------+--------+---------+
| hostgroup | srv_host | srv_port | status | Queries |
+-----------+---------------+----------+--------+---------+
| 20 | 192.168.1.204 | 3306 | ONLINE | 5683 |
| 20 | 192.168.1.205 | 3306 | ONLINE | 5543 |
| 10 | 192.168.1.206 | 3306 | ONLINE | 553 |
+-----------+---------------+----------+--------+---------+
3 rows in set (0.002 sec)
Das ist ziemlich genau ein Verhältnis von 1:20 – für eine Abfrage, die den Schreiber trifft, haben wir 20 „sichere Lesevorgänge“, die auf die verbleibenden Knoten verteilt werden können. Wenn wir andererseits beginnen, die Daten zu ändern, ändert sich das Verhältnis schnell.
MySQL [(none)]> SELECT hostgroup, srv_host, srv_port, status, queries FROM stats_mysql_connection_pool WHERE hostgroup IN (20, 10) AND status='ONLINE';
+-----------+---------------+----------+--------+---------+
| hostgroup | srv_host | srv_port | status | Queries |
+-----------+---------------+----------+--------+---------+
| 20 | 192.168.1.204 | 3306 | ONLINE | 3117 |
| 20 | 192.168.1.205 | 3306 | ONLINE | 3010 |
| 10 | 192.168.1.206 | 3306 | ONLINE | 6807 |
+-----------+---------------+----------+--------+---------+
3 rows in set (0.003 sec)
Dies ist ein Ergebnis nach der Vergabe mehrerer Noten, der Erstellung von Forenthemen und dem Hinzufügen einiger Kursinhalte. Wie Sie sehen können, ist der Schreiber bei einem solchen Verhältnis von sicheren/unsicheren Abfragen früher gesättigt als die Leser, daher ist eine Skalierung durch Hinzufügen weiterer Knoten nicht geeignet.
Was kann man dagegen tun? Es gibt eine Einstellung namens „Latenz“. Gemäß der Konfigurationsdatei bestimmt es, wann es sicher ist, die Tabelle nach dem Schreiben zu lesen. Beim Schreiben wird die Tabelle als geändert markiert und für die „Latenzzeit“ werden alle SELECTs an den Writer-Knoten gesendet. Sobald die Zeit, die länger als die „Latenzzeit“ ist, verstrichen ist, können SELECTs von dieser Tabelle erneut an Leseknoten gesendet werden. Bitte beachten Sie, dass bei MariaDB Cluster die Zeit, die für die Anwendung des Writesets auf alle Knoten benötigt wird, in der Regel sehr gering ist und in Millisekunden gezählt wird. Dies würde uns erlauben, die Latenz in der Moodle-Konfigurationsdatei ziemlich niedrig einzustellen, zum Beispiel sollte der Wert wie 0,1 s (100 Millisekunden) ganz ok sein. Sollten Sie auf Probleme stoßen, können Sie diesen Wert natürlich jederzeit noch weiter erhöhen.
Eine weitere Testoption wäre, sich ausschließlich auf MariaDB Cluster zu verlassen, um festzustellen, wann der Lesevorgang sicher ist und wann nicht. Es gibt eine wsrep_sync_wait-Variable, die konfiguriert werden kann, um Kausalitätsprüfungen für mehrere Zugriffsmuster (Lesen, Aktualisieren, Einfügen, Löschen, Ersetzen und SHOW-Befehle) zu erzwingen. Für unseren Zweck würde es ausreichen, sicherzustellen, dass Lesevorgänge mit der erzwungenen Kausalität ausgeführt werden, also setzen wir diese Variable auf „1“.
Wir werden diese Änderung auf allen MariaDB-Clusterknoten vornehmen. Außerdem müssen wir ProxySQL für die Lese-/Schreibaufteilung basierend auf den Abfrageregeln und nicht nur den Benutzern neu konfigurieren, wie wir es zuvor getan hatten. Wir werden auch den Benutzer „moodle_safereads“ entfernen, da er in diesem Setup nicht mehr benötigt wird.
Wir richten drei Abfrageregeln ein, die den Datenverkehr basierend auf der Abfrage verteilen. SELECT … FOR UPDATE wird an den Writer-Knoten gesendet, alle SELECT-Abfragen werden an Reader gesendet und alles andere (INSERT, DELETE, REPLACE, UPDATE, BEGIN, COMMIT usw.) wird ebenfalls an den Writer-Knoten gesendet.
Dadurch können wir sicherstellen, dass alle Lesevorgänge über die Reader-Knoten verteilt werden können, wodurch eine horizontale Skalierung durch Hinzufügen weiterer Knoten zum MariaDB-Cluster ermöglicht wird.
Wir hoffen, dass Sie mit diesen paar Tipps Ihr Moodle-Datenbank-Backend viel einfacher und in größerem Umfang skalieren können