MongoDB para Postgres
NOTA: Esta postagem do blog é uma fusão do meu MongoDB para Postgres (2024-03-06) e Sequelize vs. Prisma (2023-05-25). Os blogs originais foram removidos, e este blog tomou o lugar deles, já que ambos continham essencialmente o mesmo conteúdo/informação. A migração começou em início de março de 2023, a troca ocorreu em meados de novembro de 2023, e todas as instâncias do antigo sistema MongoDB foram completamente desligadas em início de janeiro de 2024.
Introdução
Durante meu tempo na eBay, enfrentei o que se tornou o problema tecnicamente mais desafiador da minha carreira: migrar o Storage Management System (STMS) de MongoDB para Postgres. Isso não foi apenas uma simples troca de banco de dados; foi uma transformação arquitetônica completa de um sistema crítico que ingere mais de 1,5 milhão de métricas por minuto em todos os data centers da eBay, com a exigência de tempo de inatividade zero e manutenção de praticamente toda a funcionalidade existente.
O que é o STMS?
O Storage Management System (STMS) serve como uma ferramenta interna crítica para a equipe de Service & Storage Infrastructure (SSI) da eBay. Ele monitora e gerencia dispositivos em todos os data centers da eBay, permitindo que engenheiros:
- Monitorem métricas de dezenas de arrays, switches, hosts, grupos de discos e clusters
- Lidarem com alertas para switches e arrays
- Concluam tarefas avançadas como alocações de hosts
- Acessem dados em tempo real para outros serviços internos da eBay
O STMS é responsável por mais de 70 arrays, 60 switches, 1100 hosts, 900 grupos de discos e 200 clusters em 3 dos data centers da eBay. Dado seu papel vital na infraestrutura da eBay, qualquer tempo de inatividade ou perda de funcionalidade impactaria diretamente os serviços principais e as operações de negócios da empresa.
O Desafio
Por que a Migração Era Necessária
A decisão de migrar de MongoDB para Postgres não foi tomada de forma leviana. Embora o MongoDB tenha atendido bem ao STMS inicialmente, a crescente complexidade das relações dos nossos dados e a necessidade de capacidades de consulta mais sofisticadas fizeram do Postgres uma solução melhor a longo prazo para o nosso caso de uso.
O que Tornou Este Problema Difícil
A complexidade dessa migração decorreu de vários desafios fundamentais:
1. Diferenças Fundamentais entre Bancos de Dados
MongoDB e Postgres são bancos de dados fundamentalmente diferentes. MongoDB é um banco de dados baseado em documentos (NoSQL), o que significa que os dados são armazenados como JSON em coleções, como documentos em um arquivo. Postgres é um banco de dados relacional (SQL), o que significa que os dados são armazenados como linhas em tabelas, como em uma planilha.
2. Arquitetura da Base de Código
Todo o backend do STMS foi construído para processar e gerenciar dados como JSONs, usando pacotes exclusivamente compatíveis com MongoDB para operações de banco de dados. Isso significava não apenas mudar o banco de dados, mas reestruturar a forma como toda a nossa aplicação lidava com os dados.
3. Requisito de Tempo de Inatividade Zero
Devido à importância vital do STMS como ferramenta interna, não poderia haver tempo de inatividade durante a migração. O sistema precisava continuar servindo 1,5+ milhão de métricas por minuto durante todo o processo.
4. Prazo Apertado e Experiência Limitada
A migração precisava ser concluída em poucos meses, sem um plano de execução claro inicialmente. Nem eu nem meus colegas tínhamos experiência migrando uma grande base de código legada de bancos de dados NoSQL para SQL, e eu tinha experiência prévia limitada com Postgres.
5. Escala e Complexidade
A migração envolveu a conversão de 36 coleções do MongoDB em 74 tabelas do Postgres, exigindo consideração cuidadosa de relações, indexação e otimização de consultas.
Escolhendo o ORM Certo: Sequelize vs Prisma
Uma das primeiras decisões importantes foi selecionar uma ferramenta ORM (Mapeamento Objeto-Relacional). Como nossa base de código já havia sido projetada para usar Mongoose para MongoDB, usar um ORM proporcionaria o caminho de transição mais suave.
Análise de Requisitos
Após uma análise cuidadosa das necessidades do projeto, estabeleci critérios essenciais para qualquer solução ORM:
- Deve ser um pacote JavaScript (a maior parte do nosso código foi escrita em JavaScript)
- Deve suportar Postgres e a maioria de seus recursos
- O desempenho deve ser pelo menos equivalente ou melhor que o do Mongoose
- Deve ser open source e mantido
Os Candidatos
Após extensa pesquisa, reduzi para dois principais concorrentes: Sequelize e Prisma. Criei ambientes de teste abrangentes usando Docker para Postgres e converti nosso maior e mais complexo conjunto de dados de estrutura de documento para estrutura de tabela.
Metodologia de Teste
Para cada ORM, medi o desempenho em operações críticas:
- Tempo para criar uma entrada
- Tempo para atualizar uma entrada
- Tempo para atualizar entradas aninhadas (relações e pares-chave-valor JSON)
- Tempo para excluir uma entrada
- Tempo para consultar/obter uma entrada
A Decisão: Sequelize
Por volta de 15 de maio de 2023, decidi que o Sequelize era o melhor ORM para o nosso caso de uso. Eis o motivo:
Vantagens do Sequelize:
- Verdadeiramente open source e não mantido por uma startup financiada
- Suportava a maioria dos recursos do Postgres
- Melhor desempenho, especialmente em comparação com o Prisma
- Ecossistema maduro com mais de 10 anos de desenvolvimento
- Representação flexível de modelo/esquema usando classes JavaScript
- Suporte para joins complexos e opções de filtragem, incluindo Regex
Resultados de Desempenho:
Nos meus testes, o Sequelize superou significativamente o Prisma. Para as entradas do nosso grande conjunto de dados:
- Sequelize: ~2,26 segundos por entrada
- Prisma: ~11,21 segundos por entrada
O Prisma foi aproximadamente 5x mais lento que o Sequelize para o nosso caso de uso. Além disso, excluir uma entrada do nosso maior conjunto de dados levou quase 4 minutos no Prisma, o que era inaceitável para os nossos requisitos.
Desafios do Sequelize:
- Representações de modelo mais complexas e volumosas (564 linhas vs 262 linhas no Mongoose)
- Sintaxe confusa em certos casos
- Complexidade na migração do banco de dados
- Documentação menos abrangente em comparação com o Prisma
Comparação de Prós e Contras do Sequelize e do Prisma
Para dar uma visão mais completa de por que escolhi o Sequelize, quero compartilhar os prós e contras detalhados que compilei para ambos os ORMs durante minha avaliação. Também analisei como eles se comparavam em termos de representação de esquema e suporte da comunidade em 15 de maio de 2023. Esse mergulho mais profundo ajudou a solidificar minha escolha, e espero que possa ser útil para qualquer outra pessoa enfrentando uma decisão semelhante.
Prós do Sequelize:
- Tem uma função sync() que cria e gerencia automaticamente tabelas para você, economizando muito esforço manual.
- Pode lidar com joins complexos para dados aninhados, o que era crítico para a estrutura do STMS.
- Suporta uma ampla gama de opções de filtragem, incluindo Regex, oferecendo flexibilidade nas consultas.
- A representação de modelo/esquema é feita em JavaScript puro usando classes, que são altamente personalizáveis para atender necessidades específicas.
- Gerencia conexões de banco de dados de forma fluida, incluindo suporte para múltiplas conexões de leitura.
- Suporta consultas SQL brutas quando você precisa olhar “por baixo do capô”.
- Estatísticas da comunidade em 15 de maio de 2023: No NPM, última atualização há 14 dias com 1.505.835 downloads semanais; no GitHub, última atualização ontem com 4,2 mil forks e 27,9 mil estrelas. Está em open source com licença MIT há mais de 10 anos, então tenho confiança de que continuará assim.
Contras do Sequelize:
- A representação de modelo/esquema pode ficar muito complexa e volumosa. Por exemplo, enquanto a representação do Mongoose do nosso grande conjunto de dados tinha cerca de 262 linhas (incluindo espaços), o mesmo conjunto de dados no Sequelize explodiu para 564 linhas.
- A sintaxe pode ser confusa e complicada em certos cenários, o que às vezes me atrasava.
- Migrar ou editar o banco de dados é um incômodo. Mesmo com o sequelize-cli gerando scripts de migração, ainda é trabalhoso, embora eu tenha notado que isso é um ponto problemático comum na maioria dos ORMs.
- A documentação não é ótima, embora esteja melhorando. Felizmente, ferramentas como o ChatGPT têm um bom entendimento do Sequelize devido à sua longa história, o que ajudou a preencher as lacunas.
- Não é tão sensível a tipos quanto o Prisma, o que pode levar a problemas em alguns projetos.
- Suporte limitado a TypeScript; embora isso não fosse uma preocupação para o STMS, poderia ser um fator निर्णisivo para outros.
Prós do Prisma:
- Usa sua própria linguagem de esquema, tornando a criação de modelos mais limpa e concisa. Para comparação, enquanto o Mongoose levou 262 linhas para o nosso grande conjunto de dados, o Prisma conseguiu fazer isso em apenas 221 linhas.
- Vem com uma ferramenta CLI que simplifica a criação e migração de bancos de dados, que é a melhor que já vi em um ORM até agora, mesmo que não seja perfeita.
- Suporta consultas SQL brutas, oferecendo flexibilidade quando necessário.
- A sintaxe do código é limpa e mais simples de entender em comparação com o Sequelize, tornando-o mais fácil de aprender.
- Gera automaticamente construtores de consultas para Node.js e TypeScript por meio do seu cliente, o que é um bom toque.
- Tem documentação excelente e limpa. O ChatGPT não está tão atualizado sobre o Prisma, mas a documentação oficial muitas vezes compensava isso.
- Estatísticas da comunidade em 15 de maio de 2023: No NPM, última atualização há 6 dias com 1.344.705 downloads semanais; no GitHub, última atualização há 3 horas com 1,1 mil forks e 31,3 mil estrelas.
Contras do Prisma:
- Não suporta filtragem Regex para Postgres, embora ofereça alternativas como “contains”, “includes” e “startsWith.”
- O desempenho foi um grande problema nos meus testes. Criar entradas para o nosso grande conjunto de dados levou cerca de 11,21 segundos por entrada no Prisma, em comparação com 2,26 segundos no Sequelize, aproximadamente 5x mais lento.
- Excluir uma única entrada do grande conjunto de dados levou quase 4 minutos, o que foi um impeditivo para as nossas necessidades.
- Mesmo com uma comparação justa em um conjunto de dados de relacionamento complexo, com três camadas de profundidade, o Sequelize foi significativamente mais rápido nas exclusões.
- O Prisma é sustentado por uma startup com 56,5 milhões de dólares em financiamento. Embora o código principal do ORM seja open source sob Apache-2.0, tenho cautela quanto a possíveis mudanças de licenciamento no futuro, semelhante ao que aconteceu com o MongoDB.
Essas comparações detalhadas deixaram claro que o Sequelize se alinhava melhor às necessidades do STMS, especialmente em desempenho e confiabilidade de longo prazo. Mas pensei que detalhar assim poderia ajudar outras pessoas que estivessem lidando com a mesma escolha para seus projetos.
O Processo de Migração
Transformação da Estrutura de Dados
A conversão da estrutura de documentos do MongoDB para a estrutura relacional do Postgres exigiu um planejamento cuidadoso. Eu tive que:
- Analisar Relacionamentos: Identificar como os documentos do MongoDB se relacionavam entre si e projetar relacionamentos de chave estrangeira apropriados
- Normalizar Dados: Dividir documentos aninhados em tabelas separadas onde apropriado
- Preservar Recursos JSON: Usar colunas JSONB para dados verdadeiramente não estruturados que precisavam permanecer flexíveis
- Projetar Índices: Criar índices apropriados para o desempenho das consultas
Soluções Personalizadas
A migração exigiu o desenvolvimento de várias soluções personalizadas:
1. Scripts de Migração de Dados
Eu criei scripts abrangentes para:
- Extrair dados das coleções do MongoDB
- Transformar estruturas de documentos para o formato relacional
- Importar dados para tabelas do Postgres com relacionamentos adequados
2. Camada de Compatibilidade da API
Para manter zero downtime, construí uma camada de compatibilidade que podia:
- Redirecionar requisições para MongoDB ou Postgres dependendo do status da migração
- Garantir consistência dos dados durante o período de transição
- Fornecer mecanismos de fallback
3. Middleware Personalizado
Desenvolvi middleware para lidar com as diferenças na forma como MongoDB e Postgres tratam certas operações, garantindo que os endpoints de API existentes continuassem a funcionar sem modificação.
Superando Desafios Técnicos
Lidando com Relacionamentos Complexos
Um dos maiores desafios foi converter os documentos embutidos do MongoDB em relacionamentos do Postgres. Por exemplo, um único documento do MongoDB poderia conter:
- Propriedades básicas
- Objetos aninhados representando entidades relacionadas
- Arrays de documentos embutidos
Isso teve que ser cuidadosamente decomposto em:
- Tabelas principais para entidades principais
- Tabelas de junção para relacionamentos muitos-para-muitos
- Relacionamentos de chave estrangeira para associações um-para-muitos
Otimização de Consultas
Os padrões de consulta do MongoDB não se traduzem diretamente para SQL. Eu tive que:
- Reescrever pipelines de agregação complexos como joins SQL
- Otimizar índices para novos padrões de consulta
- Garantir que o desempenho das consultas atendesse ou superasse o desempenho do MongoDB
Integridade dos Dados
Garantir a integridade dos dados durante a migração exigiu:
- Scripts de validação abrangentes
- Procedimentos de rollback
- Sincronização de dados em tempo real durante os períodos de transição
Resultados e Impacto
A migração do STMS de MongoDB para Postgres foi concluída com sucesso e sem downtime, mantendo quase todos os recursos e funcionalidades. Os resultados superaram as expectativas:
Melhorias de Desempenho:
- O desempenho das consultas melhorou para consultas relacionais complexas
- Melhor consistência e integridade dos dados
- Utilização de armazenamento mais eficiente
Benefícios Operacionais:
- Capacidades aprimoradas de monitoramento e depuração
- Melhor integração com as ferramentas baseadas em SQL existentes da eBay
- Procedimentos aprimorados de backup e recuperação
Impacto na Equipe:
- Conhecimento aprimorado da equipe sobre bancos de dados relacionais
- Estabelecimento de padrões para futuras migrações de banco de dados
- Criação de ferramentas e processos reutilizáveis
Habilidades Técnicas Adquiridas
Este projeto expandiu significativamente minha expertise técnica:
Tecnologias de Banco de Dados:
- Profundo entendimento dos recursos e da otimização do Postgres
- Otimização de consultas SQL e ajuste de desempenho
- Padrões de design de banco de dados e normalização
- Configurações de banco de dados primary-standby
Ferramentas de Desenvolvimento:
- ORM Sequelize e construção de consultas
- Estratégias de migração de banco de dados
- Metodologias de teste de desempenho
- Validação de dados e verificação de integridade
Padrões de Arquitetura:
- Estratégias de migração sem downtime
- Camadas de compatibilidade de API
- Padrões de abstração de banco de dados
- Sistemas de monitoramento e alertas
Crescimento Pessoal e Profissional
Este projeto de migração foi transformador para o meu desenvolvimento de carreira. Ele me levou para um território inexplorado, exigindo:
Habilidades de Liderança:
- Liderar um projeto técnico complexo sem experiência prévia
- Tomar decisões arquiteturais críticas sob pressão
- Coordenar com múltiplas equipes e partes interessadas
Capacidades de Resolução de Problemas:
- Dividir problemas complexos em componentes gerenciáveis
- Desenvolver soluções criativas para desafios sem precedentes
- Equilibrar múltiplos requisitos e restrições concorrentes
Comunicação e Trabalho em Equipe:
- Explicar conceitos técnicos para partes interessadas sem conhecimento técnico
- Documentar processos e decisões para referência futura
- Orientar membros da equipe sobre novas tecnologias e padrões
Lições Aprendidas
Lições Técnicas
- A Escolha do Banco de Dados Importa: A escolha entre NoSQL e SQL deve ser baseada em casos de uso específicos e requisitos de longo prazo
- Testes de Desempenho São Críticos: Vantagens teóricas nem sempre se traduzem em ganhos reais de desempenho
- Planejamento de Migração: Planejamento e testes abrangentes são essenciais para migrações complexas
- Investimento em Ferramentas: Construir boas ferramentas antecipadamente economiza tempo significativo e reduz erros
Lições de Gerenciamento de Projeto
- Comunicação com as Partes Interessadas: Atualizações regulares e comunicação clara evitam mal-entendidos
- Gerenciamento de Riscos: Ter planos de contingência e procedimentos de rollback é essencial
- Gerenciamento de Cronograma: Reservar tempo extra para desafios inesperados e curvas de aprendizado
- Documentação: Documentação detalhada permite transferência de conhecimento e manutenção futura
Conclusão
A migração do STMS de MongoDB para Postgres se destaca como o problema técnico mais desafiador e recompensador que resolvi em minha carreira. Ela exigiu não apenas conhecimento técnico, mas também liderança, planejamento e adaptabilidade. O sucesso do projeto demonstrou que, com planejamento adequado, testes minuciosos e compromisso com a excelência, até os desafios técnicos mais complexos podem ser superados.
Essa experiência mudou fundamentalmente minha abordagem à engenharia de software, enfatizando a importância de:
- Entender o contexto completo e os requisitos antes de tomar decisões técnicas
- Investir tempo em ferramentas e testes adequados
- Manter comunicação clara durante projetos complexos
- Estar disposto a aprender novas tecnologias e abordagens quando necessário
O sucesso da migração não apenas melhorou as capacidades do STMS, mas também estabeleceu padrões e processos que continuam a beneficiar os projetos de infraestrutura da eBay. Isso reforçou minha crença de que enfrentar desafios desconhecidos e ter sucesso ao superá-los é fundamental para o desenvolvimento pessoal e profissional.
Olhando para trás, este projeto representa um ponto de virada na minha carreira, transformando-me de um desenvolvedor que implementa soluções em um engenheiro capaz de arquitetar e liderar iniciativas técnicas complexas. A confiança e as habilidades adquiridas com essa experiência continuam a orientar minha abordagem a novos desafios e oportunidades em engenharia de software.