Moodle är en mycket populär plattform för att köra onlinekurser. Med den situation vi ser 2020 utgör Moodle, tillsammans med kommunikatörer som Zoom, ryggraden i de tjänster som möjliggör onlineinlärning och utbildning hemma. Efterfrågan på Moodle-plattformar ökade avsevärt jämfört med tidigare år. Nya plattformar har byggts, ytterligare belastning har lagts på plattformarna som historiskt sett bara fungerat som ett hjälpmedel och nu är de tänkta att driva hela utbildningssatsningen. Hur skalar man ut Moodle? Vi har en blogg om detta ämne. Hur skalar man databasens backend för Moodle? Tja, det är en annan historia. Låt oss ta en titt på det eftersom att skala ut databaser inte är det lättaste att göra, särskilt om Moodle lägger till sin egen lilla twist.
Som ingångspunkt kommer vi att använda arkitekturen som beskrivs i ett av våra tidigare inlägg. MariaDB Cluster med ProxySQL och Keepalived ovanpå saker.
Som du kan se har vi ett MariaDB-kluster med tre noder med ProxySQL som delar säkra läsningar från resten av trafiken baserat på användaren.
<?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!
Användaren, som visas ovan, definieras i Moodles konfigurationsfil. Detta tillåter oss att automatiskt och säkert skicka skrivningar och alla SELECT-satser som kräver datakonsistens till writernoden samtidigt som vi skickar några av SELECT:erna till de återstående noderna i MariaDB-klustret.
Låt oss anta att den här inställningen inte räcker för oss. Vilka alternativ har vi? Vi har två huvudelement i installationen - MariaDB Cluster och ProxySQL. Vi kommer att överväga problem på båda sidor:
- Vad kan göras om ProxySQL-instansen inte kan hantera trafik?
- Vad kan göras om MariaDB Cluster inte kan hantera trafik?
Låt oss börja med det första scenariot.
ProxySQL-instansen är överbelastad
I den aktuella miljön kan endast en ProxySQL-instans hantera trafiken - den som Virtual IP pekar på. Detta lämnar oss med en ProxySQL-instans som fungerar som en standby - igång men inte används till någonting. Om den aktiva ProxySQL-instansen närmar sig CPU-mättnad finns det ett par saker du kanske vill göra. För det första kan du självklart skala vertikalt - att öka storleken på en ProxySQL-instans kan vara det enklaste sättet att låta den hantera högre trafik. Kom ihåg att ProxySQL, som standard, är konfigurerad för att använda fyra trådar.
Om du vill kunna använda fler CPU-kärnor är det här inställning måste du också ändra.
Alternativt kan du försöka skala ut horisontellt. Istället för att använda två ProxySQL-instanser med VIP kan du samlokalisera ProxySQL med Moodle-värdar. Sedan vill du konfigurera om Moodle för att ansluta till ProxySQL på den lokala värden, helst genom Unix-uttaget - det är det mest effektiva sättet att ansluta till ProxySQL. Det finns inte mycket av en konfiguration som vi använder med ProxySQL, därför bör användning av flera instanser av ProxySQL inte lägga till för mycket av overheaden. Om du vill kan du alltid ställa in ProxySQL Cluster för att hjälpa dig att hålla ProxySQL-instanserna synkroniserade angående konfigurationen.
MariaDB-klustret är överbelastat
Nu pratar vi om ett allvarligare problem. Att öka storleken på instanserna kommer naturligtvis att hjälpa, som vanligt. Å andra sidan är horisontell utskalning något begränsad på grund av begränsningen för "safe reads". Visst, du kan lägga till fler noder till klustret men du kan bara använda dem för säkra läsningar. I vilken utsträckning detta låter dig skala ut beror på arbetsbelastningen. För ren skrivskyddad arbetsbelastning (bläddra igenom innehållet, forum etc) ser det ganska trevligt ut:
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)
Detta är i stort sett ett förhållande på 1:20 - för en fråga som träffar författaren har vi 20 "säkra läsningar" som kan spridas över de återstående noderna. Å andra sidan, när vi börjar modifiera data ändras förhållandet snabbt.
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)
Detta är ett resultat efter att ha utfärdat flera betyg, skapat forumämnen och lagt till visst kursinnehåll. Som du kan se, med en sådan säker/osäkra frågeförhållande kommer skribenten att mättas tidigare än läsarna, därför är det inte lämpligt att skala ut genom att lägga till fler noder.
Vad kan man göra åt det? Det finns en inställning som heter "latens". Enligt konfigurationsfilen avgör den när det är säkert att läsa tabellen efter skrivningen. När skrivning sker, markeras tabellen som modifierad och under "latens"-tiden kommer alla SELECT att skickas till skrivarnoden. När tiden som är längre än "latens" passerat, kan SELECT från den tabellen åter skickas till läsnoder. Kom ihåg att med MariaDB Cluster är tiden som krävs för att skrivuppsättningen ska tillämpas över alla noder vanligtvis mycket låg, räknat i millisekunder. Detta skulle tillåta oss att ställa in latensen ganska lågt i Moodle-konfigurationsfilen, till exempel borde värdet som 0.1s (100 millisekunder) vara helt ok. Om du skulle stöta på några problem kan du naturligtvis alltid öka detta värde ytterligare.
Ett annat alternativ att testa skulle vara att förlita sig enbart på MariaDB Cluster för att avgöra när läsningen är säker och när den inte är det. Det finns en wsrep_sync_wait-variabel som kan konfigureras för att framtvinga kausalitetskontroller på flera åtkomstmönster (läser, uppdaterar, infogar, tar bort, ersätter och VISA-kommandon). För vårt syfte skulle det räcka att se till att läsningar utförs med kausaliteten påtvingad, så vi kommer att sätta denna variabel till '1'.
Vi kommer att göra denna ändring på alla MariaDB Cluster-noder. Vi kommer också att behöva konfigurera om ProxySQL för läs/skrivdelning baserat på frågereglerna, inte bara användarna, som vi hade tidigare. Vi kommer också att ta bort "moodle_safereads"-användaren eftersom den inte längre behövs i den här inställningen.
Vi ställer in tre frågeregler som distribuerar trafiken baserat på frågan. SELECT … FOR UPDATE skickas till skribentnoden, alla SELECT-frågor skickas till läsare och allt annat (INSERT, DELETE, REPLACE, UPDATE, BEGIN, COMMIT och så vidare) skickas också till writer-noden.
Detta tillåter oss att säkerställa att alla läsningar kan spridas över läsarnoderna, vilket möjliggör horisontell skala ut genom att lägga till fler noder till MariaDB-klustret.
Vi hoppas att du med dessa par tips kommer att kunna skala ut din Moodle-databas backend mycket enklare och i större utsträckning