Чудили ли сте се някога какво задейства съвета в ClusterControl, че дискът ви се пълни? Или съветът за създаване на първични ключове в таблици InnoDB, ако те не съществуват? Тези съветници са мини скриптове, написани на ClusterControl Domain Specific Language (DSL), който е език, подобен на Javascript. Тези скриптове могат да бъдат написани, компилирани, записани, изпълнени и планирани в ClusterControl. За това ще бъде поредицата блогове на ClusterControl Developer Studio.
Днес ще разгледаме основите на Developer Studio и ще ви покажем как да създадете първия си съветник, където ще изберем две променливи на състоянието и ще дадем съвети относно резултата от тях.
Съветниците
Съветниците са мини скриптове, които се изпълняват от ClusterControl, при поискване или след график. Те могат да бъдат всичко - от прости съвети за конфигуриране, предупреждение за прагове или по-сложни правила за прогнози или задачи за автоматизация в целия клъстер въз основа на състоянието на вашите сървъри или бази данни. Като цяло съветниците извършват по-подробен анализ и дават по-изчерпателни препоръки, отколкото сигнали.
Съветниците се съхраняват в базата данни на ClusterControl и можете да добавяте нови или да променяте/модифицирате съществуващи съветници. Имаме и хранилище на Github за съветници, където можете да споделяте своите съветници с нас и други потребители на ClusterControl.
Езикът, използван за съветниците, е така нареченият ClusterControl DSL и е лесен за разбиране език. Семантиката на езика може да бъде най-добре сравнена с Javascript с няколко разлики, като най-важните разлики са:
- Точка и запетая са задължителни
- Различни типове числови данни, като цели числа и дълги дълги цели числа без знак.
- Масивите са двуизмерни, а едномерните масиви са списъци.
Можете да намерите пълния списък с разликите в справочника на ClusterControl DSL.
Интерфейсът на Developer Studio
Интерфейсът на Developer Studio може да бъде намерен под Cluster> Manage> Developer Studio. Това ще отвори интерфейс като този:
Съветници
Бутонът за съветници ще генерира преглед на всички съветници с техния резултат от последния път, когато са стартирали:
Можете също да видите графика на съветника във формат crontab и датата/часа от последната актуализация. Някои съветници са планирани да работят само веднъж на ден, така че техните съвети може вече да не отразяват реалността, например ако вече сте разрешили проблема, за който сте били предупредени. Можете ръчно да стартирате отново съветника, като изберете съветника и го стартирате. Отидете в секцията „компилиране и стартиране“, за да прочетете как да направите това.
Импортиране на съветници
Бутонът Import ще ви позволи да импортирате tarball с нови съветници в тях. Архивът трябва да бъде създаден спрямо главния път на съветниците, така че ако искате да качите нова версия на скрипта за размера на кеша на заявките MySQL (s9s/mysql/query_cache/qc_size.js), ще трябва да стартирате tarball от директорията s9s.
Експортиране на съветници
Можете да експортирате съветниците или част от тях, като изберете възел в дървото и натиснете бутона Експортиране. Това ще създаде tarball с файловете в пълния път на представената структура. Да предположим, че искаме да направим резервно копие на съветниците s9s/mysql, преди да направим промяна, просто избираме s9s/mysql възела в дървото и натискаме Export:
Забележка:уверете се, че директорията s9s присъства в /home/myuser/.
Това ще създаде tarball, наречен /home/myuser/s9s/mysql.tar.gz с вътрешна структура на директории s9s/mysql/*
Създаване на нов съветник
Тъй като покрихме износа и вноса, сега можем да започнем да експериментираме. Така че нека създадем нов съветник! Щракнете върху бутона Нов, за да получите следния диалог:
В този диалог можете да създадете своя нов съветник с празен файл или предварително да го попълните със специфичния за Galera или MySQL шаблон. И двата шаблона ще добавят необходимите включвания (common/mysql_helper.js) и основите за извличане на възлите Galera или MySQL и преминаване през тях.
Създаването на нов съветник с шаблона Galera изглежда така:
#include "common/mysql_helper.js"
Тук можете да видите, че mysql_helper.js се включва, за да осигури основата за свързване и запитване на MySQL възли.
Този файл съдържа функции, които можете да извикате, ако е необходимо, като например readVariable(
var WARNING_THRESHOLD=0;
…
if(threshold > WARNING_THRESHOLD)
Предупредителният праг в момента е настроен на 0, което означава, че ако измереният праг е по-голям от прага за предупреждение, съветникът трябва да предупреди потребителя. Имайте предвид, че прагът на променливата все още не е зададен/използван в шаблона, тъй като е начален старт за вашия собствен съветник.
var hosts = cluster::Hosts();
var hosts = cluster::mySqlNodes();
var hosts = cluster::galeraNodes();
Изявленията по-горе ще извлекат хостовете в клъстера и можете да използвате това, за да ги обиколите. Разликата между тях е, че първият израз включва всички хостове, които не са MySQL (също и CMON хост), вторият всички хостове на MySQL и последния само домакините на Галера. Така че, ако вашият клъстер Galera има прикачени MySQL асинхронни подчинени устройства за четене, тези хостове няма да бъдат включени.
Освен това, всички тези обекти ще се държат еднакво и ще имат възможност да четат своите променливи, статус и заявка спрямо тях.
Бутони за съветник
Сега, когато създадохме нов съветник, за този съветник има шест нови бутона:
Запазване ще запази последните ви модификации в съветника (съхранен в базата данни CMON), Преместване ще премести съветника на нов път и Премахване очевидно ще премахне съветника.
По-интересен е вторият ред бутони. Компилирането на съветника ще компилира кода на съветника. Ако кодът се компилира добре, ще видите това съобщение в Съобщения диалог под кода на съветника:
Докато ако компилацията е неуспешна, компилаторът ще ви даде намек къде се е провалила:
В този случай компилаторът показва, че е намерена синтактична грешка на ред 24.
Компилирайте и стартирайте бутон не само ще компилира скрипта, но и ще го изпълни и неговият изход ще бъде показан в диалоговия прозорец Messages, Graph или Raw. Ако компилираме и стартираме скрипта за кеширане на таблицата от auto_tuners, ще получим изход, подобен на този:
Последният бутон е графикът бутон. Това ви позволява да планирате (или да отмените графика) на вашите съветници и да добавяте тагове към тях. Ще разгледаме това в края на тази публикация, когато създадем наш собствен съветник и искаме да го планираме.
Моят първи съветник
След като покрихме основите на ClusterControl Developer Studio, най-накрая можем да започнем да създаваме нов съветник. Като пример ще създадем съветник за разглеждане на съотношението на временната таблица. Създайте нов съветник, както следва:
Теорията зад съветника, който ще създадем, е проста:ще сравним броя на временните таблици, създадени на диска, с общия брой създадени временни таблици:
tmp_disk_table_ratio = Created_tmp_disk_tables / (Created_tmp_tables + Created_tmp_disk_tables) * 100;
Първо трябва да зададем някои основни неща в главата на скрипта, като праговете и съобщенията за предупреждение и ОК. Всички промени и допълнения се прилагат по-долу:
var WARNING_THRESHOLD=20;
var TITLE="Temporary tables on disk ratio";
var ADVICE_WARNING="More than 20% of temporary tables are written to disk. It is advised to review your queries, for example, via the Query Monitor.";
var ADVICE_OK="Temporary tables on disk are not excessive." ;
Ние задаваме прага тук на 20 процента, което вече се счита за доста лошо. Но повече по тази тема, след като финализираме нашия съветник.
След това трябва да получим тези променливи на състоянието от MySQL. Преди да направим прибързани заключения и да изпълним някаква заявка „SHOW GLOBAL STATUS LIKE 'Created_tmp_%'”, вече има функция за извличане на променливата на състоянието на екземпляр на MySQL, както описахме по-горе къде се намира тази функция в common/mysql_helper. js:
statusVar = readStatusVariable(<host>, <statusvariablename>);
Можем да използваме тази функция в нашия съветник, за да извлечем Created_tmp_disk_tables и Created_tmp_tables.
for (idx = 0; idx < hosts.size(); ++idx)
{
host = hosts[idx];
map = host.toMap();
connected = map["connected"];
var advice = new CmonAdvice();
var tmp_tables = readStatusVariable(host, ‘Created_tmp_tables’);
var tmp_disk_tables = readStatusVariable(host, ‘Created_tmp_disk_tables’);
И сега можем да изчислим съотношението на временните дискови таблици:
var tmp_disk_table_ratio = tmp_disk_tables / (tmp_tables + tmp_disk_tables) * 100;
И предупреждение, ако това съотношение е по-голямо от прага, който зададохме в началото:
if(checkPrecond(host))
{
if(tmp_disk_table_ratio > WARNING_THRESHOLD) {
advice.setJustification("Temporary tables written to disk is excessive");
msg = ADVICE_WARNING;
}
else {
advice.setJustification("Temporary tables written to disk not excessive");
msg = ADVICE_OK;
}
}
Важно е да присвоите съвета на променливата msg тук, тъй като тя ще бъде добавена по-късно в обекта за съвет с функцията setAdvice(). Пълният скрипт за пълнота:
#include "common/mysql_helper.js"
/**
* Checks the percentage of max ever used connections
*
*/
var WARNING_THRESHOLD=20;
var TITLE="Temporary tables on disk ratio";
var ADVICE_WARNING="More than 20% of temporary tables are written to disk. It is advised to review your queries, for example, via the Query Monitor.";
var ADVICE_OK="Temporary tables on disk are not excessive.";
function main()
{
var hosts = cluster::mySqlNodes();
var advisorMap = {};
for (idx = 0; idx < hosts.size(); ++idx)
{
host = hosts[idx];
map = host.toMap();
connected = map["connected"];
var advice = new CmonAdvice();
var tmp_tables = readStatusVariable(host, 'Created_tmp_tables');
var tmp_disk_tables = readStatusVariable(host, 'Created_tmp_disk_tables');
var tmp_disk_table_ratio = tmp_disk_tables / (tmp_tables + tmp_disk_tables) * 100;
if(!connected)
continue;
if(checkPrecond(host))
{
if(tmp_disk_table_ratio > WARNING_THRESHOLD) {
advice.setJustification("Temporary tables written to disk is excessive");
msg = ADVICE_WARNING;
advice.setSeverity(0);
}
else {
advice.setJustification("Temporary tables written to disk not excessive");
msg = ADVICE_OK;
}
}
else
{
msg = "Not enough data to calculate";
advice.setJustification("there is not enough load on the server or the uptime is too little.");
advice.setSeverity(0);
}
advice.setHost(host);
advice.setTitle(TITLE);
advice.setAdvice(msg);
advisorMap[idx]= advice;
}
return advisorMap;
}
Сега можете да си поиграете с прага от 20, опитайте се да го намалите до 1 или 2 например и тогава вероятно ще видите как този съветник всъщност ще ви даде съвет по въпроса.
Както можете да видите, с прост скрипт можете да проверите две променливи една срещу друга и да докладвате/съветвате въз основа на техния резултат. Но това ли е всичко? Все още има няколко неща, които можем да подобрим!
Подобрения на първия ми съветник
Първото нещо, което можем да подобрим, е, че този съветник няма много смисъл. Това, което метриката всъщност отразява, е общият брой временни таблици на диска след последния СТАТУС НА FLUSH или стартиране на MySQL. Това, което не пише, е с каква ставка всъщност създава временни таблици на диска. Така че можем да преобразуваме Created_tmp_disk_tables в скорост, използвайки времето на работа на хоста:
var tmp_disk_table_rate = tmp_disk_tables / uptime;
Това трябва да ни даде броя на временните таблици в секунда и в комбинация с tmp_disk_table_ratio, това ще ни даде по-точен поглед върху нещата. Отново, след като достигнем прага от две временни таблици в секунда, не искаме незабавно да изпращаме предупреждение/съвет.
Друго нещо, което можем да подобрим, е да не използваме функцията readStatusVariable(
В този случай можем да оптимизираме това, като извлечем променливите на състоянието в карта с помощта на функцията host.sqlInfo() и извлечем всичко наведнъж като карта. Тази функция съдържа най-важната информация за хоста, но не съдържа цялата. Например променливата продължителност на работа, която ни е необходима за скоростта, не е налична в картата host.sqlInfo() и трябва да бъде извлечена с функцията readStatusVariable(
Ето как ще изглежда нашият съветник сега, с промените/допълненията, маркирани с удебелен шрифт:
#include "common/mysql_helper.js"
/**
* Checks the percentage of max ever used connections
*
*/
var RATIO_WARNING_THRESHOLD=20;
var RATE_WARNING_THRESHOLD=2;
var TITLE="Temporary tables on disk ratio";
var ADVICE_WARNING="More than 20% of temporary tables are written to disk and current rate is more than 2 temporary tables per second. It is advised to review your queries, for example, via the Query Monitor.";
var ADVICE_OK="Temporary tables on disk are not excessive.";
function main()
{
var hosts = cluster::mySqlNodes();
var advisorMap = {};
for (idx = 0; idx < hosts.size(); ++idx)
{
host = hosts[idx];
map = host.toMap();
connected = map["connected"];
var advice = new CmonAdvice();
var hostStatus = host.sqlInfo();
var tmp_tables = hostStatus['CREATED_TMP_TABLES'];
var tmp_disk_tables = hostStatus['CREATED_TMP_DISK_TABLES'];
var uptime = readStatusVariable(host, 'uptime');
var tmp_disk_table_ratio = tmp_disk_tables / (tmp_tables + tmp_disk_tables) * 100;
var tmp_disk_table_rate = tmp_disk_tables / uptime;
if(!connected)
continue;
if(checkPrecond(host))
{
if(tmp_disk_table_rate > RATE_WARNING_THRESHOLD && tmp_disk_table_ratio > RATIO_WARNING_THRESHOLD) {
advice.setJustification("Temporary tables written to disk is excessive: " + tmp_disk_table_rate + " tables per second and overall ratio of " + tmp_disk_table_ratio);
msg = ADVICE_WARNING;
advice.setSeverity(0);
}
else {
advice.setJustification("Temporary tables written to disk not excessive");
msg = ADVICE_OK;
}
}
else
{
msg = "Not enough data to calculate";
advice.setJustification("there is not enough load on the server or the uptime is too little.");
advice.setSeverity(0);
}
advice.setHost(host);
advice.setTitle(TITLE);
advice.setAdvice(msg);
advisorMap[idx]= advice;
}
return advisorMap;
}
Насрочвам първия си съветник
След като запазихме този нов съветник, компилирахме го и стартирахме, сега можем да планираме този съветник. Тъй като нямаме прекомерно натоварване, вероятно ще стартираме този съветник веднъж на ден.
Основният режим на планиране е подобен на Cron, който има предварително зададени всяка минута, 5 минути, час, ден, месец и това е точно това, от което се нуждаем и е много лесно за управление на графика. Промяната на това на разширени ще отключи другите полета за въвеждане в сиво. Тези полета за въвеждане работят точно като crontab, така че можете дори да планирате за конкретен ден, ден от месеца или дори да го зададете в делнични дни.
Следвайки този блог, ще създадем проверка за SELinux или проверки за сигурност за Spectre и Meltdown, ако възлите са засегнати. Останете на линия!