MongoDB para Postgres
🚨 Esta postagem de 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 assumiu seu lugar, 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 mudança ocorreu em meio 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 Sistema de Gerenciamento de Armazenamento (STMS) de MongoDB para Postgres. Não foi apenas uma simples troca de banco de dados; foi uma transformação arquitetural completa de um sistema crítico que ingere mais de 1,5 milhão de métricas por minuto nos data centers da eBay, com a exigência de tempo de inatividade zero e manutenção de quase todas as funcionalidades existentes.
O que é STMS?
O Sistema de Gerenciamento de Armazenamento (STMS) serve como uma ferramenta interna crítica para a equipe de Service & Storage Infrastructure (SSI) da eBay. Ele monitora e gerencia dispositivos nos data centers da eBay, permitindo que engenheiros:
- Monitorar métricas de dezenas de arrays, switches, hosts, grupos de discos e clusters
- Gerenciar alertas para switches e arrays
- Executar tarefas avançadas como alocações de hosts
- Acessar dados em tempo real para outros serviços internos da eBay
O STMS abrange 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 centrais da empresa e as operações de negócios.
O Desafio
Por que a migração foi necessária
A decisão de migrar de MongoDB para Postgres não foi tomada levianamente. Embora o MongoDB tenha atendido bem ao STMS inicialmente, a crescente complexidade de nossos relacionamentos de dados e a necessidade de capacidades de consulta mais sofisticadas tornaram o Postgres uma solução melhor a longo prazo para nosso caso de uso.
O que tornou este problema difícil
A complexidade desta migração decorreu de vários desafios fundamentais:
1. Diferenças Fundamentais de Banco 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 de gabinete. 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 significou não apenas mudar o banco de dados, mas reestruturar como toda a nossa aplicação manipulava os dados.
3. Requisito de Tempo de Inatividade Zero
Devido à importância crítica do STMS como ferramenta interna, não poderia haver tempo de inatividade durante a migração. O sistema precisava continuar servindo mais de 1,5 milhão de métricas por minuto ao longo de todo o processo.
4. Cronograma 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 em migrar uma grande base de código legada de NoSQL para bancos de dados SQL, e eu tinha experiência limitada prévia com Postgres.
5. Escala e Complexidade
A migração envolveu converter 36 coleções MongoDB em 74 tabelas Postgres, exigindo cuidadosa consideração de relacionamentos, 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 (Object-Relational Mapping). Como nossa base de código já estava projetada para usar Mongoose para MongoDB, usar um ORM proporcionaria o caminho de transição mais suave.
Análise de Requisitos
Após 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 escrito em JavaScript)
- Deve suportar Postgres e a maioria de seus recursos
- O desempenho deve ser pelo menos equivalente ou melhor que o Mongoose
- Deve ser de código aberto e mantido
Os Candidatos
Após extensa pesquisa, reduzi a 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 da estrutura de documentos para a estrutura de tabelas.
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 (relacionamentos 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 ORM melhor para nosso caso de uso. Veja o porquê:
Vantagens do Sequelize:
- Realmente de código aberto e não mantido por uma startup financiada
- Suporta a maioria dos recursos do Postgres
- Melhor desempenho, especialmente comparado ao Prisma
- Ecossistema maduro com mais de 10 anos de desenvolvimento
- Representação flexível de modelo/esquema usando classes JavaScript
- Suporte a joins complexos e opções de filtragem incluindo Regex
Resultados de Desempenho:
Em meus testes, o Sequelize superou significativamente o Prisma. Para nossas entradas de 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 nosso caso de uso. Além disso, excluir uma entrada do nosso maior conjunto de dados levou ao Prisma quase 4 minutos, o que era inaceitável para nossos requisitos.
Desafios do Sequelize:
- Representações de modelo mais complexas e inchadas (564 linhas vs 262 linhas para Mongoose)
- Sintaxe confusa em certos casos
- Complexidade de migração de banco de dados
- Documentação menos abrangente comparada ao Prisma
Comparação de Prós & Contras do Sequelize & Prisma
Para dar uma visão mais completa do porquê escolhi o Sequelize, quero compartilhar os detalhes de prós e contras que compilei para ambos os ORMs durante minha avaliação. Também analisei como eles se posicionavam em termos de representação de esquema e suporte da comunidade em 15 de maio de 2023. Essa análise mais profunda ajudou a solidificar minha escolha, e espero que possa ser útil para qualquer outra pessoa enfrentando uma decisão semelhante.
Prós do Sequelize:
- Possui uma função sync() que cria e gerencia tabelas automaticamente, 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, proporcionando flexibilidade nas consultas.
- A representação de modelo/esquema é feita em JavaScript puro usando classes, altamente personalizáveis para atender necessidades específicas.
- Gerencia conexões de banco de dados de forma fluida, incluindo suporte a múltiplas conexões de leitura.
- Suporta consultas SQL brutas para quando precisar acessar detalhes internos.
- Estatísticas da comunidade em 15 de maio de 2023: No NPM, atualizado pela última vez há 14 dias com 1.505.835 downloads semanais; no GitHub, atualizado ontem com 4,2k forks e 27,9k estrelas. É de código aberto com licença MIT há mais de 10 anos, então estou confiante de que permanecerá assim.
Contras do Sequelize:
- A representação de modelo/esquema pode ficar muito complexa e inchada. Por exemplo, enquanto a representação Mongoose do nosso grande conjunto de dados tinha cerca de 262 linhas (incluindo espaços), o mesmo conjunto em Sequelize inflou para 564 linhas.
- A sintaxe pode ser confusa e complicada em certos cenários, o que me atrasou às vezes.
- 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 percebido que isso é um ponto doloroso comum na maioria dos ORMs.
- A documentação não é ótima, embora esteja melhorando. Felizmente, ferramentas como o ChatGPT têm um bom domínio 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 gerar problemas em alguns projetos.
- Suporte limitado a TypeScript, embora isso não fosse uma preocupação para o STMS, pode ser decisivo 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 nosso grande conjunto de dados, o Prisma fez isso em apenas 221 linhas.
- Vem com uma ferramenta CLI que simplifica a criação e migração de banco de dados, sendo a melhor que já vi em um ORM até agora, embora não seja perfeita.
- Suporta consultas SQL brutas, oferecendo flexibilidade quando necessário.
- A sintaxe do código é limpa e mais simples de entender comparada ao Sequelize, facilitando o aprendizado.
- Gera automaticamente construtores de consultas para Node.js e TypeScript via seu cliente, o que é um detalhe agradável.
- Possui documentação excelente e limpa. O ChatGPT não está tão atualizado sobre o Prisma, mas a documentação oficial costuma compensar.
- Estatísticas da comunidade em 15 de maio de 2023: No NPM, atualizado há 6 dias com 1.344.705 downloads semanais; no GitHub, atualizado há 3 horas com 1,1k forks e 31,3k estrelas.
Contras do Prisma:
- Não suporta filtragem Regex para Postgres, embora ofereça alternativas como “contains”, “includes” e “startsWith”.
- Desempenho foi um grande problema nos meus testes. Criar entradas para nosso grande conjunto de dados levou ao Prisma cerca de 11,21 segundos por entrada comparado aos 2,26 segundos do Sequelize, aproximadamente 5x mais lento.
- Excluir uma única entrada do grande conjunto de dados levou quase 4 minutos, o que foi decisivo para nossas necessidades.
- Mesmo com uma comparação justa em um conjunto de dados complexo, com relacionamentos de três camadas, o Sequelize foi significativamente mais rápido nas exclusões.
- O Prisma é apoiado por uma startup com US$ 56,5 milhões em financiamento. Embora seu código principal de ORM seja de código aberto sob Apache-2.0, estou cauteloso quanto a possíveis mudanças de licença no futuro, similar 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 a longo prazo. Mas achei que dividir isso poderia ajudar outros que enfrentam a mesma escolha em seus projetos.
O Processo de Migração
Transformação da Estrutura de Dados
Convertendo a estrutura de documentos do MongoDB para a estrutura relacional do Postgres exigiu 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, quando apropriado
- Preservar Recursos JSON: Usar colunas JSONB para dados verdadeiramente não estruturados que precisavam permanecer flexíveis
- Projetar Índices: Criar índices adequados para desempenho de consultas
Soluções Personalizadas
A migração exigiu o desenvolvimento de várias soluções personalizadas:
1. Scripts de Migração de Dados
Criei scripts abrangentes para:
- Extrair dados das coleções do MongoDB
- Transformar estruturas de documentos para formato relacional
- Importar dados nas tabelas do Postgres com relacionamentos corretos
2. Camada de Compatibilidade de API
Para manter zero tempo de inatividade, construí uma camada de compatibilidade que poderia:
- Roteiar solicitações para o MongoDB ou para o Postgres, dependendo do status da migração
- Garantir a 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 o MongoDB e o Postgres tratam certas operações, garantindo que os endpoints de API existentes continuassem a funcionar sem modificações.
Superando Desafios Técnicos
Manipulação de Relacionamentos Complexos
Um dos maiores desafios foi converter os documentos incorporados do MongoDB em relacionamentos do Postgres. Por exemplo, um único documento do MongoDB pode conter:
- Propriedades básicas
- Objetos aninhados que representam entidades relacionadas
- Arrays de documentos incorporados
Isso precisou 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 & Impacto
A migração do STMS do MongoDB para o Postgres foi concluída com sucesso, sem tempo de inatividade, mantendo quase todas as funcionalidades e recursos. 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 de backup e recuperação aprimorados
Impacto na Equipe:
- Conhecimento da equipe sobre bancos de dados relacionais aprimorado
- Padrões estabelecidos para futuras migrações de bancos de dados
- Ferramentas e processos reutilizáveis criados
Habilidades Técnicas Adquiridas
Este projeto expandiu significativamente minha expertise técnica:
Tecnologias de Banco de Dados:
- Compreensão profunda dos recursos e otimizações 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 primário-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 tempo de inatividade
- Camadas de compatibilidade de API
- Padrões de abstração de banco de dados
- Sistemas de monitoramento e alerta
Crescimento Pessoal & Profissional
Este projeto de migração foi transformador para o desenvolvimento da minha carreira. Ele me empurrou para territórios desconhecidos, 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:
- Decompor problemas complexos em componentes gerenciáveis
- Desenvolver soluções criativas para desafios sem precedentes
- Equilibrar múltiplos requisitos e restrições concorrentes
Comunicação & Trabalho em Equipe:
- Explicar conceitos técnicos para partes interessadas não técnicas
- Documentar processos e decisões para referência futura
- Mentorar membros da equipe em novas tecnologias e padrões
Lições Aprendidas
Lições Técnicas
- A Seleção de Banco de Dados Importa: A escolha entre NoSQL e SQL deve ser baseada em casos de uso específicos e requisitos de longo prazo
- Teste de Desempenho é Crítico: Vantagens teóricas nem sempre se traduzem em ganhos de desempenho no mundo real
- Planejamento de Migração: Planejamento e testes abrangentes são essenciais para migrações complexas
- Investimento em Ferramentas: Construir ferramentas adequadas desde o início economiza tempo significativo e reduz erros
Lições de Gerenciamento de Projetos
- Comunicação com Stakeholders: Atualizações regulares e comunicação clara evitam mal-entendidos
- Gestão de Riscos: Ter planos de fallback e procedimentos de rollback é essencial
- Gestão de Cronograma: Reservar tempo de buffer para desafios inesperados e curvas de aprendizado
- Documentação: Documentação completa 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 gratificante que resolvi em minha carreira. Ela exigiu não apenas expertise técnica, mas também liderança, planejamento e adaptabilidade. O sucesso do projeto demonstrou que, com planejamento adequado, testes rigorosos 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 ao longo de 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 beneficiando os projetos de infraestrutura da eBay. Reforçou minha crença de que abraçar desafios desconhecidos e triunfar sobre eles é fundamental tanto para o desenvolvimento pessoal quanto profissional.
Olhando para trás, este projeto representa um ponto de virada em minha carreira, transformando-me de um desenvolvedor que implementa soluções para um engenheiro que pode arquitetar e liderar iniciativas técnicas complexas. A confiança e as habilidades adquiridas com essa experiência continuam guiando minha abordagem a novos desafios e oportunidades na engenharia de software.