MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

Napisz swojego pierwszego doradcę

Czy kiedykolwiek zastanawiałeś się, co powoduje, że w ClusterControl pojawia się informacja, że ​​Twój dysk się zapełnia? Albo poradę dotyczącą tworzenia kluczy podstawowych w tabelach InnoDB, jeśli nie istnieją? Doradcy ci to miniskrypty napisane w języku ClusterControl Domain Specific Language (DSL), który jest językiem podobnym do Javascript. Skrypty te można pisać, kompilować, zapisywać, wykonywać i planować w ClusterControl. O tym będzie mowa w serii blogów ClusterControl Developer Studio.

Dzisiaj omówimy podstawy Developer Studio i pokażemy, jak stworzyć swojego pierwszego doradcę, w którym wybierzemy dwie zmienne stanu i udzielimy porad dotyczących ich wyniku.

Doradcy

Doradcy to miniskrypty wykonywane przez ClusterControl na żądanie lub zgodnie z harmonogramem. Mogą to być proste porady konfiguracyjne, ostrzeżenia dotyczące progów lub bardziej złożone reguły dotyczące przewidywań lub zadań automatyzacji obejmujących cały klaster w oparciu o stan serwerów lub baz danych. Ogólnie rzecz biorąc, doradcy przeprowadzają bardziej szczegółowe analizy i wydają bardziej kompleksowe zalecenia niż alerty.

Doradcy są przechowywani w bazie danych ClusterControl i można dodawać nowych lub zmieniać/modyfikować istniejących doradców. Posiadamy również repozytorium doradców Github, w którym możesz udostępniać swoich doradców nam i innym użytkownikom ClusterControl.

Język używany przez doradców to tak zwany ClusterControl DSL i jest to język łatwy do zrozumienia. Semantykę języka można najlepiej porównać do JavaScript z kilkoma różnicami, z których najważniejsze to:

  • Średniki są obowiązkowe
  • Różne liczbowe typy danych, takie jak liczby całkowite i długie liczby całkowite bez znaku.
  • Tablice są tablicami dwuwymiarowymi, a tablice jednowymiarowe są listami.

Pełną listę różnic można znaleźć w dokumentacji ClusterControl DSL.

Interfejs Developer Studio

Interfejs Developer Studio można znaleźć w Cluster> Manage> Developer Studio. Otworzy się taki interfejs:

Doradcy

Przycisk doradców wygeneruje przegląd wszystkich doradców z ich wynikami od ostatniego uruchomienia:

Możesz również zobaczyć harmonogram doradcy w formacie crontab oraz datę/godzinę od ostatniej aktualizacji. Niektórzy doradcy działają tylko raz dziennie, więc ich porady mogą nie odzwierciedlać już rzeczywistości, na przykład, jeśli już rozwiązałeś problem, o którym zostałeś ostrzeżony. Możesz ręcznie ponownie uruchomić doradcę, wybierając doradcę i uruchamiając go. Przejdź do sekcji „Skompiluj i uruchom”, aby dowiedzieć się, jak to zrobić.

Doradcy ds. importu

Przycisk Import pozwoli Ci zaimportować archiwum tar z nowymi doradcami. Plik tar musi zostać utworzony względem głównej ścieżki doradców, więc jeśli chcesz przesłać nową wersję skryptu rozmiaru pamięci podręcznej zapytań MySQL (s9s/mysql/query_cache/qc_size.js), musisz uruchomić archiwum z katalogu s9s.

Doradcy ds. eksportu

Możesz wyeksportować doradców lub ich część, wybierając węzeł w drzewie i naciskając przycisk Eksportuj. Spowoduje to utworzenie tarballa z plikami w pełnej ścieżce prezentowanej struktury. Załóżmy, że chcemy zrobić kopię zapasową doradców s9s/mysql przed dokonaniem zmiany, po prostu wybieramy węzeł s9s/mysql w drzewie i naciskamy Eksportuj:

Uwaga:upewnij się, że katalog s9s jest obecny w /home/myuser/.

Spowoduje to utworzenie tarballa o nazwie /home/myuser/s9s/mysql.tar.gz z wewnętrzną strukturą katalogów s9s/mysql/*

Tworzenie nowego doradcy

Ponieważ zajęliśmy się eksportem i importem, możemy teraz zacząć eksperymentować. Stwórzmy więc nowego doradcę! Kliknij przycisk Nowy, aby wyświetlić następujące okno dialogowe:

W tym oknie dialogowym możesz utworzyć nowego doradcę z pustym plikiem lub wstępnie wypełnić go szablonem Galera lub MySQL. Oba szablony dodadzą niezbędne dołączenia (common/mysql_helper.js) oraz podstawy do pobrania węzłów Galera lub MySQL i ich pętli.

Tworzenie nowego doradcy za pomocą szablonu Galera wygląda tak:

#include "common/mysql_helper.js" 

Tutaj możesz zobaczyć, że plik mysql_helper.js zostaje dołączony, aby zapewnić podstawę do łączenia i odpytywania węzłów MySQL.

Ten plik zawiera funkcje, które możesz wywołać w razie potrzeby, jak na przykład readVariable(,), które pozwolą ci uzyskać wartość zmiennych globalnych lub wywołać readStatusVariable(,), co również pozwoli ci aby uzyskać globalne zmienne statusu w MySQL. Ten plik może znajdować się w drzewie, jak pokazano poniżej:

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

Próg ostrzeżenia jest obecnie ustawiony na 0, co oznacza, że ​​jeśli zmierzony próg jest większy niż próg ostrzeżenia, doradca powinien ostrzec użytkownika. Pamiętaj, że próg zmiennej nie jest jeszcze ustawiony/używany w szablonie, ponieważ jest to początek dla twojego własnego doradcy.

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

Powyższe instrukcje pobiorą hosty w klastrze i możesz użyć tego do ich pętli. Różnica między nimi polega na tym, że pierwsza instrukcja obejmuje wszystkie hosty inne niż MySQL (także host CMON), druga wszystkie hosty MySQL, a ostatnia tylko gospodarze Galery. Jeśli więc Twój klaster Galera ma podłączone asynchroniczne moduły podrzędne odczytu MySQL, te hosty nie zostaną uwzględnione.

Poza tym wszystkie te obiekty będą zachowywać się tak samo i będą miały możliwość odczytywania swoich zmiennych, statusu i zapytań względem nich.

Przyciski doradcy

Po utworzeniu nowego doradcy dostępnych jest sześć nowych przycisków dla tego doradcy:

Zapisz zapisze twoje najnowsze modyfikacje do doradcy (przechowywane w bazie danych CMON), Przenieś przeniesie doradcę na nową ścieżkę i Usuń oczywiście usunie doradcę.

Bardziej interesujący jest drugi rząd przycisków. Kompilowanie doradcy spowoduje skompilowanie kodu doradcy. Jeśli kod skompiluje się poprawnie, zobaczysz ten komunikat w Wiadomościach dialog pod kodem doradcy:

Jeśli kompilacja się nie powiodła, kompilator podpowie, gdzie się nie udało:

W tym przypadku kompilator wskazuje błąd składni w linii 24.

kompilacja i uruchomienie przycisk nie tylko skompiluje skrypt, ale także go wykona, a jego wynik zostanie wyświetlony w oknie dialogowym Messages, Graph lub Raw. Jeśli skompilujemy i uruchomimy skrypt pamięci podręcznej tabeli z auto_tunerów, otrzymamy dane wyjściowe podobne do tego:

Ostatni przycisk to harmonogram przycisk. Dzięki temu możesz zaplanować (lub anulować) swoich doradców i dodać do nich tagi. Omówimy to na końcu tego posta, kiedy stworzyliśmy naszego własnego doradcę i chcemy to zaplanować.

Mój pierwszy doradca

Teraz, gdy omówiliśmy podstawy ClusterControl Developer Studio, możemy wreszcie zacząć tworzyć nowego doradcę. Jako przykład stworzymy doradcę, który przyjrzy się tymczasowemu współczynnikowi tabeli. Utwórz nowego doradcę w następujący sposób:

Teoria stojąca za doradcą, którego zamierzamy utworzyć, jest prosta:porównamy liczbę tabel tymczasowych utworzonych na dysku z całkowitą liczbą utworzonych tabel tymczasowych:

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

Najpierw musimy ustawić podstawowe informacje w nagłówku skryptu, takie jak progi oraz ostrzeżenia i komunikaty OK. Wszystkie zmiany i uzupełnienia są stosowane poniżej:

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

Ustawiliśmy tutaj próg na 20 procent, który już jest uważany za dość zły. Ale więcej na ten temat po sfinalizowaniu naszego doradcy.

Następnie musimy pobrać te zmienne stanu z MySQL. Zanim przejdziemy do konkluzji i wykonamy zapytanie „SHOW GLOBAL STATUS LIKE 'Created_tmp_%'”, istnieje już funkcja do pobrania zmiennej statusu instancji MySQL, tak jak opisaliśmy powyżej, gdzie ta funkcja znajduje się w common/mysql_helper. js:

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

Możemy użyć tej funkcji w naszym doradcy, aby pobrać Created_tmp_disk_tables i 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’); 

A teraz możemy obliczyć współczynnik tymczasowych tablic dyskowych:

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

I uwaga, jeśli ten stosunek jest większy niż próg, który ustawiliśmy na początku:

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

Ważne jest, aby w tym miejscu przypisać Porada do zmiennej msg, ponieważ zostanie ona dodana później do obiektu Porada za pomocą funkcji setAdvice(). Pełny skrypt dla kompletności:

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

Teraz możesz pobawić się progiem 20, spróbować obniżyć go na przykład do 1 lub 2, a wtedy prawdopodobnie zobaczysz, jak ten doradca faktycznie udzieli ci porady w tej sprawie.

Jak widać, za pomocą prostego skryptu możesz porównać ze sobą dwie zmienne i zgłosić/porada w oparciu o ich wynik. Ale czy to wszystko? Jest jeszcze kilka rzeczy, które możemy poprawić!

Ulepszenia mojego pierwszego doradcy

Pierwszą rzeczą, którą możemy poprawić, jest to, że ten doradca nie ma większego sensu. W rzeczywistości metryka odzwierciedla całkowitą liczbę tabel tymczasowych na dysku od ostatniego STATUSU FLUSH lub uruchomienia MySQL. To, czego nie mówi, to szybkość faktycznie tworzy tymczasowe tabele na dysku. Możemy więc przekonwertować tabele Created_tmp_disk_tables na współczynnik wykorzystujący czas pracy hosta:

    var tmp_disk_table_rate = tmp_disk_tables / uptime; 

Powinno to dać nam liczbę tymczasowych tabel na sekundę, aw połączeniu z tmp_disk_table_ratio da nam dokładniejszy obraz sytuacji. Ponownie, gdy osiągniemy próg dwóch tymczasowych tabel na sekundę, nie chcemy od razu wysyłać ostrzeżenia/porady.

Inną rzeczą, którą możemy poprawić, jest nieużywanie funkcji readStatusVariable(, ) z biblioteki common/mysql_helper.js. Ta funkcja wykonuje zapytanie do hosta MySQL za każdym razem, gdy odczytujemy zmienną statusu, podczas gdy CMON już pobiera większość z nich co sekundę, a i tak nie potrzebujemy statusu w czasie rzeczywistym. To nie jest tak, że dwa lub trzy zapytania zabiją hosty w klastrze, ale jeśli wielu z tych doradców działa w podobny sposób, może to spowodować mnóstwo dodatkowych zapytań.

W tym przypadku możemy to zoptymalizować, pobierając zmienne stanu w mapie za pomocą funkcji host.sqlInfo() i pobierając wszystko na raz jako mapę. Ta funkcja zawiera najważniejsze informacje o hoście, ale nie zawiera wszystkich. Na przykład zmienna uptime, której potrzebujemy dla szybkości, nie jest dostępna w mapie host.sqlInfo() i należy ją pobrać za pomocą funkcji readStatusVariable(, ).

Tak będzie teraz wyglądał nasz doradca, z pogrubionymi zmianami/dodatkami:

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

Planowanie mojego pierwszego doradcy

Po zapisaniu tego nowego doradcy, skompilowaniu go i uruchomieniu możemy teraz zaplanować ten doradca. Ponieważ nie mamy nadmiernego obciążenia pracą, prawdopodobnie będziemy uruchamiać tego doradcę raz dziennie.

Podstawowy tryb planowania jest podobny do Cron, który ma ustawione co minutę, 5 minut, godzinę, dzień, miesiąc i jest to dokładnie to, czego potrzebujemy i jest bardzo łatwe do zarządzania harmonogramem. Zmiana tego na zaawansowane odblokuje inne wyszarzone pola wprowadzania. Te pola wejściowe działają dokładnie tak samo jak crontab, więc możesz nawet zaplanować konkretny dzień, dzień miesiąca, a nawet ustawić go na dni powszednie.

Podążając za tym blogiem, utworzymy narzędzie do sprawdzania SELinux lub testy bezpieczeństwa dla Spectre i Meltdown, jeśli dotyczy to węzłów. Bądź na bieżąco!


  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. MongoDB $gt Operator potoku agregacji

  2. MongoDb:znajdź głęboko zagnieżdżony obiekt za pomocą $lookup

  3. MongoDB $count Operator agregacji

  4. MongoDB $setOnInsert

  5. Szybki sposób na znalezienie duplikatów w indeksowanej kolumnie w mongodb