
O progresso não para, por isso, as razões para atualizar para versões atuais do MySQL se tornam cada vez mais significativas. Recentemente, em um de nossos projetos, chegou a hora de atualizar os confortáveis clusters do Percona Server 5.7 para a versão 8. Isso aconteceu na plataforma Ubuntu Linux 16.04. Como realizar tal operação com o mínimo de inatividade e quais problemas encontramos durante a atualização — leia neste artigo.
Preparação
Qualquer atualização de servidor de banco de dados provavelmente está relacionada à reconfiguração do banco: mudanças nas exigências de limites dos recursos do sistema e na correção das configurações do banco, que precisam ser limpas de diretivas obsoletas.
Antes da atualização, devemos consultar a documentação oficial:
- ;
- ;
- ;
- .
E elaborar um plano de ação:
- Corrigir os arquivos de configuração, removendo as diretivas obsoletas.
- Verificar a compatibilidade com ferramentas.
- Atualizar as bases de dados slave, instalando o pacote
percona-server-server. - Atualizar o mestre, instalando o mesmo pacote.
Vamos revisar cada item do plano e ver o que pode dar errado.
IMPORTANTE! O procedimento de atualização do cluster MySQL baseado em Galera tem suas particularidades, que não estão descritas neste artigo. Não utilize este guia nesse caso.
Parte 1: Verificação das configurações
Na versão 8 do MySQL, foi removido query_cache. Na verdade, ele foi já na versão 5.7, mas agora foi . Portanto, é necessário remover as diretivas relacionadas. Para o cache de consultas, agora podem ser utilizados ferramentas externas — por exemplo, .
Além disso, no arquivo de configuração foram encontradas diretivas obsoletas sobre innodb_file_format. Se na versão 5.7 do MySQL havia a possibilidade de escolha do formato InnoDB, a versão 8 já funciona .
Nosso resultado — remoção das seguintes diretivas:
-
query_cache_type,query_cache_limitequery_cache_size; -
innodb_file_formateinnodb_file_format_max.
Para a verificação, utilizaremos a imagem Docker do Percona Server. O arquivo de configuração do servidor será colocado no diretório mysql_config_test, e ao lado, criaremos diretórios para dados e logs. Exemplo de teste da configuração do percona-server:
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-centosConclusão: haverá um arquivo nos logs do Docker ou no diretório de logs — dependendo das suas configurações — que descreverá as diretivas problemáticas.
Isso é o que encontramos:
2020-04-03T12:44:19.670831Z 0 [Warning] [MY-011068] [Server] A sintaxe 'expire-logs-days' está obsoleta e será removida em uma versão futura. Por favor, use binlog_expire_logs_seconds em vez disso.
2020-04-03T12:44:19.671678Z 0 [Warning] [MY-013242] [Server] --character-set-server: 'utf8' é atualmente um alias para o conjunto de caracteres UTF8MB3, mas será um alias para UTF8MB4 em uma versão futura. Por favor, considere usar UTF8MB4 para ser inequívoco.
2020-04-03T12:44:19.671682Z 0 [Warning] [MY-013244] [Server] --collation-server: 'utf8_general_ci' é uma colação do conjunto de caracteres obsoleto UTF8MB3. Por favor, considere usar UTF8MB4 com uma colação apropriada em vez disso. Assim, precisamos também resolver as codificações e substituir a diretiva obsoleta expire-logs-days.
Parte 2: Verificando instalações em funcionamento
Na documentação de atualização, existem 2 utilitários para verificar a compatibilidade do banco de dados. O uso deles ajuda o administrador a verificar a compatibilidade da estrutura de dados existente.
Vamos começar com a utilidade clássica mysqlcheck. Basta executá-la:
mysqlcheck -u root -p --all-databases --check-upgradeSe nenhum problema for encontrado, a utilidade terminará com o código 0:

Além disso, nas versões modernas do MySQL, está disponível a utilidade (no caso do Percona, é o pacote percona-mysql-shell). Ela substitui o cliente clássico mysql e combina funções de cliente, editor de código SQL e ferramentas de administração do MySQL. Para verificar o servidor antes da atualização, você pode executar o seguinte comando através dela:
mysqlsh -- util check-for-server-upgrade { --user=root --host=1.1.1.1 --port=3306 } --config-path=\/etc\/mysql\/my.cnfE aqui estão as observações que recebemos:

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

Decidimos que a atualização deve ocorrer sem problemas.
Observação sobre os avisos acima, que indicam problemas com codificações. O fato é que o UTF-8 no MySQL, até recentemente, pois armazenava apenas 3 bytes em vez de 4. No MySQL 8, finalmente o alias utf8 em breve levará à codificação utf8mb4,e as antigas colunas nas tabelas se tornarão utf8mb3.No futuro, a codificação utf8mb3. será removida, mas não nesta versão. Portanto, decidimos corrigir as codificações já na instalação do SGBD em funcionamento, após sua atualização.
Parte 3: Atualizando servidores
O que pode dar errado quando há um plano tão incrível?.. Compreendendo bem que detalhes sempre acontecem, realizamos o primeiro experimento no cluster de desenvolvimento MySQL.
Como já mencionado, aborda a questão da atualização de servidores MySQL com réplicas. A essência é que primeiro deve-se atualizar todas as réplicas (slave), pois o MySQL 8 consegue replicar a partir de um master da versão 5.7. Uma certa complexidade se deve ao fato de que estamos utilizando o modo master master, onde o master remoto está em modo read-only. Ou seja, o tráfego de produção flui para um data center, enquanto o segundo é o de backup.
A topologia é a seguinte:

A atualização deve começar pelas réplicas mysql replica dc 2, mysql master dc 2 e mysql replica dc 1, e terminar no servidor mysql master dc 1. Para maior confiabilidade, desligamos as máquinas virtuais, fizemos snapshots e, pouco antes da atualização, interrompemos a replicação com o comando STOP SLAVE. De resto, a atualização parece assim:
- Reiniciamos cada réplica, adicionando nas configurações 3 opções:
skip-networking,skip-slave-start,skip-log-bin. O fato é que a atualização do banco gera logs binários com a atualização das tabelas de sistema. Essas diretrizes garantem que não haverá alteração dos dados da aplicação no banco e que a informação sobre a atualização das tabelas de sistema não será registrada nos logs binários. Isso evitará problemas na retomada da replicação. - Instalamos o pacote
percona-server-server. É importante notar que na versão MySQL 8 não é necessário executar o comandomysqlupgradeapós a atualização do servidor. - Após o início bem-sucedido, reinicializamos o servidor novamente — já sem os parâmetros que foram adicionados no primeiro ponto.
- Verificamos se a replicação está operando com sucesso: checamos
SHOW SLAVE STATUSe observamos que as tabelas com os contadores no banco da aplicação estão sendo atualizadas.
Tudo isso parece bastante simples: a atualização do dev foi bem-sucedida. Ok, podemos planejar a atualização noturna para a produção.
Não houve tristeza — nós atualizamos o prod
No entanto, transferir a experiência bem-sucedida do dev para a produção não ocorreu sem surpresas.
Felizmente, o próprio processo de atualização começa com as réplicas, portanto, ao encontrar dificuldades, interrompemos os trabalhos e restauramos a réplica a partir do snapshot. A investigação dos problemas foi transferida para a manhã seguinte. Nos logs, encontramos as seguintes entradas:
2020-01-14T21:43:21.500563Z 2 [ERROR] [MY-012069] [InnoDB] A tabela: t1 tem 19 colunas, mas o dicionário do InnoDB tem 20 colunas
2020-01-14T21:43:21.500722Z 2 [ERROR] [MY-010767] [Server] Erro ao corrigir os dados SE para db1.t1
2020-01-14T21:43:24.208365Z 0 [ERROR] [MY-010022] [Server] Falha ao popular tabelas DD.
2020-01-14T21:43:24.208658Z 0 [ERROR] [MY-010119] [Server] Abortando A pesquisa nos arquivos de várias listas de distribuição no Google levou à compreensão de que este problema surge devido a . Embora, na verdade, seja até um bug das ferramentas mysqlcheck e mysqlsh.
Descobriu-se que no MySQL mudaram a forma de representação dos dados para campos decimais (int, tinyint etc.), portanto, dentro do mysql-server, utiliza-se uma forma diferente de armazenamento. Se o seu banco de dados originalmente era na versão 5.5 ou 5.1 e depois você atualizou para a 5.7, pode ser necessário realizar OPTIMIZE para algumas tabelas. Então, o MySQL atualizará os arquivos com os dados, convertendo-os para o formato de armazenamento atual.
Isso também pode ser verificado com a ferramenta mysqlfrm:
mysqlfrm --diagnostic -vv /var/lib/mysql/db/table.frm
...
'field_length': 8,
'field_type': 246, # formato do campo
'field_type_name': 'decimal',
'flags': 3,
'flags_extra': 67,
'interval_nr': 0,
'name': 'your_decimal_column',
... Se field_type for igual a 0, então na tabela está sendo utilizado o antigo tipo — é necessário executar OPTIMIZE. No entanto, se o valor for 246 — você já tem um novo tipo. Você pode conferir mais sobre os tipos em .
Além disso, neste INNODB_SYS_TABLESPACES , se essas tabelas foram criadas na versão 5.1. Para evitar problemas ao atualizar, você pode usaro script SQL anexo .
as tabelas são recriadas Infelizmente, em um banco de dados grande em produção, não é possível simplesmente realizar um.
. Aqui, o percona-toolkit ajuda: para a operação online OPTIMIZE, a ferramenta pt-online-schema-change é perfeitamente adequada. OPTIMIZEO plano atualizado ficou assim:
Realizar a otimização de todas as tabelas.
- Realizar a atualização dos bancos de dados.
- Para verificar isso e ao mesmo tempo descobrir o tempo de atualização, desligamos 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
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=t1A atualização das tabelas é realizada sem bloqueios prolongados, pois a ferramenta cria uma nova tabela temporária, na qual copia os dados da tabela principal. Assim que ambas as tabelas são idênticas, a tabela original é bloqueada e substituída pela nova. No nosso caso, o teste inicial mostrou que a atualização de todas as tabelas levaria cerca de um dia, mas a cópia de dados causou uma carga excessiva nos discos.
Para evitar isso, na produção, adicionamos à equipe o argumento --sleep com o valor 10 — esse parâmetro regula a duração da espera após a transferência de um lote de dados para a nova tabela. Isso pode reduzir a carga se o aplicativo em execução exigir um tempo de resposta ágil.
Após a execução da otimização, a atualização foi bem-sucedida.
… mas não completamente!
Já meia hora após a atualização, o cliente veio com um problema. O banco de dados estava funcionando de maneira estranha: periodicamente começaram a ocorrer resetes de conexões. Assim foi exibido no monitoramento:

No gráfico, é visível um padrão em forma de serra, relacionado ao fato de que algumas threads do servidor MySQL caíam periodicamente com erro. O aplicativo começou a apresentar erros:
[PDOException] SQLSTATE[HY000] [2002] Conexão recusadaUma rápida inspeção dos logs revelou que o daemon mysqld não conseguia obter os recursos necessários do sistema operacional. Investigando os erros, descobrimos no sistema arquivos de políticas do apparmor "orfã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 amd64Esses arquivos foram gerados durante a atualização para o MySQL 5.7 há alguns anos e pertencem a um pacote removido. A exclusão dos arquivos e o reinício do serviço apparmor resolveram 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 apparmorPara concluir
Qualquer operação, mesmo a mais simples, pode levar a problemas inesperados. E até mesmo ter um plano bem elaborado nem sempre garante o resultado esperado. Agora, qualquer plano de atualização de nossa equipe inclui também a limpeza obrigatória de arquivos desnecessários que possam ter surgido como resultado das ações anteriores.
E com essa arte gráfica pouco profissional, gostaria de agradecer imensamente à empresa Percona pelos seus excelentes produtos!

P.S.
Confira também em nosso blog:
- «»;
- «»;
- «»;
- «»;
- «».
Fonte: habr.com
