sql >> Databasteknik >  >> NoSQL >> MongoDB

Skriv din första rådgivare

Har du någonsin undrat vad som utlöser rådet i ClusterControl att din disk håller på att fyllas? Eller rådet att skapa primärnycklar på InnoDB-tabeller om de inte finns? Dessa rådgivare är miniskript skrivna i ClusterControl Domain Specific Language (DSL) som är ett Javascript-liknande språk. Dessa skript kan skrivas, kompileras, sparas, köras och schemaläggas i ClusterControl. Det är vad bloggserien ClusterControl Developer Studio kommer att handla om.

Idag kommer vi att täcka grunderna i Developer Studio och visa dig hur du skapar din allra första rådgivare där vi väljer två statusvariabler och ger råd om deras resultat.

Rådgivarna

Rådgivare är miniskript som exekveras av ClusterControl, antingen på begäran eller efter ett schema. De kan vara allt från enkla konfigurationsråd, varningar om trösklar eller mer komplexa regler för förutsägelser eller klusteromfattande automatiseringsuppgifter baserat på tillståndet för dina servrar eller databaser. I allmänhet utför rådgivare mer detaljerade analyser och producerar mer omfattande rekommendationer än varningar.

Rådgivarna lagras i ClusterControl-databasen och du kan lägga till nya eller ändra/modifiera befintliga rådgivare. Vi har också ett Github-förråd för rådgivare där du kan dela dina rådgivare med oss ​​och andra ClusterControl-användare.

Språket som används för rådgivarna är det så kallade ClusterControl DSL och är ett lättbegripligt språk. Språkets semantik kan bäst jämföras med Javascript med ett par skillnader, där de viktigaste skillnaderna är:

  • Semikolon är obligatoriska
  • Olika numeriska datatyper som heltal och långa heltal utan tecken.
  • Arrayer är tvådimensionella och enkeldimensionella arrayer är listor.

Du kan hitta hela listan över skillnader i ClusterControl DSL-referensen.

Utvecklarstudions gränssnitt

Developer Studio-gränssnittet finns under Cluster> Hantera> Developer Studio. Detta öppnar ett gränssnitt så här:

Rådgivare

Knappen rådgivare genererar en översikt över alla rådgivare med deras resultat sedan senaste gången de körde:

Du kan också se rådgivarens schema i crontab-format och datum/tid sedan senaste uppdateringen. Vissa rådgivare är schemalagda att köra endast en gång om dagen så deras råd kanske inte längre speglar verkligheten, till exempel om du redan har löst problemet du varnades för. Du kan manuellt köra rådgivaren igen genom att välja rådgivaren och köra den. Gå till avsnittet "kompilera och kör" för att läsa hur du gör detta.

Importrådgivare

Importera-knappen låter dig importera en tarball med nya rådgivare i dem. Tarballen måste skapas i förhållande till rådgivarnas huvudsökväg, så om du vill ladda upp en ny version av skriptet MySQL query cache size (s9s/mysql/query_cache/qc_size.js) måste du starta tarballen från s9s-katalogen.

Exporterande rådgivare

Du kan exportera rådgivarna eller en del av dem genom att välja en nod i trädet och trycka på knappen Exportera. Detta kommer att skapa en tarball med filerna i hela sökvägen för den presenterade strukturen. Anta att vi vill göra en säkerhetskopia av s9s/mysql-rådgivarna innan vi gör en ändring, vi väljer helt enkelt s9s/mysql-noden i trädet och trycker på Exportera:

Obs:se till att s9s-katalogen finns i /home/myuser/.

Detta kommer att skapa en tarball som heter /home/myuser/s9s/mysql.tar.gz med en intern katalogstruktur s9s/mysql/*

Skapa en ny rådgivare

Eftersom vi har täckt export och import kan vi nu börja experimentera. Så låt oss skapa en ny rådgivare! Klicka på knappen Ny för att få följande dialog:

I den här dialogrutan kan du skapa din nya rådgivare med antingen en tom fil eller förfylla den med den Galera- eller MySQL-specifika mallen. Båda mallarna kommer att lägga till de nödvändiga inslagen (common/mysql_helper.js) och grunderna för att hämta Galera- eller MySQL-noderna och loopa över dem.

Att skapa en ny rådgivare med Galera-mallen ser ut så här:

#include "common/mysql_helper.js"

Här kan du se att mysql_helper.js inkluderas för att ge grunden för att ansluta och fråga MySQL-noder.

Den här filen innehåller funktioner som du kan anropa om det behövs som till exempel readVariable(,) som gör att du kan få det globala variabelvärdet eller anropa readStatusVariable(,) vilket också låter dig för att få de globala statusvariablerna i MySQL. Den här filen kan finnas i trädet som visas nedan:

var WARNING_THRESHOLD=0;
…
if(threshold > WARNING_THRESHOLD)

Varningströskeln är för närvarande inställd på 0, vilket innebär att om den uppmätta tröskeln är högre än varningströskeln, bör rådgivaren varna användaren. Observera att den variabla tröskeln inte är inställd/används i mallen ännu då den är en kickstart för din egen rådgivare.

var hosts     = cluster::Hosts();
var hosts     = cluster::mySqlNodes();
var hosts     = cluster::galeraNodes();

Uttrycken ovan hämtar värdarna i klustret och du kan använda detta för att loopa över dem. Skillnaden mellan dem är att den första satsen inkluderar alla icke-MySQL-värdar (även CMON-värden), den andra alla MySQL-värdar och den sista endast Galera-värdarna. Så om ditt Galera-kluster har MySQL asynkrona lässlavar kopplade, kommer dessa värdar inte att inkluderas.

Utöver det kommer alla dessa objekt att bete sig likadant och har förmågan att läsa deras variabler, status och fråga mot dem.

Rådgivareknappar

Nu när vi har skapat en ny rådgivare finns det sex nya knappar tillgängliga för denna rådgivare:

Spara kommer att spara dina senaste ändringar till rådgivaren (lagrad i CMON-databasen), Flytta kommer att flytta rådgivaren till en ny sökväg och Ta bort kommer uppenbarligen att ta bort rådgivaren.

Mer intressant är den andra raden med knappar. Att sammanställa rådgivaren kommer att sammanställa rådgivarens kod. Om koden kompileras bra kommer du att se detta meddelande i Meddelanden dialog under rådgivarens kod:

Om kompileringen misslyckades kommer kompilatorn att ge dig en ledtråd var den misslyckades:

I detta fall indikerar kompilatorn att ett syntaxfel hittades på rad 24.

kompilera och kör -knappen kommer inte bara att kompilera skriptet utan också köra det och dess utdata kommer att visas i dialogrutan Meddelanden, Graph eller Raw. Om vi ​​kompilerar och kör tabellcacheskriptet från auto_tuners, kommer vi att få utdata som liknar detta:

Den sista knappen är schemat knapp. Detta gör att du kan schemalägga (eller avboka) dina rådgivare och lägga till taggar till dem. Vi kommer att ta upp detta i slutet av det här inlägget när vi har skapat vår alldeles egna rådgivare och vill schemalägga det.

Min första rådgivare

Nu när vi har täckt grunderna i ClusterControl Developer Studio kan vi nu äntligen börja skapa en ny rådgivare. Som ett exempel kommer vi att skapa en rådgivare för att titta på det tillfälliga tabellförhållandet. Skapa en ny rådgivare enligt följande:

Teorin bakom rådgivaren vi ska skapa är enkel:vi kommer att jämföra antalet temporära tabeller som skapats på disken med det totala antalet tillfälliga tabeller som skapats:

tmp_disk_table_ratio = Created_tmp_disk_tables / (Created_tmp_tables + Created_tmp_disk_tables) * 100;

Först måste vi ställa in några grunder i huvudet på skriptet, som trösklarna och varnings- och ok-meddelandena. Alla ändringar och tillägg tillämpas nedan:

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." ;

Vi sätter gränsen här till 20 procent vilket anses vara ganska dåligt redan. Men mer om det ämnet när vi har slutfört vår rådgivare.

Därefter måste vi hämta dessa statusvariabler från MySQL. Innan vi drar till slutsatser och kör någon "VISA GLOBAL STATUS SOM 'Created_tmp_%'"-fråga, finns det redan en funktion för att hämta statusvariabeln för en MySQL-instans, som det vi beskrev ovan där denna funktion finns i common/mysql_helper. js:

statusVar = readStatusVariable(<host>, <statusvariablename>);

Vi kan använda den här funktionen i vår rådgivare för att hämta Create_tmp_disk_tables och 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’);

Och nu kan vi beräkna det temporära disktabellförhållandet:

        var tmp_disk_table_ratio = tmp_disk_tables / (tmp_tables + tmp_disk_tables) * 100;

Och varna om detta förhållande är större än tröskeln vi ställde in i början:

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

Det är viktigt att tilldela Advice till variabeln msg här eftersom denna kommer att läggas till senare i rådgivningsobjektet med funktionen setAdvice(). Hela skriptet för fullständighet:

#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;
}

Nu kan du leka med tröskeln 20, försöka sänka den till t.ex. 1 eller 2 och då kan du förmodligen se hur den här rådgivaren faktiskt kommer att ge dig råd i frågan.

Som du kan se kan du med ett enkelt skript kontrollera två variabler mot varandra och rapportera/råda baserat på deras resultat. Men är det allt? Det finns fortfarande ett par saker vi kan förbättra!

Förbättringar av min första rådgivare

Det första vi kan förbättra är att den här rådgivaren inte är så vettig. Vad mätvärdet faktiskt återspeglar är det totala antalet temporära tabeller på disken sedan den senaste FLUSH STATUS eller start av MySQL. Vad det inte står är till vilken takt det skapar faktiskt tillfälliga tabeller på disken. Så vi kan konvertera Create_tmp_disk_tables till en hastighet med hjälp av värdens drifttid:

    var tmp_disk_table_rate = tmp_disk_tables / uptime;

Detta bör ge oss antalet temporära tabeller per sekund och i kombination med tmp_disk_table_ratio kommer detta att ge oss en mer exakt bild av saker och ting. Återigen, när vi når tröskeln på två tillfälliga bord per sekund vill vi inte genast skicka ut en varning/rådgivning.

En annan sak vi kan förbättra är att inte använda funktionen readStatusVariable(, ) från common/mysql_helper.js-biblioteket. Denna funktion exekverar en fråga till MySQL-värden varje gång vi läser en statusvariabel, medan CMON redan hämtar de flesta av dem varje sekund och vi behöver inte en realtidsstatus ändå. Det är inte så att två eller tre frågor kommer att döda värdarna i klustret, men om många av dessa rådgivare körs på ett liknande sätt kan detta skapa massor av extra frågor.

I det här fallet kan vi optimera detta genom att hämta statusvariablerna i en karta med funktionen host.sqlInfo() och hämta allt på en gång som en karta. Den här funktionen innehåller den viktigaste informationen om värden, men den innehåller inte all. Till exempel är den variabel upptid som vi behöver för hastigheten inte tillgänglig i host.sqlInfo()-kartan och måste hämtas med funktionen readStatusVariable(, ).

Så här kommer vår rådgivare att se ut nu, med ändringarna/tilläggen markerade i fet stil:

#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;
}

Schemalägger min första rådgivare

Efter att vi har sparat den här nya rådgivaren, kompilerat den och kört, kan vi nu schemalägga den här rådgivaren. Eftersom vi inte har en överdriven arbetsbelastning kommer vi förmodligen att köra den här rådgivaren en gång om dagen.

Grundschemaläggningsläget liknar Cron som har varje minut, 5 minuter, timme, dag, månad förinställd och detta är precis vad vi behöver och är mycket lätt att hantera schemaläggningen. Om du ändrar detta till avancerat låser du upp de andra nedtonade inmatningsfälten. Dessa inmatningsfält fungerar exakt på samma sätt som en crontab, så du kan till och med schemalägga för en viss dag, dag i månaden eller till och med ställa in den på vardagar.

Efter den här bloggen kommer vi att skapa en checker för SELinux eller säkerhetskontroller för Spectre och Meltdown om noder påverkas. Håll utkik!


  1. Så här tar du emot Redis-publiceringsmeddelande i Go

  2. Ställ in Cache Redis Expiration till 1 år

  3. Docker Redis Connection vägrade

  4. Klona databas i Mongodb mellan värdar med noddrivrutin