Atualizando o MySQL (Percona Server) de 5,7 para 8,0



O progresso não pára, então as razões para atualizar para as versões mais recentes do MySQL estão se tornando cada vez mais significativas. Há pouco tempo, em um de nossos projetos, era hora de atualizar os aconchegantes clusters do Percona Server 5.7 para a versão 8. Tudo isso aconteceu na plataforma Ubuntu Linux 16.04. Como executar uma operação semelhante com tempo de inatividade mínimo e quais problemas encontramos durante a atualização - leia este artigo.

Treinamento


Qualquer atualização do servidor de banco de dados provavelmente está conectada à migração do banco de dados: alterações nos requisitos para limites de recursos do sistema e correção das configurações do banco de dados, que devem ser eliminadas das diretivas desatualizadas.

Antes de atualizar, iremos definitivamente para a documentação oficial:


E faça um plano de ação:

  1. Corrija os arquivos de configuração removendo diretivas obsoletas.
  2. Verifique a compatibilidade com os utilitários.
  3. Atualize os bancos de dados escravos instalando o pacote percona-server-server.
  4. Atualize o assistente colocando o mesmo pacote.

Analisaremos cada item do plano e veremos o que pode dar errado.

IMPORTANTE! O procedimento de atualização de cluster do MySQL baseado em Galera possui suas próprias sutilezas que não são descritas no artigo. Você não deve usar esta instrução neste caso.

Parte 1: Verificando configurações


Na versão 8, o MySQL foi removido query_cache. De fato, foi declarado obsoleto na versão 5.7, mas agora foi completamente excluído . Portanto, é necessário remover as diretivas relacionadas. E para consultas em cache, agora você pode usar ferramentas externas - por exemplo, ProxySQL .

Também foram encontradas diretivas profissionais desatualizadas na configuração innodb_file_format. Se no MySQL 5.7 foi possível selecionar o formato InnoDB, a 8ª versão já funciona apenas com o formato Barracuda .

Nosso resultado é a remoção das seguintes diretrizes:

  • query_cache_type, query_cache_limitE query_cache_size;
  • innodb_file_formate innodb_file_format_max.

Para verificação, usaremos a imagem do Docker do Percona Server. Colocaremos a configuração do servidor no diretório mysql_config_teste, em seguida, criaremos os diretórios para dados e logs. Exemplo de teste de configuração do servidor percona:

mkdir -p {mysql_config_test,mysql_data,mysql_logs}
cp -r /etc/mysql/conf.d/* mysql_config_test/
docker run  --name some-percona -v $(pwd)/mysql_config_test:/etc/my.cnf.d/  -v $(pwd)/mysql_data/:/var/lib/mysql/ -v $(pwd)/mysql_logs/:/var/log/mysql/ -e MYSQL_ROOT_PASSWORD=${MYSQL_PASSWORD} -d percona:8-centos

Resultado: nos logs do Docker ou no diretório com os logs (dependendo das configurações), um arquivo será exibido no qual as diretivas do problema serão descritas.

Aqui está o que tivemos:

2020-04-03T12:44:19.670831Z 0 [Warning] [MY-011068] [Server] The syntax 'expire-logs-days' is deprecated and will be removed in a future release. Please use binlog_expire_logs_seconds instead.
2020-04-03T12:44:19.671678Z 0 [Warning] [MY-013242] [Server] --character-set-server: 'utf8' is currently an alias for the character set UTF8MB3, but will be an alias for UTF8MB4 in a future release. Please consider using UTF8MB4 in order to be unambiguous.
2020-04-03T12:44:19.671682Z 0 [Warning] [MY-013244] [Server] --collation-server: 'utf8_general_ci' is a collation of the deprecated character set UTF8MB3. Please consider using UTF8MB4 with an appropriate collation instead.

Assim, ainda precisávamos lidar com codificações e substituir a diretiva obsoleta expire-logs-days.

Parte 2: Verificando instalações em execução


Existem 2 utilitários na documentação da atualização para verificar a compatibilidade do banco de dados. Seu uso ajuda o administrador a verificar a compatibilidade da estrutura de dados existente.

Vamos começar com o utilitário mysqlcheck clássico. Basta executar:

mysqlcheck -u root -p --all-databases --check-upgrade

Se nenhum problema for detectado, o utilitário sairá com o código 0:



Além disso, o utilitário mysql-shell está disponível nas versões modernas do MySQL (no caso do Percona, este é um pacote percona-mysql-shell). É um substituto para o cliente mysql clássico e combina as funções do cliente, o editor SQL e as ferramentas de administração do MySQL. Para verificar o servidor antes da atualização, você pode executar os seguintes comandos através dele:

mysqlsh -- util check-for-server-upgrade { --user=root --host=1.1.1.1 --port=3306 } --config-path=/etc/mysql/my.cnf

E aqui estão os comentários que recebemos:



Em geral, nada crítico - apenas avisos sobre codificações (veja abaixo) . O resultado geral da implementação:



decidimos que a atualização deveria ocorrer sem problemas.

Uma observação sobre os avisos acima que indicam problemas de codificação. O fato é que o UTF-8 no MySQL até recentemente não era um UTF-8 "real" , já que ele armazenava apenas 3 bytes em vez de 4. No MySQL 8, eles finalmente decidiram corrigi-lo : o alias utf8em breve levará à codificação utf8mb4e os antigos as colunas nas tabelas se tornarão utf8mb3. No futuro, a codificação utf8mb3será excluída, mas não nesta versão. Portanto, decidimos corrigir as codificações já em uma instalação funcional do DBMS, após atualizá-lo.

Parte 3: Atualizações do servidor


O que pode dar errado quando existe um plano tão chique? ... Bem ciente de que as nuances sempre acontecem, realizamos o primeiro experimento no cluster de desenvolvimento MySQL.

Como já mencionado, a documentação oficial destaca a questão da atualização dos servidores MySQL com réplicas. A conclusão é que, a princípio, vale a pena atualizar todas as réplicas (escravos), pois o MySQL 8 pode replicar a partir do assistente da versão 5.7. Alguma dificuldade reside no fato de que usamos o modo mestre <-> mestre quando o mestre remoto está no modo somente leitura . Na verdade, o tráfego de combate entra em um datacenter e o segundo é em backup.

A topologia é a seguinte: A



atualização deve começar com réplicas dc 2 da réplica do mysql, mysql master dc 2 e mysql replica dc 1, e terminando com o servidor mysql master dc 1. Para maior confiabilidade, paramos as máquinas virtuais, fizemos instantâneos e paramos a replicação com o comando imediatamente antes da atualização STOP SLAVE. O restante da atualização fica assim:

  1. Cada reinício réplica, adicionando a opção de configuração 3: skip-networking, skip-slave-start, skip-log-bin. O fato é que a atualização do banco de dados gera logs binários com a atualização de tabelas do sistema. Essas diretivas garantem que não haverá alterações nos dados do aplicativo no banco de dados e as informações sobre a atualização de tabelas do sistema não serão inseridas nos logs binários. Isso evitará problemas ao retomar a replicação.
  2. Instale o pacote percona-server-server. É importante observar que no MySQL 8, você não precisa executar o comando mysqlupgradeapós atualizar o servidor.
  3. Após um início bem-sucedido, reinicie o servidor novamente - já sem os parâmetros que foram adicionados no primeiro parágrafo.
  4. Garantimos que a replicação funcione com êxito: verificamos SHOW SLAVE STATUSe atualizamos as tabelas com contadores no banco de dados do aplicativo.

Tudo isso parece bem simples: a atualização do desenvolvedor foi bem-sucedida. Ok, você pode planejar com segurança um upgrade noturno para produção.

Não havia tristeza - atualizamos prod


No entanto, portar a experiência bem-sucedida do desenvolvedor na produção não foi sem surpresas.

Felizmente, o próprio processo de atualização começa com réplicas, portanto, tendo encontrado dificuldades, paramos o trabalho e restauramos a réplica a partir do instantâneo. O estudo do problema foi remarcado na manhã seguinte. As seguintes entradas apareceram nos logs:

2020-01-14T21:43:21.500563Z 2 [ERROR] [MY-012069] [InnoDB] table: t1 has 19 columns but InnoDB dictionary has 20 columns
2020-01-14T21:43:21.500722Z 2 [ERROR] [MY-010767] [Server] Error in fixing SE data for db1.t1
2020-01-14T21:43:24.208365Z 0 [ERROR] [MY-010022] [Server] Failed to Populate DD tables.
2020-01-14T21:43:24.208658Z 0 [ERROR] [MY-010119] [Server] Aborting

Um estudo dos arquivos de várias listas de discussão no Google levou à compreensão de que esse problema surge devido a um erro no MySQL . Embora seja um bug mysqlchecke até utilitário mysqlsh.

Acontece que o MySQL mudou a maneira como os dados são apresentados para os campos decimais (int, tinyint, etc.), portanto, outra maneira de armazená-los é usada dentro do mysql-server. Se seu banco de dados estava originalmente na versão 5.5 ou 5.1 e, em seguida, você atualizou para 5.7, pode ser necessário produzir OPTIMIZEalgumas tabelas. Em seguida, o MySQL atualizará os arquivos de dados, transferindo-os para o formato de armazenamento atual.

Você também pode verificar isso com o utilitário mysqlfrm:

mysqlfrm --diagnostic -vv /var/lib/mysql/db/table.frm
...
 'field_length': 8,
  'field_type': 246, #  
  'field_type_name': 'decimal',
  'flags': 3,
  'flags_extra': 67,
  'interval_nr': 0,
 'name': 'you_deciaml_column',
...

Se field_typevocê tiver 0, o tipo antigo será usado na tabela - isso deve ser feito OPTIMIZE. No entanto, se o valor for 246, você já possui um novo tipo. Mais informações sobre os tipos podem ser encontradas no código .

Além disso, esse bug considera o segundo motivo possível que nos ignorou - a falta de tabelas do InnoDB na tabela do sistema INNODB_SYS_TABLESPACES, se elas foram criadas na versão 5.1. Para evitar problemas durante a atualização, você pode usar o script SQL anexado .

Por que não tivemos esses problemas no desenvolvimento? A base é copiada periodicamente para a produção - assim, as tabelas são recriadas .

Infelizmente, em um banco de dados grande realmente funcionando, ele não funcionará apenas para obter e executar o onipresente OPTIMIZE. O Percona-toolkit ajudará aqui: o utilitário pt-online-schema-change é excelente para a operação OPTIMIZE online.

O plano atualizado foi o seguinte:

  1. Otimize todas as tabelas.
  2. Execute uma atualização do banco de dados.

Para verificar e ao mesmo tempo descobrir o horário da atualização, desabilitamos uma das réplicas e, para todas as tabelas, executamos o seguinte comando:

pt-online-schema-change --critical-load Threads_running=150 --alter "ENGINE=InnoDB" --execute --chunk-size 100 --quiet --alter-foreign-keys-method auto h=127.0.0.1,u=root,p=${MYSQL_PASSWORD},D=db1,t=t1

As tabelas são atualizadas sem bloqueios longos devido ao fato de o utilitário criar uma nova tabela temporária na qual copia os dados da tabela principal. No momento em que ambas as tabelas são idênticas, a tabela original é bloqueada e substituída por uma nova. No nosso caso, uma execução de teste mostrou que a atualização de todas as tabelas levaria cerca de um dia, mas a cópia dos dados causou muita carga nos discos.

Para evitar isso, na produção, adicionamos um argumento --sleepcom um valor 10 ao comando - este parâmetro controla a duração da espera após a transferência de um pacote de dados para uma nova tabela. Dessa forma, você pode reduzir a carga se um aplicativo realmente em execução exigir tempo de resposta.

Após a otimização, a atualização foi bem-sucedida.

... mas não completamente!


Meia hora após a atualização, o cliente encontrou um problema. A base funcionou muito estranha: periodicamente, as quedas de conexão começaram . Aqui está o que parecia no monitoramento:



O gráfico dente de serra é visível na captura de tela, devido ao fato de que parte dos threads do servidor MySQL periodicamente caiu com um erro. Apareceram erros no aplicativo:

[PDOException] SQLSTATE[HY000] [2002] Connection refused

Uma inspeção rápida dos logs revelou que o daemon mysqld não pôde obter os recursos necessários do sistema operacional. Ao lidar com erros, encontramos nos arquivos de políticas aparentes “órfãos” do sistema :

# dpkg -S /etc/apparmor.d/cache/usr.sbin.mysqld
dpkg-query: no path found matching pattern /etc/apparmor.d/cache/usr.sbin.mysqld
# dpkg -S /etc/apparmor.d/local/usr.sbin.mysqld
dpkg-query: no path found matching pattern /etc/apparmor.d/local/usr.sbin.mysqld
# dpkg -S /etc/apparmor.d/usr.sbin.mysqld
mysql-server-5.7: /etc/apparmor.d/usr.sbin.mysqld
# dpkg -l mysql-server-5.7
rc  mysql-server-5.7 5.7.23-0ubuntu0.16.04.1      amd64

Esses arquivos foram formados durante a atualização para o MySQL 5.7 há alguns anos e pertencem ao pacote remoto. Excluir arquivos e reiniciar o serviço apparmor resolveu o problema:

systemctl stop apparmor
rm /etc/apparmor.d/cache/usr.sbin.mysqld
rm /etc/apparmor.d/local/usr.sbin.mysqld
rm /etc/apparmor.d/usr.sbin.mysqld
systemctl start apparmor

Finalmente


Qualquer operação, mesmo a mais simples, pode levar a problemas inesperados. E mesmo ter um plano bem elaborado nem sempre garante o resultado esperado. Agora, em qualquer plano de atualização, nossa equipe também inclui a limpeza obrigatória de arquivos extras que podem aparecer como resultado de ações recentes.

E com este trabalho gráfico não tão profissional, gostaria de agradecer à Percona por seus ótimos produtos!



PS


Leia também no nosso blog:


All Articles