Moodle е много популярна платформа за провеждане на онлайн курсове. Със ситуацията, която виждаме през 2020 г., Moodle, заедно с комуникатори като Zoom, формира гръбнака на услугите, които позволяват онлайн обучение и обучение вкъщи. Търсенето на платформи Moodle значително нарасна в сравнение с предишни години. Бяха изградени нови платформи, беше поставено допълнително натоварване на платформите, които исторически са действали само като помощен инструмент и сега те са предназначени да управляват цялото образователно усилие. Как да мащабирате Moodle? Имаме блог по тази тема. Как да мащабирам бекенда на базата данни за Moodle? Е, това е друга история. Нека да го разгледаме, тъй като мащабирането на бази данни не е най-лесното нещо, особено ако Moodle добавя свой собствен малък обрат.
Като входна точка ще използваме архитектурата, описана в една от по-ранните ни публикации. MariaDB Cluster с ProxySQL и Keepalived на всичкото отгоре.
Както можете да видите, имаме клъстер MariaDB с три възела с ProxySQL, който разделя безопасното четене от останалия трафик въз основа на потребителя.
<?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!
Потребителят, както е показано по-горе, е дефиниран в конфигурационния файл на Moodle. Това ни позволява автоматично и безопасно да изпращаме записи и всички оператори SELECT, които изискват последователност на данните към възела за запис, като същевременно изпращаме някои от SELECT към останалите възли в клъстера MariaDB.
Да приемем, че тази конкретна настройка не е достатъчна за нас. Какви са опциите, които имаме? Имаме два основни елемента в настройката - MariaDB Cluster и ProxySQL. Ще разгледаме проблеми и от двете страни:
- Какво може да се направи, ако ProxySQL екземплярът не може да се справи с трафика?
- Какво може да се направи, ако MariaDB Cluster не може да се справи с трафика?
Да започнем с първия сценарий.
Екземплярът на ProxySQL е претоварен
В текущата среда само един екземпляр на ProxySQL може да обработва трафика – този, към който сочи виртуалният IP. Това ни оставя с екземпляр на ProxySQL, който действа като режим на готовност - работещ, но не използван за нищо. Ако активният екземпляр на ProxySQL се доближава до насищането на процесора, има няколко неща, които може да искате да направите. Първо, очевидно, можете да мащабирате вертикално - увеличаването на размера на екземпляр на ProxySQL може да е най-лесният начин да го оставите да обработва по-висок трафик. Моля, имайте предвид, че ProxySQL по подразбиране е конфигуриран да използва 4 нишки.
Ако искате да можете да използвате повече ядра на процесора, това е настройка, която също трябва да промените.
Алтернативно можете да опитате да мащабирате хоризонтално. Вместо да използвате две копия на ProxySQL с VIP, можете да разпределите ProxySQL с хостове на Moodle. След това искате да преконфигурирате Moodle да се свързва с ProxySQL на локалния хост, в идеалния случай през Unix сокета - това е най-ефективният начин за свързване с ProxySQL. Няма много конфигурация, която използваме с ProxySQL, затова използването на множество екземпляри на ProxySQL не трябва да добавя твърде много от режийните разходи. Ако искате, винаги можете да настроите ProxySQL Cluster, за да ви помогне да поддържате екземплярите на ProxySQL в синхрон по отношение на конфигурацията.
Клъстерът MariaDB е претоварен
Сега говорим за по-сериозен проблем. Разбира се, увеличаването на размера на екземплярите ще помогне, както обикновено. От друга страна, хоризонталното мащабиране е донякъде ограничено поради ограничението за „безопасно четене“. Разбира се, можете да добавите още възли към клъстера, но можете да ги използвате само за безопасно четене. До каква степен това ви позволява да мащабирате, зависи от натоварването. За чисто работно натоварване само за четене (разглеждане на съдържанието, форуми и т.н.) изглежда доста хубаво:
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)
Това е почти съотношение 1:20 - за една заявка, която удря записващия, имаме 20 „безопасни четения“, които могат да бъдат разпределени в останалите възли. От друга страна, когато започнем да променяме данните, съотношението бързо се променя.
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)
Това е резултат след издаване на няколко оценки, създаване на теми във форума и добавяне на съдържание на курса. Както можете да видите, с такова съотношение безопасни/небезопасни заявки записващият ще бъде наситен по-рано от читателите, поради което мащабирането чрез добавяне на повече възли не е подходящо.
Какво може да се направи по въпроса? Има настройка, наречена „латентност“. Според конфигурационния файл, той определя кога е безопасно да се прочете таблицата след записа. Когато записът се случи, таблицата се маркира като променена и за времето на „латентност“ всички SELECT ще бъдат изпратени до възела за запис. След като изтече времето, по-дълго от „латентност“, SELECT от тази таблица може отново да се изпрати до възлите за четене. Моля, имайте предвид, че с MariaDB Cluster времето, необходимо за прилагане на набора за запис към всички възли обикновено е много малко, отчитано в милисекунди. Това би ни позволило да зададем доста ниска латентност в конфигурационния файл на Moodle, например стойността като 0.1s (100 милисекунди) би трябвало да е съвсем наред. Разбира се, ако срещнете някакви проблеми, винаги можете да увеличите тази стойност още повече.
Друга вариант за тестване би бил да разчитате единствено на MariaDB Cluster, за да разберете кога четенето е безопасно и кога не. Има променлива wsrep_sync_wait, която може да бъде конфигурирана да принуди проверки за причинно-следствена връзка на няколко модела на достъп (четене, актуализиране, вмъкване, изтриване, заместване и команди SHOW). За нашата цел би било достатъчно да гарантираме, че четенията се изпълняват с наложена причинно-следствена връзка, така че ще зададем тази променлива на „1“.
Ще направим тази промяна на всички възли на MariaDB Cluster. Също така ще трябва да преконфигурираме ProxySQL за разделяне на четене/запис въз основа на правилата на заявката, а не само на потребителите, както направихме преди. Също така ще премахнем потребителя „moodle_safereads“, тъй като той вече не е необходим в тази настройка.
Настройваме три правила за заявка, които разпределят трафика въз основа на заявката. SELECT ... FOR UPDATE се изпраща към възела за запис, всички заявки SELECT се изпращат до четците и всичко останало (INSERT, DELETE, REPLACE, UPDATE, BEGIN, COMMIT и т.н.) също се изпраща до възела за записване.
Това ни позволява да гарантираме, че всички четения могат да бъдат разпределени между възлите на четеца, като по този начин позволява хоризонтално мащабиране чрез добавяне на още възли към MariaDB Cluster.
Надяваме се с тези няколко съвета, че ще можете да мащабирате бекенда на базата данни на Moodle много по-лесно и в по-голяма степен