Você já se perguntou o que aciona o aviso no ClusterControl de que seu disco está enchendo? Ou o conselho para criar chaves primárias em tabelas InnoDB se elas não existirem? Esses orientadores são mini scripts escritos na Linguagem Específica de Domínio ClusterControl (DSL) que é uma linguagem semelhante a Javascript. Esses scripts podem ser escritos, compilados, salvos, executados e agendados no ClusterControl. É sobre isso que a série de blogs do ClusterControl Developer Studio tratará.
Hoje abordaremos o básico do Developer Studio e mostraremos como criar seu primeiro consultor, onde escolheremos duas variáveis de status e daremos conselhos sobre o resultado.
Os Conselheiros
Advisors são mini scripts executados pelo ClusterControl, sob demanda ou após um agendamento. Eles podem ser qualquer coisa, desde simples conselhos de configuração, avisos sobre limites ou regras mais complexas para previsões ou tarefas de automação em todo o cluster com base no estado de seus servidores ou bancos de dados. Em geral, os consultores realizam análises mais detalhadas e produzem recomendações mais abrangentes do que alertas.
Os orientadores são armazenados dentro do banco de dados do ClusterControl e você pode adicionar novos orientadores ou alterar/modificar os existentes. Também temos um repositório Github de conselheiros onde você pode compartilhar seus conselheiros conosco e com outros usuários do ClusterControl.
A linguagem utilizada pelos orientadores é a chamada ClusterControl DSL e é uma linguagem de fácil compreensão. A semântica da linguagem pode ser melhor comparada ao Javascript com algumas diferenças, onde as diferenças mais importantes são:
- Os pontos e vírgulas são obrigatórios
- Vários tipos de dados numéricos, como inteiros e inteiros longos não assinados.
- Matrizes são bidimensionais e matrizes unidimensionais são listas.
Você pode encontrar a lista completa de diferenças na referência de DSL do ClusterControl.
A interface do Developer Studio
A interface do Developer Studio pode ser encontrada em Cluster> Gerenciar> Developer Studio. Isso abrirá uma interface como esta:
Conselheiros
O botão de orientadores gerará uma visão geral de todos os orientadores com sua saída desde a última vez em que foram executados:
Você também pode ver a agenda do orientador no formato crontab e a data/hora desde a última atualização. Alguns consultores são programados para serem executados apenas uma vez por dia, de modo que seus conselhos podem não refletir mais a realidade, por exemplo, se você já resolveu o problema sobre o qual foi avisado. Você pode reexecutar manualmente o orientador selecionando o orientador e executá-lo. Vá para a seção “compilar e executar” para ler como fazer isso.
Consultores de importação
O botão Importar permitirá que você importe um tarball com novos conselheiros neles. O tarball deve ser criado em relação ao caminho principal dos conselheiros, então se você deseja fazer o upload de uma nova versão do script de tamanho do cache de consulta do MySQL (s9s/mysql/query_cache/qc_size.js) você terá que fazer o tarball iniciar do diretório s9s.
Consultores de exportação
Você pode exportar os orientadores ou parte deles selecionando um nó na árvore e pressionando o botão Exportar. Isso criará um tarball com os arquivos no caminho completo da estrutura apresentada. Suponha que desejamos fazer um backup dos conselheiros s9s/mysql antes de fazer uma alteração, simplesmente selecionamos o nó s9s/mysql na árvore e pressionamos Export:
Observação:certifique-se de que o diretório s9s esteja presente em /home/myuser/.
Isso criará um tarball chamado /home/myuser/s9s/mysql.tar.gz com uma estrutura de diretório interna s9s/mysql/*
Criando um novo consultor
Já que cobrimos exportações e importações, podemos agora começar a experimentar. Então vamos criar um novo conselheiro! Clique no botão Novo para obter o seguinte diálogo:
Nesta caixa de diálogo, você pode criar seu novo orientador com um arquivo vazio ou preenchê-lo com o modelo específico do Galera ou MySQL. Ambos os modelos adicionarão as inclusões necessárias (common/mysql_helper.js) e o básico para recuperar os nós Galera ou MySQL e fazer um loop sobre eles.
A criação de um novo orientador com o modelo Galera se parece com isso:
#include "common/mysql_helper.js"
Aqui você pode ver que o mysql_helper.js é incluído para fornecer a base para conectar e consultar nós MySQL.
Este arquivo contém funções que você pode invocar se necessário, como por exemplo readVariable(
var WARNING_THRESHOLD=0;
…
if(threshold > WARNING_THRESHOLD)
O limite de aviso está atualmente definido como 0, o que significa que se o limite medido for maior que o limite de aviso, o orientador deve avisar o usuário. Observe que o limite variável ainda não está definido/usado no modelo, pois é um kickstart para seu próprio orientador.
var hosts = cluster::Hosts();
var hosts = cluster::mySqlNodes();
var hosts = cluster::galeraNodes();
As instruções acima buscarão os hosts no cluster e você pode usar isso para fazer um loop sobre eles. A diferença entre eles é que a primeira instrução inclui todos os hosts não MySQL (também o host CMON), a segunda todos os hosts MySQL e a última somente os anfitriões da Galera. Portanto, se seu cluster Galera tiver escravos de leitura assíncrona MySQL anexados, esses hosts não serão incluídos.
Fora isso, todos esses objetos se comportarão da mesma forma e apresentarão a capacidade de ler suas variáveis, status e consulta a eles.
Botões do orientador
Agora que criamos um novo orientador, existem seis novos botões disponíveis para este orientador:
Salvar salvará suas últimas modificações no orientador (armazenado no banco de dados CMON), Mover irá mover o orientador para um novo caminho e Remover obviamente removerá o conselheiro.
Mais interessante é a segunda linha de botões. Compilar o orientador compilará o código do orientador. Se o código compilar bem, você verá esta mensagem nas Mensagens diálogo abaixo do código do orientador:
Enquanto a compilação falhou, o compilador lhe dará uma dica de onde falhou:
Nesse caso, o compilador indica que um erro de sintaxe foi encontrado na linha 24.
O compilar e executar botão não apenas compilará o script, mas também o executará e sua saída será mostrada na caixa de diálogo Mensagens, Gráfico ou Raw. Se compilarmos e executarmos o script de cache de tabela dos auto_tuners, obteremos uma saída semelhante a esta:
O último botão é a agenda botão. Isso permite que você agende (ou desmarque) seus orientadores e adicione tags a eles. Abordaremos isso no final deste post quando tivermos criado nosso próprio consultor e quisermos agendá-lo.
Meu primeiro conselheiro
Agora que abordamos o básico do ClusterControl Developer Studio, podemos finalmente começar a criar um novo orientador. Como exemplo, criaremos um orientador para observar a proporção da tabela temporária. Crie um novo orientador da seguinte forma:
A teoria por trás do orientador que vamos criar é simples:vamos comparar o número de tabelas temporárias criadas no disco com o número total de tabelas temporárias criadas:
tmp_disk_table_ratio = Created_tmp_disk_tables / (Created_tmp_tables + Created_tmp_disk_tables) * 100;
Primeiro precisamos definir algumas noções básicas no cabeçalho do script, como os limites e as mensagens de aviso e ok. Todas as alterações e adições são aplicadas abaixo:
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." ;
Definimos o limite aqui para 20%, o que já é considerado muito ruim. Mas falaremos mais sobre esse tópico assim que finalizarmos nosso orientador.
Em seguida, precisamos obter essas variáveis de status do MySQL. Antes de tirarmos conclusões precipitadas e executarmos alguma consulta “SHOW GLOBAL STATUS LIKE 'Created_tmp_%'”, já existe uma função para recuperar a variável de status de uma instância MySQL, conforme descrito acima onde esta função está localizada em common/mysql_helper. js:
statusVar = readStatusVariable(<host>, <statusvariablename>);
Podemos usar esta função em nosso orientador para buscar as tabelas Created_tmp_disk_tables e 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’);
E agora podemos calcular a proporção das tabelas de disco temporárias:
var tmp_disk_table_ratio = tmp_disk_tables / (tmp_tables + tmp_disk_tables) * 100;
E alerta se essa proporção for maior que o limite que definimos no início:
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;
}
}
É importante atribuir o Advice à variável msg aqui, pois isso será adicionado posteriormente ao objeto de aconselhamento com a função setAdvice(). O script completo para completar:
#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;
}
Agora você pode brincar com o limite de 20, tentar reduzi-lo para 1 ou 2, por exemplo, e então você provavelmente verá como esse conselheiro realmente lhe dará conselhos sobre o assunto.
Como você pode ver, com um script simples, você pode comparar duas variáveis entre si e relatar/aconselhar com base em seu resultado. Mas isso é tudo? Ainda há algumas coisas que podemos melhorar!
Melhorias no meu primeiro orientador
A primeira coisa que podemos melhorar é que esse conselheiro não faz muito sentido. O que a métrica realmente reflete é o número total de tabelas temporárias no disco desde o último FLUSH STATUS ou inicialização do MySQL. O que não diz é a que taxa ele realmente cria tabelas temporárias no disco. Assim, podemos converter o Created_tmp_disk_tables em uma taxa usando o uptime do host:
var tmp_disk_table_rate = tmp_disk_tables / uptime;
Isso deve nos dar o número de tabelas temporárias por segundo e combinado com o tmp_disk_table_ratio, isso nos dará uma visão mais precisa das coisas. Novamente, uma vez que atingimos o limite de duas tabelas temporárias por segundo, não queremos enviar imediatamente um alerta/conselho.
Outra coisa que podemos melhorar é não usar a função readStatusVariable(
Nesse caso, podemos otimizar isso recuperando as variáveis de status em um mapa usando a função host.sqlInfo() e recuperando tudo de uma vez como um mapa. Esta função contém as informações mais importantes do host, mas não contém todas. Por exemplo, a variável uptime que precisamos para a taxa não está disponível no mapa host.sqlInfo() e deve ser recuperada com a função readStatusVariable(
É assim que nosso orientador ficará agora, com as alterações/adições marcadas em negrito:
#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;
}
Agendando meu primeiro orientador
Depois de salvar este novo orientador, compilá-lo e executá-lo, agora podemos agendar esse orientador. Como não temos uma carga de trabalho excessiva, provavelmente executaremos esse consultor uma vez por dia.
O modo de agendamento básico é semelhante ao Cron que tem cada minuto, 5 minutos, hora, dia, mês predefinidos e é exatamente isso que precisamos e é muito fácil gerenciar o agendamento. Alterar isso para avançado desbloqueará os outros campos de entrada acinzentados. Esses campos de entrada funcionam exatamente da mesma forma que um crontab, para que você possa agendar para um determinado dia, dia do mês ou até mesmo defini-lo para dias da semana.
Seguindo este blog, criaremos um verificador para SELinux ou verificações de segurança para Spectre e Meltdown se os nós forem afetados. Fique atento!