Atualizando MySQL (Servidor Percona) de 5.7 para 8.0

Atualizando MySQL (Servidor Percona) de 5.7 para 8.0

O progresso não pára, então os motivos para atualizar para as versões mais recentes do MySQL estão se tornando cada vez mais convincentes. Não faz muito tempo, em um de nossos projetos, chegou a hora de atualizar os aconchegantes clusters Percona Server 5.7 para a versão 8. Tudo isso aconteceu na plataforma Ubuntu Linux 16.04. Como realizar tal operação com tempo de inatividade mínimo e quais problemas encontramos durante a atualização - leia neste artigo.

Treinamento

Qualquer atualização do servidor de banco de dados provavelmente está associada à reconfiguração do banco de dados: mudanças nos requisitos de limites de recursos do sistema e correção das configurações do banco de dados que precisam ser limpas de diretivas desatualizadas.

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

E vamos traçar um plano de ação:

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

Vamos analisar cada ponto do plano e ver o que pode dar errado.

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

Parte 1: Verificando configurações

MySQL foi removido na versão 8 query_cache. Na verdade ele estava declarado obsoleto de volta na versão 5.7, mas agora completamente excluído. Por conseguinte, é necessário suprimir as directivas associadas. E para armazenar solicitações em cache agora você pode usar ferramentas externas - por exemplo, ProxySQL.

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

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

  • query_cache_type, query_cache_limit и query_cache_size;
  • innodb_file_format и innodb_file_format_max.

Para verificar, usaremos a imagem Docker do Percona Server. Colocaremos a configuração do servidor no diretório mysql_config_test, e ao lado criaremos 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

Resumindo: nos logs do Docker ou no diretório com os logs - dependendo de suas configurações - aparecerá um arquivo no qual as diretivas problemáticas 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 descobrir as codificações e substituir a diretiva desatualizada expire-logs-days.

Parte 2: Verificando instalações em funcionamento

A documentação de atualização contém 2 utilitários 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 clássico mysqlcheck. Basta executar:

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

Se nenhum problema for encontrado, o utilitário será encerrado com o código 0:

Atualizando MySQL (Servidor Percona) de 5.7 para 8.0

Além disso, um utilitário está disponível nas versões modernas do MySQL shell mysql (no caso do Percona este é o pacote percona-mysql-shell). É um substituto para o cliente MySQL clássico e combina as funções de um cliente, um editor de código SQL e ferramentas de administração MySQL. Para verificar o servidor antes de atualizar, 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

Aqui estão os comentários que recebemos:

Atualizando MySQL (Servidor Percona) de 5.7 para 8.0

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

Atualizando MySQL (Servidor Percona) de 5.7 para 8.0

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

Uma observação sobre os avisos acima indicando problemas com codificações. O fato é que UTF-8 no MySQL até recentemente não era "verdadeiro" UTF-8, já que armazenou apenas 3 bytes em vez de 4. No MySQL 8 isso é finalmente decidi consertar: alias utf8 em breve levará à codificação utf8mb4, e as colunas antigas nas tabelas se tornarão utf8mb3. Codificação adicional utf8mb3 será removido, mas não nesta versão. Portanto, decidimos corrigir as codificações já presentes na instalação do SGBD em execução, após atualizá-lo.

Parte 3: Atualizações do Servidor

O que poderia dar errado quando existe um plano tão inteligente? Compreendendo muito bem que nuances sempre acontecem, conduzimos o primeiro experimento em um cluster de desenvolvimento MySQL.

Como já mencionado, documentação oficial cobre a questão da atualização de servidores MySQL com réplicas. O resultado final é que você deve primeiro atualizar todas as réplicas (escravos), já que o MySQL 8 pode replicar a partir de uma versão master 5.7. Alguma dificuldade reside no fato de usarmos o modo mestre <-> mestre, quando o mestre remoto está no modo somente leitura. Ou seja, na verdade, o tráfego de combate vai para um data center e o segundo é de backup.

A topologia fica assim:

Atualizando MySQL (Servidor Percona) de 5.7 para 8.0

A atualização deve começar com réplicas réplica mysql dc 2, mestre mysql dc 2 и mysql replica dc 1e terminamos com o servidor mysql master dc 1. Para ser mais confiável, paramos as máquinas virtuais, tiramos snapshots delas e imediatamente antes da atualização paramos a replicação com o comando STOP SLAVE. O resto da atualização fica assim:

  1. Reiniciamos cada réplica adicionando 3 opções às configurações: skip-networking, skip-slave-start, skip-log-bin. O fato é que a atualização do banco de dados gera logs binários com atualizações nas tabelas do sistema. Estas diretivas garantem que não haverá alterações nos dados da aplicação no banco de dados e que informações sobre atualização de tabelas do sistema não serão incluídas nos logs binários. Isso evitará problemas ao retomar a replicação.
  2. Instalando o pacote percona-server-server. É importante notar que no MySQL versão 8 não você precisa executar o comando mysqlupgrade após a atualização do servidor.
  3. Após um início bem-sucedido, reiniciamos o servidor novamente - sem os parâmetros que foram adicionados no primeiro parágrafo.
  4. Garantimos que a replicação funcione com sucesso: verifique SHOW SLAVE STATUS e veja se as tabelas com contadores no banco de dados da aplicação estão atualizadas.

Tudo parece bastante simples: a atualização do desenvolvedor foi bem-sucedida. Ok, você pode agendar com segurança uma atualização noturna para produção.

Não houve tristeza - atualizamos o produto

No entanto, a transferência de experiência de desenvolvimento bem-sucedida para a produção não ocorreu sem surpresas.

Felizmente, o próprio processo de atualização começa com réplicas; portanto, quando encontramos dificuldades, interrompemos o trabalho e restauramos a réplica do instantâneo. A investigação dos problemas foi adiada para a manhã seguinte. Os logs continham as seguintes entradas:

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

A pesquisa nos arquivos de diversas mailing lists do Google levou ao entendimento de que esse problema ocorre devido a Bug do MySQL. Embora seja mais provável que seja um bug de utilitário mysqlcheck и mysqlsh.

Acontece que o MySQL mudou a forma como eles representam os dados para campos decimais (int, tinyint, etc.), então o mysql-server usa uma maneira diferente de armazená-los. Se o seu banco de dados inicialmente estava na versão 5.5 ou 5.1 e depois atualizou para 5.7, talvez seja necessário OPTIMIZE para algumas mesas. Então 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_type Se for igual a 0, então o tipo antigo é usado na tabela - você precisa realizar OPTIMIZE. Porém, se o valor for 246, você já possui um novo tipo. Mais informações sobre os tipos podem ser encontradas em code.

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

Por que não tivemos esses problemas no desenvolvimento? O banco de dados é copiado periodicamente da produção - assim, tabelas são recriadas.

Infelizmente, em um grande banco de dados realmente funcional, você não será capaz de simplesmente pegar e executar um OPTIMIZE. percona-toolkit ajudará aqui: o utilitário pt-online-schema-change é excelente para a operação OPTIMIZE online.

O plano atualizado ficou assim:

  1. Otimize todas as tabelas.
  2. Atualize os bancos de dados.

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

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 demorados porque o utilitário cria 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 pela nova. No nosso caso, um teste mostrou que levaria cerca de um dia para atualizar todas as tabelas, mas a cópia dos dados causou muita carga nos discos.

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

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

... mas não completamente!

Meia hora após a atualização, o cliente apresentou um problema. O banco de dados funcionou de forma muito estranha: periodicamente eles iniciavam redefinições de conexão. Isto é o que parecia no monitoramento:

Atualizando MySQL (Servidor Percona) de 5.7 para 8.0

A captura de tela mostra um gráfico dente de serra devido ao fato de que alguns threads do servidor MySQL travavam periodicamente com um erro. Erros apareceram no aplicativo:

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

Uma rápida inspeção dos logs revelou que o daemon mysqld não conseguiu obter os recursos necessários do sistema operacional. Ao resolver os erros, descobrimos no sistema arquivos de política de apparmor "órfãos":

# 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 criados durante a atualização para o MySQL 5.7 há alguns anos e pertencem a um pacote removido. Excluir os 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

Em conclusão

Qualquer operação, mesmo a mais simples, pode levar a problemas inesperados. E mesmo ter um plano bem pensado nem sempre garante o resultado esperado. Agora, qualquer plano de atualização que nossa equipe tenha também inclui a limpeza obrigatória de arquivos desnecessários que possam ter surgido como resultado de ações recentes.

E com essa criatividade gráfica pouco profissional, gostaria de agradecer imensamente à Percona pelos excelentes produtos!

Atualizando MySQL (Servidor Percona) de 5.7 para 8.0

PS

Leia também em nosso blog:

Fonte: habr.com

Adicionar um comentário