34 pontos por GN⁺ 2024-03-15 | 1 comentários | Compartilhar no WhatsApp
  • A equipe de banco de dados da Figma resumiu a jornada de nove meses para fazer sharding horizontal da stack Postgres e como isso possibilitou uma escalabilidade quase infinita

A jornada de sharding horizontal da stack Postgres da Figma

  • A escala da stack de banco de dados da Figma cresceu quase 100x desde 2020: isso é um problema positivo, pois reflete a expansão do negócio, mas ao mesmo tempo traz desafios técnicos. Em 2020, a empresa operava um único banco de dados Postgres na maior instância física da AWS e, até o fim de 2022, construiu uma arquitetura distribuída com cache, réplicas de leitura e vários bancos de dados particionados verticalmente.
  • Particionamento vertical: ao separar grupos de tabelas relacionadas em suas próprias partições verticais, a equipe obteve ganhos graduais de escala e manteve folga suficiente para acompanhar o crescimento. Por exemplo, grupos de tabelas relacionadas como “arquivos do Figma” ou “organizações” foram divididos em suas próprias partições verticais.
  • Transição para o sharding horizontal: a equipe reconheceu que o particionamento vertical sozinho tinha limites. Depois dos esforços iniciais de escala com foco em reduzir o uso de CPU, passou a monitorar vários gargalos em uma frota maior e mais diversa. Os limites de escala do banco de dados foram quantificados em diferentes dimensões, de CPU e IO até tamanho das tabelas e número de linhas gravadas. Identificar esses limites foi essencial para prever quanta folga restava por shard.
  • Limites do tamanho das tabelas: algumas tabelas passaram a armazenar vários terabytes e dezenas de bilhões de linhas, alcançando um tamanho difícil de administrar em um único banco de dados. Nessa escala, a operação de vacuum do Postgres (uma tarefa de fundo essencial para evitar interrupções por esgotamento de transaction IDs) passava a afetar a confiabilidade. As tabelas com maior volume de escrita logo excederiam o IOPS máximo suportado pelo Amazon Relational Database Service (RDS). Era um problema que o particionamento vertical não conseguia resolver, e uma solução maior era necessária para impedir o colapso do banco de dados.

Construindo a base para escalar

  • Minimizar o impacto para desenvolvedores: a equipe absorveu a maior parte da complexidade do modelo de dados relacional para que os desenvolvedores de aplicação pudessem se concentrar em criar novos recursos interessantes na Figma, em vez de refatorar grandes partes do código.
  • Escala transparente: a ideia era evitar mudanças adicionais na camada de aplicação no futuro ao escalar. Ou seja, depois do trabalho inicial para tornar as tabelas compatíveis, a expansão futura poderia acontecer de forma transparente para as equipes de produto.
  • Evitar backfill custoso: a Figma evitou soluções que exigissem backfill em tabelas grandes ou em todas as tabelas. Dado o tamanho dessas tabelas e os limites de throughput do Postgres, esse backfill levaria meses.
  • Progresso gradual: a equipe identificou uma abordagem que pudesse ser lançada gradualmente, reduzindo o risco de mudanças críticas em produção. Isso diminuía o risco de grandes interrupções e permitia que a equipe de banco de dados mantivesse a confiabilidade da Figma durante a migração.
  • Evitar migrações sem volta: a capacidade de rollback foi mantida mesmo após a conclusão do trabalho de sharding físico. Isso reduz o risco de ficar preso a um estado ruim quando surgem variáveis desconhecidas.
  • Manter forte consistência de dados: a equipe evitou soluções complexas difíceis de implementar sem downtime ou que comprometessem a consistência, como double-writes. O objetivo era uma solução que permitisse escalar com downtime quase zero.
  • Aproveitar os próprios pontos fortes: sob pressão de prazos apertados, a equipe preferiu uma abordagem que pudesse ser lançada o mais gradualmente possível. Para as tabelas de crescimento mais rápido, procurou aproveitar a experiência e as tecnologias já dominadas.

Explorando as opções possíveis

  • Avaliação de opções de bancos de dados com sharding horizontal: existem várias soluções populares, open source e gerenciadas, para bancos de dados com sharding horizontal compatíveis com Postgres ou MySQL. No processo de avaliação, a equipe analisou CockroachDB, TiDB, Spanner e Vitess. No entanto, migrar para um desses bancos alternativos exigiria uma migração de dados complexa para garantir consistência e confiabilidade entre dois armazenamentos de banco de dados diferentes.
  • Aproveitar a experiência existente: nos últimos anos, a equipe desenvolveu muito conhecimento sobre como operar o RDS Postgres de forma estável e eficiente. Durante a migração, teria sido necessário reconstruir esse conhecimento de domínio do zero. Dado o ritmo de crescimento extremamente agressivo, restavam apenas alguns meses.
  • Descartar a escolha de banco NoSQL: outra solução escalável frequentemente adotada conforme uma empresa cresce é um banco NoSQL. Porém, a Figma já tinha um modelo de dados relacional muito complexo construído sobre a arquitetura atual do Postgres, e a API NoSQL não oferecia essa variedade. A intenção era permitir que os engenheiros se concentrassem em lançar ótimos recursos e construir novos produtos, em vez de reescrever quase todas as aplicações de backend; por isso, NoSQL não era uma solução viável.
  • Considerar construir uma solução de sharding horizontal sobre a infraestrutura existente de RDS Postgres: para uma equipe pequena, não fazia sentido reimplementar internamente um banco de dados relacional genérico com sharding horizontal. Isso significaria competir com ferramentas criadas por grandes comunidades open source ou fornecedores especializados de banco de dados. Ainda assim, como o sharding horizontal seria adaptado à arquitetura específica da Figma, bastaria oferecer um conjunto muito menor de funcionalidades. Por exemplo, a equipe decidiu não oferecer suporte a transações entre shards com garantia de atomicidade, porque havia maneiras de lidar com falhas de transações entre shards. Foi escolhida uma estratégia de colocation para minimizar as mudanças necessárias na camada de aplicação. Com isso, tornou-se possível oferecer suporte a um subconjunto do Postgres compatível com a maior parte da lógica de produto. Também ficou mais fácil manter retrocompatibilidade entre Postgres com sharding e sem sharding. Diante de variáveis desconhecidas, era possível fazer rollback facilmente para o Postgres sem sharding.

O caminho para o sharding horizontal

  • Introdução ao sharding horizontal: sharding horizontal é o processo de dividir uma única tabela ou grupo de tabelas para distribuir os dados entre várias instâncias físicas de banco de dados. Com isso, as tabelas com sharding horizontal na camada de aplicação podem dar suporte a qualquer número de shards na camada física. Sempre é possível escalar mais simplesmente executando uma divisão física de shards, e essa operação acontece de forma transparente em segundo plano, com downtime mínimo e sem mudanças no nível da aplicação. Com essa capacidade, a Figma conseguiu ficar à frente dos gargalos restantes de escala do banco de dados e eliminar um dos últimos grandes desafios de escalabilidade da empresa. Se o particionamento vertical permitia acelerar na velocidade de uma rodovia, o sharding horizontal remove o limite de velocidade e permite voar.
  • A complexidade do sharding horizontal: o sharding horizontal é uma ordem de magnitude mais complexo do que os esforços anteriores de escala. Quando as tabelas são divididas entre vários bancos de dados físicos, muitas das propriedades de confiabilidade e consistência que se assumem em um banco SQL ACID deixam de existir. Por exemplo, certas consultas SQL podem se tornar ineficientes ou impossíveis de suportar, e o código da aplicação precisa ser atualizado para fornecer informações suficientes para rotear consultas de forma eficiente ao shard correto sempre que possível. Mudanças de schema precisam ser coordenadas para manter todos os shards sincronizados, e chaves estrangeiras e índices globalmente únicos deixam de poder ser garantidos pelo Postgres. As transações passam a abranger vários shards, e o Postgres já não consegue mais impô-las. Agora, operações de escrita podem ter sucesso em alguns bancos enquanto falham em outros. A lógica de produto precisa ser cuidadosamente projetada para ser robusta a essas “falhas de commit parcial” (por exemplo, imagine mover uma equipe entre duas organizações e metade dos dados simplesmente ficar faltando!).
  • Um esforço de vários anos rumo ao sharding horizontal: a equipe sabia que alcançar o sharding horizontal completo seria um esforço de vários anos. Era preciso entregar valor incremental enquanto reduzia o risco do projeto o máximo possível. O primeiro objetivo foi shardear o quanto antes, em produção, uma tabela relativamente simples, mas com tráfego muito alto. Isso não apenas provaria a viabilidade do sharding horizontal, como também prolongaria a folga dos bancos de dados mais carregados. Depois disso, seria possível construir recursos adicionais ao shardear grupos de tabelas mais complexos. Mesmo o conjunto mais simples possível de funcionalidades ainda exigiu um trabalho considerável. Do início ao fim, a equipe levou cerca de nove meses para shardear a primeira tabela.

Nossa abordagem única

  • Colocation (colos): fizeram sharding horizontal de grupos de tabelas relacionadas em colocations que compartilham a mesma chave de sharding e o mesmo layout físico de sharding, carinhosamente chamadas de “colos”. Isso fornece aos desenvolvedores uma abstração amigável para interagir com tabelas com sharding horizontal.
  • Sharding lógico: separaram o conceito de “sharding lógico” na camada de aplicação do conceito de “sharding físico” na camada do Postgres. Usaram views para fazer lançamentos de sharding lógico, mais seguros e baratos, antes de executar failovers físicos distribuídos, que são mais arriscados.
  • Motor de consultas do DBProxy: construíram o serviço DBProxy para interceptar consultas SQL geradas na camada de aplicação e rotear dinamicamente as consultas para diferentes bancos de dados Postgres. O DBProxy inclui um motor de consultas capaz de analisar e executar consultas complexas em um ambiente com sharding horizontal. Por meio do DBProxy, conseguiram implementar recursos como balanceamento de carga dinâmico e hedging de requisições.
  • Prontidão da aplicação sombra: adicionaram uma estrutura de “prontidão da aplicação sombra” capaz de prever como o tráfego real de produção se comportaria sob diferentes chaves de sharding potenciais. Isso dá às equipes de produto uma visão clara da necessidade de refatorar ou remover lógica da aplicação para prepará-la para o sharding horizontal.
  • Replicação lógica completa: não foi necessário implementar “replicação lógica filtrada”, que copia apenas subconjuntos de dados para cada shard. Em vez disso, copiaram o conjunto completo de dados e depois permitiram leitura/gravação apenas para o subconjunto de dados pertencente a um determinado shard.

Implementando o sharding

  • A importância de escolher a chave de shard: uma das decisões mais importantes no sharding horizontal é qual chave de shard usar. O sharding horizontal adiciona várias restrições de modelagem de dados em torno da chave de shard. Por exemplo, a maioria das consultas precisa incluir a chave de shard para que a requisição seja roteada ao shard correto. Certas restrições do banco de dados, como chaves estrangeiras, só funcionam quando a chave estrangeira também é a chave de sharding. A chave de shard também deve distribuir os dados de forma uniforme por todos os shards para evitar hotspots que prejudiquem a confiabilidade ou a escalabilidade.
  • Abordagem personalizada para o modelo de dados da Figma: a Figma funciona no navegador, e muitos usuários podem colaborar simultaneamente no mesmo arquivo da Figma. Isso significa que ela é sustentada por um modelo de dados relacional relativamente complexo, que registra metadados de arquivos, metadados de organizações, comentários, versões de arquivos e mais. Como não havia um único bom candidato no modelo de dados existente, consideraram usar a mesma chave de sharding para todas as tabelas, mas isso teria exigido criar chaves compostas para adicionar uma chave de sharding unificada, adicionar colunas a todos os esquemas de tabela, executar backfills caros para preenchê-las e, depois, refatorar consideravelmente a lógica do produto. Em vez disso, personalizaram a abordagem para o modelo de dados único da Figma e escolheram um pequeno número de chaves de sharding, como UserID, FileID e OrgID. Quase todas as tabelas da Figma podem ser shardadas usando uma dessas chaves.
  • Introdução dos Colos: introduziram o conceito de colocation para fornecer uma abstração amigável aos desenvolvedores de produto. Tabelas dentro de um colo oferecem suporte a joins entre tabelas e transações completas quando limitadas a uma única chave de sharding. A maior parte do código da aplicação já interagia com o banco de dados dessa forma, minimizando o trabalho necessário dos desenvolvedores para adaptar as tabelas ao sharding horizontal.
  • Garantindo uniformidade na distribuição dos dados: depois de escolher a chave de sharding, é preciso garantir uma distribuição uniforme dos dados entre todos os bancos de dados de backend. Infelizmente, muitas das chaves de sharding escolhidas usam IDs auto-incrementais ou IDs com prefixo de timestamp Snowflake. Isso teria criado hotspots significativos, com a maior parte dos dados concentrada em um único shard. Exploraram uma migração para IDs mais aleatórios, mas isso exigiria uma migração de dados cara e demorada. Em vez disso, decidiram usar um hash da chave de sharding para o roteamento. Se você escolher uma função de hash suficientemente aleatória, é possível garantir uma distribuição uniforme dos dados. Uma desvantagem é que varreduras por intervalo na chave de shard ficam menos eficientes, porque chaves consecutivas são transformadas por hash para shards de banco de dados diferentes. No entanto, como esse padrão de consulta não é comum na base de código, foi um compromisso aceitável.

A solução “lógica”

  • Reduzindo o risco do lançamento do sharding horizontal: para reduzir o risco de lançar o sharding horizontal, quiseram separar o processo físico de divisão de shards do processo de preparação das tabelas na camada de aplicação. Para isso, separaram “sharding lógico” de “sharding físico”. Assim, puderam dividir a migração em duas partes, implementá-las de forma independente e reduzir o risco. O sharding lógico trouxe confiança à stack de serving por meio de lançamentos graduais e de baixo risco. Quando encontravam bugs, reverter o sharding lógico era apenas uma simples mudança de configuração. Reverter o trabalho de shard físico também era possível, mas exigia uma coordenação mais complexa para garantir a consistência dos dados.
  • Comportamento após o sharding lógico: quando uma tabela é shardada logicamente, todas as operações de leitura e escrita já passam a funcionar como se houvesse sharding horizontal. Em termos de confiabilidade, latência e consistência, tudo se comporta como em um ambiente shardado horizontalmente, mas os dados ainda permanecem fisicamente em um único host de banco de dados. Quando ganharam confiança de que o sharding lógico funcionava como esperado, então executaram o trabalho de sharding físico. Isso envolve copiar os dados de um único banco para vários backends shardados e, em seguida, redirecionar novamente o tráfego de leitura e escrita para os novos bancos de dados.

Um motor de consultas de verdade

  • Redesenho da stack de backend para suportar sharding horizontal: no início, os serviços de aplicação se comunicavam diretamente com o PGBouncer, a camada de pool de conexões. No entanto, o sharding horizontal exige parsing, planejamento e execução de consultas muito mais complexos. Para dar suporte a isso, construíram um novo serviço em golang chamado DBProxy. O DBProxy fica entre a camada de aplicação e o PGBouncer. Ele contém lógica para balanceamento de carga, melhor observabilidade, suporte a transações, gerenciamento da topologia do banco de dados e um motor de consultas leve.
  • Componentes centrais do motor de consultas:
    • Parser de consultas: lê o SQL enviado pela aplicação e o converte em uma árvore sintática abstrata (AST).
    • Planejador lógico: analisa a AST e extrai do plano de consulta o tipo de consulta (insert, update etc.) e o ID do shard lógico.
    • Planejador físico: mapeia a consulta do ID de shard lógico para o banco de dados físico. Reescreve a consulta para executá-la no shard físico apropriado.
  • Abordagem “scatter-gather”: funciona como um jogo de esconde-esconde em todo o banco de dados: envia a consulta para todos os shards (dispersão) e reúne as respostas de cada um (coleta). Parece divertido, mas, se for usado em excesso com consultas complexas, pode fazer o banco ficar lento como uma lesma.
  • Implementação de consultas em um mundo com sharding horizontal: consultas de shard único são filtradas por uma única chave de shard. O motor de consultas só precisa extrair essa chave e rotear a consulta para o banco de dados físico adequado. Ele “empurra para baixo” a complexidade da execução da consulta para o Postgres. No entanto, quando a chave de sharding está ausente da consulta, o motor precisa realizar um processo mais complexo de “scatter-gather”. Nesse caso, ele precisa distribuir a consulta para todos os shards (fase de dispersão) e depois agregar os resultados (fase de coleta).
  • Simplificando a compatibilidade com SQL: se o serviço DBProxy desse suporte à compatibilidade total com SQL, ele teria ficado muito parecido com o motor de consultas do banco de dados Postgres. Queriam simplificar a API para minimizar a complexidade do DBProxy e reduzir o trabalho dos desenvolvedores de aplicação de reescrever consultas não suportadas. Para decidir qual subconjunto era apropriado, construíram uma estrutura de “planejamento sombra” capaz de definir esquemas potenciais de sharding das tabelas e executar a etapa de planejamento lógico sobre o tráfego real de produção em tempo real. É possível registrar as consultas e seus respectivos planos de consulta em um banco de dados Snowflake para rodar análises offline. A partir desses dados, escolheram uma linguagem de consultas que suporta os 90% mais comuns das consultas, evitando ao mesmo tempo a complexidade de pior caso do motor de consultas. Por exemplo, todas as varreduras por intervalo e consultas pontuais são permitidas, mas joins só são permitidos entre duas tabelas do mesmo colo quando feitos sobre a chave de sharding.

Perspectivas futuras

  • Encapsulamento de shards lógicos: foi preciso decidir como encapsular os shards lógicos. A equipe explorou particionar os dados usando um banco de dados Postgres separado ou um schema Postgres. Infelizmente, isso exigia alterações físicas nos dados ao fazer o sharding lógico, o que era tão complexo quanto uma divisão de shard físico.
  • Representação de shards por meio de views do Postgres: em vez disso, decidiu-se representar os shards como views do Postgres. É possível criar várias views para cada tabela, e cada uma corresponde a um subconjunto dos dados de um determinado shard. Isso tem a seguinte forma: CREATE VIEW table_shard1 AS SELECT * FROM table WHERE hash(shard_key) >= min_shard_range AND hash(shard_key) < max_shard_range). Todas as operações de leitura e escrita são feitas por meio dessas views.
  • Criação de views shardeadas sobre um banco de dados físico existente sem sharding: isso permitiu fazer o sharding de forma lógica antes de executar uma operação arriscada de resharding físico. Cada view é acessada por meio de seu próprio serviço de connection pooler shardeado. O connection pooler ainda aponta para a instância física não shardeada, fazendo com que ela pareça shardeada. Por meio de feature flags no mecanismo de consultas, foi possível lançar gradualmente leituras e escritas shardeadas para reduzir o risco e fazer rollback a qualquer momento em poucos segundos, redirecionando o tráfego de volta para a tabela principal. Até a execução do primeiro reshard, já era possível ter confiança na segurança da topologia shardeada.
  • Riscos de depender de views: views adicionam overhead de desempenho e, em alguns casos, podem mudar de forma fundamental como o query planner do Postgres otimiza as consultas. Para validar essa abordagem, a equipe coletou um corpus de consultas sanitizadas de produção e executou testes de carga com e sem o uso de views. Confirmou-se que, na maioria dos casos, as views adicionavam apenas overhead mínimo de desempenho e, mesmo no pior caso, ficavam abaixo de 10%. Também foi criado um framework de shadow reads que enviava todo o tráfego de leitura em tempo real pelas views e comparava desempenho e correção entre consultas com e sem views. Como resultado, confirmou-se que as views eram uma solução viável com impacto mínimo de desempenho.

Resolvendo o problema de topologia

  • Entendimento da topologia pelo DBProxy para roteamento de consultas: era necessário que tabelas e bancos de dados físicos fossem compreendidos em termos de topologia. Como os conceitos de sharding lógico e físico foram separados, surgiu a necessidade de uma forma de representar essas abstrações dentro da topologia.
  • Mapeamento de tabelas e chaves de shard: era necessário definir como mapear a tabela users para a chave de shard user_id e como mapear um ID de shard lógico (123) para os bancos de dados lógico e físico apropriados.
  • Particionamento vertical e dependência de arquivos de configuração hardcoded: no particionamento vertical, a equipe dependia de arquivos de configuração simples e hardcoded que mapeavam tabelas para suas respectivas partições. A transição para sharding horizontal exigiu um sistema mais complexo.
  • Mudanças dinâmicas na topologia e necessidade de atualização rápida de estado no DBProxy: durante a divisão de shards, a topologia mudava dinamicamente, exigindo que o DBProxy atualizasse rapidamente seu estado para evitar roteamento de requisições ao banco de dados errado.
  • Retrocompatibilidade das mudanças de topologia: todas as mudanças de topologia precisavam ser retrocompatíveis, evitando alterações em caminhos críticos do site.
  • Construção de uma topologia de banco de dados que encapsula metadados complexos de sharding horizontal: foi construída uma topologia de banco de dados que encapsula metadados complexos de sharding horizontal e fornece atualizações em tempo real em menos de 1 segundo.
  • Simplificação da gestão do banco de dados por meio da separação entre topologia lógica e física: foi possível reduzir custos e complexidade ao manter em ambientes não produtivos a mesma topologia lógica da produção, mas com menos bancos de dados físicos.
  • Garantia de invariantes na topologia por meio de uma biblioteca de topologia: a equipe manteve a correção do sistema ao implementar sharding horizontal, impondo invariantes na topologia, como exigir que todo ID de shard seja mapeado para exatamente um banco de dados físico.

Operações de sharding físico

  • Etapa final após preparar a tabela para sharding: o último passo foi fazer o failover físico de um banco de dados não shardeado para um banco de dados shardeado. Embora grande parte da mesma lógica pudesse ser reutilizada para o sharding horizontal, havia algumas diferenças importantes, como a passagem de uma relação 1 para 1 para uma relação 1 para N.
  • Necessidade de aumentar a resiliência do processo de failover: foi necessário tornar o processo de failover mais resiliente para lidar com novos modos de falha, nos quais a operação de sharding poderia ter sucesso apenas em partes do banco de dados.
  • Maioria dos riscos já mitigada durante o particionamento vertical: como muitos dos riscos já haviam sido mitigados no particionamento vertical, foi possível avançar para a primeira operação de sharding físico muito mais rapidamente do que seria possível de outra forma.

Onde está hoje a jornada de sharding horizontal

  • Investimento de vários anos em sharding horizontal: após reconhecer que seria necessário um investimento de vários anos em sharding horizontal para a escalabilidade futura da Figma, a primeira tabela com sharding horizontal foi lançada em setembro de 2023.
  • Execução bem-sucedida do failover: foi alcançado um failover bem-sucedido, com 10 segundos de disponibilidade parcial temporária no primário do banco de dados e nenhum impacto de disponibilidade nos réplicas. Após o sharding, não houve regressão em latência nem em disponibilidade.
  • Tratamento de shards complexos: foi tratado um shard relativamente simples do banco de dados com maior taxa de escrita. Neste ano, está previsto o sharding de bancos de dados progressivamente mais complexos, com dezenas de tabelas e milhares de pontos de chamada no código.
  • Necessidade de sharding horizontal para todas as tabelas da Figma: isso é necessário para remover o último gargalo de escalabilidade e permitir um verdadeiro escape velocity. Um ambiente totalmente shardeado horizontalmente oferece vários benefícios, como maior confiabilidade, redução de custos e aumento da velocidade dos desenvolvedores.
  • Problemas que ainda precisam ser resolvidos:
    • Suporte a atualizações de schema com sharding horizontal
    • Geração de IDs globalmente únicos para chaves primárias shardeadas horizontalmente
    • Transações atômicas entre shards para casos de uso críticos para o negócio
    • Índices distribuídos globalmente únicos (atualmente suportados apenas em índices que incluem a chave de shard)
    • Maior velocidade para desenvolvedores com modelos de ORM compatíveis de forma transparente com sharding horizontal
    • Operações de reshard totalmente automatizadas, capazes de executar uma divisão de shard com o clique de um botão
  • Reavaliação da abordagem atual de sharding horizontal no RDS: a jornada começou há 18 meses sob uma pressão muito forte de cronograma. Com a evolução e o amadurecimento contínuos dos stores NewSQL, agora há espaço suficiente para reavaliar os trade-offs entre manter o caminho atual e migrar para uma solução open source ou gerenciada.
  • Avanços empolgantes na jornada de sharding horizontal: ainda há muitos desafios a resolver, e a jornada está apenas no começo. A expectativa é compartilhar análises mais profundas sobre várias partes da stack de sharding horizontal. Quem tiver interesse em projetos como esse é incentivado a entrar em contato. A empresa está contratando.

Opinião do GN⁺

  • A equipe de banco de dados da Figma buscou superar os limites de escalabilidade do banco de dados por meio de sharding horizontal, um passo importante para sustentar o crescimento e o desempenho de uma ferramenta de colaboração baseada em nuvem.
  • O sharding horizontal traz novos desafios em gestão de dados e otimização de consultas, exigindo novos conhecimentos e habilidades de administradores de banco de dados e desenvolvedores.
  • Embora o sharding horizontal aumente significativamente a escalabilidade do banco de dados, ele também exige novas soluções para lidar com consultas complexas e manter a consistência dos dados.
  • Um projeto open source que oferece funcionalidade semelhante é o CitusDB, que permite escalar horizontalmente bancos de dados Postgres.
  • Ao adotar tecnologias de sharding horizontal, é preciso considerar a complexidade do modelo de dados, o desempenho das consultas, a flexibilidade do sistema e os aspectos de manutenção, o que significa buscar equilíbrio entre escalabilidade do banco de dados e facilidade de gestão.

1 comentários

 
GN⁺ 2024-03-15
Comentários do Hacker News
  • Tabelas muito grandes e limite de IOPS do RDS

    • Foi mencionado que a maior tabela chega a vários TB e em breve deve ultrapassar o máximo de IOPS suportado pelo RDS.
    • O RDS para PostgreSQL chega a no máximo 256.000 IOPS em um volume de 64 TB.
    • Em uma configuração multi-AZ, isso gera um custo de $70 mil por mês.
  • Resultado do sharding e custos

    • No fim, considera-se um sharding em 5 partes, com cada shard suportando cerca de 50.000 IOPS e 12 TB de dados.
    • Em uma configuração multi-AZ, isso gera um custo de $100 mil por mês.
  • Tempo e custo gastos com o sharding

    • Levaram 9 meses para fazer o sharding da primeira tabela.
    • Como também foram necessárias mudanças na aplicação, o cálculo fica em 9 meses * 20 dias úteis/mês * (3 engenheiros de banco de dados + 2 engenheiros de aplicação) = 900 dias de trabalho.
    • Supondo um salário médio anual de $100 mil por engenheiro, o custo total fica em cerca de $400 mil.
  • Comparação de custos com o YugabyteDB

    • O YugabyteDB, um NewSQL compatível com PostgreSQL, teria um custo estimado de $15 mil por mês para igualar o desempenho máximo do RDS.
    • A Figma gastou internamente cerca de 25 vezes mais ($400 mil/$15 mil) para implementar sharding horizontal e ainda continua usando RDS, que por sua vez custa cerca de 6 vezes mais ($100 mil/$15 mil).
  • Sugestão de separar o banco por cliente

    • Sugere-se que talvez fosse mais fácil colocar cada cliente em um banco de dados separado (lógico).
    • Como não há necessidade de transações entre clientes diferentes, parece que estão resolvendo um problema mais difícil do que o real.
    • Não está claro se os bancos de dados (lógicos) do PostgreSQL escalariam bem, mas em princípio isso não é impossível.
  • Construção de uma versão para PG semelhante ao Vitess do MySQL

    • A reescrita de queries parece interessante.
    • Colocar uma camada entre o banco e a aplicação também permitiria vários ACLs (listas de controle de acesso).
  • Consideração sobre o FoundationDB

    • Há curiosidade sobre por que não tentaram o FoundationDB.
    • Havia problemas com o vacuuming (coleta de lixo) do PostgreSQL.
    • Em versões anteriores, o vacuuming exigia o dobro de espaço, mas isso pode ter mudado nas versões mais recentes.
  • Abordagem que trata sharding como um hack

    • É melhor depender das APIs do sistema operacional do que lidar diretamente com buffering/caching de I/O em baixo nível.
    • Ainda existe a percepção de que faltam técnicas e infraestrutura equivalentes para sharding de banco de dados.
  • Dúvida sobre não usar a extensão Citus

    • O Citus já é uma extensão madura do Postgres, mas não foi mencionado no artigo.
    • Talvez não conhecessem o Citus ou o tenham ignorado por algum motivo específico.
  • Possibilidade de usar Aurora Limitless

    • Pergunta-se se seria possível usar o Amazon Aurora Limitless.
  • Entendimento sobre bancos de dados NoSQL

    • NoSQL é adequado para backends que acomodam dados não estruturados quando não é necessário um modelo relacional complexo.
    • O Postgres oferece suporte a isso com o tipo de dado jsonb, mas como eles já têm um bom modelo de dados, não há tanta necessidade de usá-lo.
  • Maturidade do sharding e consideração de soluções NewSQL

    • Com o sharding já mais maduro, questiona-se se vale a pena considerar soluções NewSQL para sharding automático e suporte multi-região.
    • Aprender a operar um banco de dados NewSQL também representa um custo adicional.
  • Tecnologia Spanner do Google e a avaliação da Figma

    • No Google, o Spanner é visto como uma tecnologia quase mágica, com sharding horizontal infinito e suporte a transações, e quase todos os projetos estão migrando para o Spanner.
    • Expressa-se curiosidade sobre como a Figma avaliou o Cloud Spanner e se, com seu esquema horizontal de Postgres, acabou abrindo mão do suporte real a transações, mesmo que temporariamente.