Percio Castelo.
EN Início
O guia mestre de migração legada: do efeito dominó à incompatibilidade de arquitetura
← Voltar para blog

O guia mestre de migração legada: do efeito dominó à incompatibilidade de arquitetura

07/06/2026 · 7 min · Infraestrutura · 524 visualizações

O guia mestre de migração legada: do efeito dominó à incompatibilidade de arquitetura#

Quem atua com infraestrutura corporativa sabe que migrar sistemas legados raramente é um fluxo previsível. Recentemente, gerenciei uma transição de alta complexidade: a migração de contas robustas de servidores obsoletos (MySQL 5.7) para ambientes modernos (MariaDB 10.11 / CloudLinux 9). O que se projetava como uma transferência de blocos tornou-se uma caçada analítica por bugs de compatibilidade.

Abaixo, desconstruo os grandes pilares de falha e os processos de depuração envolvidos nessa jornada.


1. ModSecurity e a colisão do SQL strict mode#

Durante a restauração do banco de dados no novo servidor MariaDB 10.11, os primeiros sintomas de rejeição surgiram no WAF (Web Application Firewall). O ModSecurity bloqueava requisições legítimas devido a erros estruturais gerados pelo comportamento do banco de dados.

A. O comportamento do modo estrito#

O MySQL 5.7.x a partir da versão 5.7.5 já traz NO_ZERO_DATE e NO_ZERO_IN_DATE no sql_mode default, mas instalações anteriores a 5.7.5 ou servidores com configurações permissivas customizadas permitiam a gravação de campos de data inválidos (ex: 0000-00-00 00:00:00) e aceitavam a truncagem silenciosa de strings. No MariaDB 10.11, o modo estrito (STRICT_TRANS_TABLES) vem ativo por padrão. Se o servidor de origem possuía sql_mode customizado permissivo, qualquer inserção incompatível gera um erro impeditivo do motor do banco, quebrando a transação PHP.

B. Diagnóstico e resolução no SQL mode#

Para triagem do estado das flags de comportamento do SQL, execute:

# Verificar o sql_mode ativo no banco de dados MariaDB
mysql -e "SHOW VARIABLES LIKE 'sql_mode';"

Se as flags STRICT_TRANS_TABLES ou ONLY_FULL_GROUP_BY estiverem ativas e gerando crashes nas aplicações CakePHP antigas, você deve atenuar isso editando as configurações globais do banco de dados temporariamente (ou ajustando a conexão da aplicação).


Outro erro clássico de migração de sistemas legados envolve a pilha de execução do PHP (LSAPI/FPM). Ao mover aplicações compiladas para servidores modernos rodando CloudLinux 9, a inicialização dos binários PHP antigos (ex: PHP 5.6 ou 7.2 legados) falha devido à desatualização das bibliotecas OpenSSL compartilhadas do sistema operacional.

A. Diagnóstico de bibliotecas compartilhadas (.so)#

O sistema operacional moderno entrega a biblioteca libssl.so.3 (OpenSSL 3.x), enquanto as compilações do PHP legado buscam a assinatura física libssl.so.1.1 (OpenSSL 1.1.1). Essa incompatibilidade impede o carregamento da extensão de criptografia e do módulo curl no PHP, travando conexões externas e rotinas de sessões HTTPS.

# Auditar as dependências dinâmicas do binário lsphp buscando referências ssl
ldd /usr/local/lsws/lsphp72/bin/lsphp | grep -i ssl

Se o comando retornar "not found" para as chaves OpenSSL antigas, o interpretador não conseguirá inicializar rotinas de autenticação e criptografia no PHP.


3. O limite do legado: MariaDB 10.11 vs cakephp 2.0#

Com o tráfego regularizado, enfrentamos o Erro 503 (Service Unavailable). Via lvetop, identifiquei o usuário batendo 200% de SPEED e saturação de IOPS.

Investigando o kernel#

Usei o strace para diagnosticar processos lsphp ativos por centenas de segundos:

# Monitorar o uso de recursos de CPU, IO e processos CloudLinux
lvetop

# Monitorar processos lsphp ativos e tempos de CPU consumidos
ps aux | grep lsphp

# Inspecionar syscalls em andamento no processo LSAPI travado
strace -p [PID]

O retorno foi restart_syscall. O processo estava em I/O Wait, travado no socket do MariaDB aguardando a resposta de uma transação.

Rastreabilidade: o optimizer do MariaDB#

No SHOW FULL PROCESSLIST, capturei a query. O problema estava no módulo de faturamento do CakePHP 2.0, que usava subqueries correlacionadas. O otimizador do MariaDB 10.11 ignorava os índices da tabela orders, partindo para um Full Table Scan de 565 milhões de iterações.


4. Auditoria de consultas SQL: otimizadores, EXPLAIN e índices#

Para entender a ineficiência da consulta e aplicar correções no banco, é necessário auditar o plano de execução da query com EXPLAIN e validar a presença de índices.

A. Checagem de versão da aplicação#

Antes de propor correções de código no framework CakePHP, identifique a versão declarada:

# Verificar a versão declarada do framework CakePHP no Config/core.php
cat /home/user/public_html/Config/core.php | grep -i "version"

B. Análise de plano de execução (EXPLAIN)#

Ao capturar a query com subquery correlacionada causadora do travamento, execute o EXPLAIN no console MySQL:

-- Analisar o plano de execução da query problemática no orders com subquery correlacionada
EXPLAIN SELECT * FROM orders
WHERE user_id = 123
  AND id IN (SELECT order_id FROM order_items WHERE product_id = 987);

Saída Ineficiente Esperada (Sem Índices): A ausência de key e o valor ALL em type confirmam o Full Table Scan sobre orders, com rows na casa das centenas de milhões — validando o diagnóstico da seção 3. A subquery aparece como DEPENDENT SUBQUERY, o que mostra que o otimizador reexecuta a busca interna para cada linha examinada:

+----+--------------------+-------------+------------+------+---------------+------+---------+------+-----------+----------+-----------------------------+
| id | select_type        | table       | partitions | type | possible_keys | key  | key_len | ref  | rows      | filtered | Extra                       |
+----+--------------------+-------------+------------+------+---------------+------+---------+------+-----------+----------+-----------------------------+
|  1 | PRIMARY            | orders      | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 565000000 |    10.00 | Using where                 |
|  2 | DEPENDENT SUBQUERY | order_items | NULL       | ALL  | NULL          | NULL | NULL    | NULL |      1000 |    10.00 | Using where; Using temporary|
+----+--------------------+-------------+------------+------+---------------+------+---------+------+-----------+----------+-----------------------------+

Saída Otimizada Esperada (Com Índices): O campo type alterado para ref em orders e o número de linhas (rows) reduzido para uma pequena fração de registros indica o uso correto de índices. Como a consulta utiliza SELECT *, a cláusula Extra reporta Using where (e não Using index, impossível quando colunas fora do índice são projetadas):

+----+--------------------+-------------+------------+--------+-----------------------+-----------------------+---------+------------------+------+----------+-------------+
| id | select_type        | table       | partitions | type   | possible_keys         | key                   | key_len | ref              | rows | filtered | Extra       |
+----+--------------------+-------------+------------+--------+-----------------------+-----------------------+---------+------------------+------+----------+-------------+
|  1 | PRIMARY            | orders      | NULL       | ref    | idx_orders_user_status| idx_orders_user_status| 8       | const            |   50 |   100.00 | Using where |
|  2 | DEPENDENT SUBQUERY | order_items | NULL       | eq_ref | PRIMARY,idx_prod      | PRIMARY               | 8       | orders.id        |    1 |   100.00 | Using where |
+----+--------------------+-------------+------------+--------+-----------------------+-----------------------+---------+------------------+------+----------+-------------+

C. Auditoria e criação de índices no banco#

Para verificar os índices existentes na tabela orders:

# Verificar os índices estruturados na tabela orders
mysql -u user -p -d database -e "SHOW INDEX FROM orders;"

Se não houver chave para user_id e status, crie um índice composto para evitar o escaneamento total:

-- Criar índice composto de cobertura para otimizar a consulta no orders
CREATE INDEX idx_orders_user_status ON orders(user_id, status);

5. Protocolos de backup e reversão (rollback)#

Operações de atualização de bancos de dados legados exigem backups atômicos consistentes das estruturas de dados e do código de produção para assegurar um plano de contingência rápido.

A. Scripts de backup preventivo#

Gere backups datados do banco de dados e do diretório da aplicação antes de aplicar alterações ou migrar os motores de banco:

# Realizar backup completo dos bancos de dados salvando em /root/
mysqldump -u root -p --all-databases --single-transaction --quick > /root/all-databases-$(date +%Y%m%d).sql

# Compactar a pasta contendo a aplicação CakePHP legada com caminho relativo
sudo tar czf /root/cakephp-backup-$(date +%Y%m%d).tar.gz -C /home/user public_html

B. Procedimento de rollback (reversão)#

Caso a migração ou as correções no banco de dados causem regressão grave nas tabelas de produção, execute o rollback imediato:

# Restaurar os bancos de dados a partir do dump SQL preventivo
mysql -u root -p < /root/all-databases-$(date +%Y%m%d).sql

# Limpar o diretório completamente (incluindo dotfiles como .htaccess e .env)
sudo find /home/user/public_html -mindepth 1 -delete

# Restaurar os arquivos de código originais no diretório de trabalho espelhando o backup
sudo tar xzf /root/cakephp-backup-$(date +%Y%m%d).tar.gz -C /home/user

6. Validação pós-fix e monitoramento contínuo#

Após aplicar os índices ou migrar para uma VPS dedicada rodando MySQL nativo via Governor, execute os testes operacionais para garantir a integridade dos serviços.

A. Teste de acessibilidade e logs do PHP#

Valide se as requisições estão respondendo normalmente e se não há logs de travamento de threads:

# Testar se a aplicação web está retornando código HTTP 200
curl -I https://site.com/

# Auditar logs de erros do PHP da aplicação legada em busca de warnings ou fatal errors
tail -50 /home/user/public_html/error_log

# Testar conectividade imediata com o banco de dados via terminal
mysql -u user -p -e "SELECT 1;"

B. Monitoramento e escuta de queries lentas#

O slow query log é a ferramenta mais eficaz para detectar degradações futuras.

# Definir caminho do log, habilitar slow query log e definir limiar de tempo para 2 segundos
mysql -e "SET GLOBAL slow_query_log_file = '/var/log/mysql/slow-query.log'; SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 2.0;"

# Monitorar em tempo real as consultas executadas de forma lenta no servidor
tail -f /var/log/mysql/slow-query.log

7. Checklist de migração MySQL → MariaDB#

Utilize a lista de verificação abaixo para garantir que todas as fases da migração de bancos de dados legados sejam contempladas:

1. Pré-migração#

  • [ ] Realizar backup estruturado do banco de dados com mysqldump e chaves seguras.
  • [ ] Compactar a pasta da aplicação legada contendo o código do framework CakePHP.
  • [ ] Mapear e registrar as versões do CakePHP e bibliotecas SSL instaladas.
  • [ ] Identificar e documentar as queries com maior tempo de processamento.

2. Execução da migração#

  • [ ] Realizar o restore do banco de dados na nova partição MariaDB.
  • [ ] Verificar integridade sintática das tabelas: mysqlcheck --all-databases.
  • [ ] Ajustar as flags de sql_mode na configuração global para evitar crashes no modo estrito.
  • [ ] Auditar dependências dinâmicas de OpenSSL nas instâncias lsphp legadas.

3. Validação técnica#

  • [ ] Rodar EXPLAIN nas consultas complexas de tabelas principais.
  • [ ] Validar a presença e eficiência de índices compostos em colunas acessadas de forma recorrente.
  • [ ] Testar a resposta HTTP da página inicial e de rotas internas críticas.
  • [ ] Triar logs de erro do Apache/LiteSpeed e do PHP em /home/<usuário>/public_html/error_log.

4. Monitoramento pós-instalação#

  • [ ] Ativar e inspecionar em tempo real o arquivo de slow query /var/log/mysql/slow-query.log.
  • [ ] Acompanhar o consumo de processamento e IOPS CloudLinux via comando lvetop.
  • [ ] Validar a normalização do Load Average do servidor por um período contínuo de 24 horas.

8. Matriz de riscos de migração legada#

A tabela a seguir apresenta os riscos mapeados nesta transição de arquitetura e suas devidas mitigações:

Item de RiscoSeveridadeDescrição do ProblemaMitigação / Ação Corretiva
SQL Mode Strict CrashAltaInserção de dados nulos ou datas zeradas aborta a transação com erro impeditivo no MariaDB 10.11.Ajustar o sql_mode global ou modificar a declaração de conexão na aplicação.
Falta de Índices (Full Scan)AltaO otimizador de consultas ignora índices em subqueries complexas, gerando Full Table Scan e estouro de IOPS.Analisar com EXPLAIN e criar índices compostos (CREATE INDEX) nas colunas chaves.
OpenSSL Dependency BreakAltaInterpretadores PHP antigos falham ao subir por não localizarem referências à biblioteca dinâmica libssl.so.1.1.Copiar/vincular dependências antigas compatíveis ou recompilar pacotes PHP LSAPI isolados.
Bloqueio de Sessão (Timeout)MédiaDeadlocks e concorrências de queries lentas travam as sessões PHP, gerando travamento geral da interface.Ajustar as configurações de lock de tabelas InnoDB e otimizar as queries causadoras.
Estouro de Speed no CloudLinuxMédiaO uso excessivo de recursos de processamento por processos lsphp resulta em erros HTTP 503 constantes.Configurar limites temporários maiores ou alocar as contas em VPS dedicada sob MySQL Governor.

Considerações práticas#

Este caso demonstra que a evolução da infraestrutura pode quebrar sistemas que dependem de comportamentos obsoletos. O papel do engenheiro é identificar quando o limite do software chegou ao fim da linha para o hardware atual. O MariaDB 10.11 é rigoroso, e o otimizador exige índices bem desenhados para transacionar dados em grande volume sem derrubar os pools de processos do servidor.

Este artigo foi útil?

Deixe uma reação rápida para apoiar o conteúdo:

524 leituras
Creative Commons Atribuição-NãoComercial

Este post está licenciado sob CC BY-NC.

Comentários

Participe da discussão abaixo.

0 comentários