Desde o lançamento da versão 5.5 do servidor de bancos de dados MySQL que eu venho verificando muitos problemas relacionados com a variável de resolução de nomes, skip-name-resolve. Para quem ainda não sabe ou está iniciando com o MySQL, toda vez que o servidor de bancos de dados recebe uma consulta, como aquela vinda do mysql client, o host de onde vem essa conexão é parte da verificação de autenticação do usuário. Além do nome de usuário e a senha, o usuário deverá ter permissão de originar uma conexão de um determinado host, assim configurado através da criação explícita do usuário através do comando CREATE USER ou, dependendo das configuração de SQL_MODE, usuários podem ser criados diretamente através do comando GRANT, este que permite que você também dê as devidas permissões e configure host e senha para o usuário.
Voltando então ao momento da conexão, considerando que o host é também verificado, na versão 5.5 uma nova feature foi apresentada, sendo adicionada para que hosts passassem a permanecer em memória cache. Não só isso, como o MySQL verifica a existência do host vinculado a uma conexão através da coluna host da tabela mysql.user; quando um host não existe, o MySQL tenta resolver o host através de um DNS Lookup. Primeiro ele resolve o IP em um nome de host e assim ele continua utilizando o IP, mas guarda no cache o nome do host. Na resolução do IP em nome, existe uma verificação adicional: verificar se o IP que chegou no MySQL é o mesmo IP configurado por trás do nome da máquina configurado no DNS. Parece muito bom, mas, se na sua empresa você não utiliza um DNS ou só tem endereços de IP na coluna hosts da tabela mysql.user, talvez não seja necessário gerar um overhead para o servidor, e também um pouco de dor de cabeça, pois, dependendo do tipo de monitoramento que você tem internamente, uma simples linha de um IP adicionada ao error log pode disparar um chamado desnecessário no meio da noite – olha, isso acontece!!
Vantagens e desvantagens, se é necessário que um usuário se conecte do endereço BOX01, no qual um dos requisitos é criar um usuário “foo”@”box01”, tudo bem, vale ter a configuração. Um outro ponto bastante interessante é configurar o MySQL para que, caso um determinado usuário tente se conectar x vezes e não consega se logar no MySQL por conta de digitação errada ou mesmo esquecimento da senha, ele pode ser bloqueado (ninguém sabe quando é uma pessoa ou um robô tentando acesso). Isso poderá ser realizado através da variável max_connect_errors, que adicionada ao arquivo de configuração com um valor 3, por exemplo, dará 3 oportunidades de tentativa de login. Para desbloquear os hosts bloqueados, FLUSH HOSTS.
Com a opção habilitada, o MySQL, além de fazer essa verificação de IP (se ele é ele mesmo!!), utilizará um mecanismo de memória para adicionar ao cache os hosts logo no primeiro acesso válido, sendo estes hosts mantidos em memória até o espaço para essa lista de hosts se esgotar. Nesse momento, o algoritmo LRU (Least Recently Used) é acionado, e o host menos acessado é despejado da memória (processo conhecido como eviction). Todo esse processo também envolve estruturas como mutexes, threads e locks.
Agora, caso os usuários que utilizam o MySQL possam ser criados considerando o IP de onde a conexão é gerada ou a string localhost, podemos desabilitar a resolução de nomes com a variável –skip-name-resolve, adicionada à sessão [mysqld] do arquivo de configuração do MySQL e reiniciar o mysqld.
[mysqld]
max_connect_errors=3 # três tentativas de autenticação
#skip-name-resolve # desabilita o DNS Lookup, linha comentada
Interessante ressaltar que caso seja encontrado na coluna host das tabelas privilégio (user, db, host, tables_priv, columns_priv e procs_priv) um valor diferente de um IP ou a string localhost, não é aconselhável que a resolução de nomes seja habilitada. Caso contrário, se existir somente IPs e a string localhost, –skip-name-resolve poderá ser desabilitado. Use a consulta abaixo para verificar a existência de possíveis valores na coluna host nas tabelas de privilégios do MySQL (também conhecidas como grant tables):
mysql> select a.host as `mysql.user`, b.host as `mysql.db`, c.host as `mysql.tables_priv`, d.host as `mysql.columns_pric` FROM mysql.user as a left join mysql.db as b on a.user=b.user left join mysql.tables_priv as c on a.user=c.user left join mysql.columns_priv as d on a.user=d.user;
+-----------------------+----------+-------------------+--------------------+
| mysql.user | mysql.db | mysql.tables_priv | mysql.columns_pric |
+-----------------------+----------+-------------------+--------------------+
| localhost | % | NULL | NULL |
| localhost.localdomain | % | NULL | NULL |
| localhost | % | NULL | NULL |
| localhost.localdomain | % | NULL | NULL |
| 127.0.0.1 | NULL | NULL | NULL |
| ::1 | NULL | NULL | NULL |
| localhost | NULL | NULL | NULL |
| localhost | NULL | NULL | NULL |
| localhost.localdomain | NULL | NULL | NULL |
+-----------------------+----------+-------------------+--------------------+
9 rows in set (0.01 sec)
No resultado da consulta acima, perceba que há muitos valores NULL em tabelas mais à direita. Esse comportamento denota que não há usuários com permissões de acesso restrito somente a bancos de dados, a tabelas de bancos de dados ou apenas a colunas de determinadas tabelas de bancos de dados específicos.
Quando o recurso está habilitado e o MySQL não consegue fazer o lookup reverso de conexões, um evento de Warning é adicionado ao log de erro – verifique a variável error_log para saber onde o arquivo de log foi criado – onde é descrito que não foi possível resolver determinado IP/DNS de uma conexão. O erro que será adicionado ao arquivo de log de erro do MySQL é algo como a linha abaixo:
[Warning] IP address '#.#.#.#' could not be resolved: Name or service not known
Interessante saber exatamente o que cada evento adicionado ao log de erros do MySQL representa para que seu sistema continue rodando sem problemas de downtime e ter a possibilidade de ser mais proativo com os possíveis problemas que o MySQL e os seus bancos de dados possam apresentar no futuro.
Este foi um artigo curto, mais teórico que prático, mas a boa notícia é que vou tentar voltar em breve!!
Happy MySQL’ing!!