OpenAI

23 de outubro de 2026

Engenharia

Escalando o armazenamento online para mais de 1 bilhão de usuários do ChatGPT (Parte II)

Como otimizamos o Azure Cosmos DB no Habitat, nossa plataforma de armazenamento de aplicações, para lidar com um crescimento sem precedentes.

Por Jon Lee, Hrachya Hakobyan e Chaomin Yu, membros da equipe técnica

Carregando…

Todos os produtos da OpenAI precisam de acesso rápido e confiável aos dados, fornecido pela nossa plataforma de armazenamento, o Habitat. Ela precisa responder em milissegundos a mais de 1 bilhão de usuários em 40 regiões geográficas. Nossa infraestrutura enfrentou um desafio extraordinário: sustentar um crescimento explosivo e novos casos de uso, sem deixar de melhorar a confiabilidade, o desempenho e a velocidade de desenvolvimento de produtos. Superar esse desafio exigiu repensar o projeto e a operação da nossa plataforma de armazenamento online. Avaliávamos constantemente as escolhas e concessões, seguindo esta ordem: primeiro, alcançar a confiabilidade necessária para o tráfego crítico dos produtos; depois, a velocidade exigida por usuários no mundo todo; e, por fim, operar com eficiência em escala massiva.

Esta série em duas partes explica como transformamos o Habitat de uma simples biblioteca cliente com um banco de dados em uma plataforma de armazenamento distribuída globalmente, que disponibiliza mais de 500 petabytes de dados. A Parte I abordou a evolução do Habitat de um cliente Python para um serviço. Também apresentou as técnicas que nos permitiram levar um serviço baseado em Python muito além do que muitos considerariam viável.

Neste artigo, a Parte II, mostramos como ampliamos a escala do componente de armazenamento subjacente: o Azure Cosmos DB. Em estreita parceria com a equipe do Azure, chegamos a uma abordagem multilocatária viável, com contêineres gerenciados em conjunto e excelente desempenho de leitura em escala global massiva.

Figura 01 · O que é o Habitat?

Plataforma de armazenamento online

O Habitat é a plataforma de armazenamento online que criamos para os produtos da OpenAI acessarem as informações necessárias com rapidez e confiabilidade.

  • Solicitação
  • Resposta
  • Alterações (CDC)

Clientes

Plataforma de armazenamento online

Recursos de armazenamento

  • ChatGPT
  • API
  • Codex
  • Serviços internos
  • E muito mais

Habitat

  • CacheCaches
  • Políticas de ACLAutorização
  • Posicionamento e residência de dadosResidência de dados
  • CriptografiaSegurança de dados
  • IsolamentoMultilocação
  • Limitação de taxaFormatação de solicitações
  • RoteamentoConsulta de schema · Residência de dados
  • Azure Cosmos DBArmazenamento online
  • NanobaseArmazenamento online
  • ValkeyCaches
  • Armazenamento de blobsRecursos de armazenamento
Serviços de CDCCaptura de dados de alteração
  • Databricks
  • Rockset
  • Kafka
  • E muito mais

Tornando a arquitetura multilocatária confiável em escala

À medida que as empresas crescem, as equipes de infraestrutura costumam migrar de sistemas de locatário único para sistemas multilocatários. Na arquitetura de locatário único, cada equipe responsável por uma área do produto mantém seu próprio sistema. Isso reduz o alcance das falhas e facilita a delimitação de responsabilidades e o isolamento de cargas. À medida que as equipes e as áreas do produto crescem, essa operação fica cara. A arquitetura de locatário único torna cada equipe de produto responsável pelo planejamento de capacidade e frequentemente resulta em um grande excesso de recursos provisionados.

Já a arquitetura multilocatária atribui o controle a uma equipe centralizada de banco de dados, com mais conhecimento e experiência para provisionar recursos. Mas ela traz seus próprios problemas, como os vizinhos ruidosos: um locatário consome uma parcela excepcionalmente grande dos recursos, prejudicando os demais.

No Habitat, tivemos que ponderar todas essas escolhas para projetar um sistema de armazenamento confiável e eficiente em escala. Hoje, o Habitat é uma camada de banco de dados multilocatária para muitos produtos da OpenAI. Mas percorremos um caminho circular: começamos com um contêiner multilocatário do Azure Cosmos DB, passamos a provisionar contêineres de armazenamento de locatário único e voltamos a usar um contêiner multilocatário por padrão. Nossa jornada com a arquitetura multilocatária no Habitat ainda está no início: atendemos a muitos casos de uso, mas conseguimos adiar investimentos nessa área aproveitando, sempre que possível, as primitivas nativas do Azure Cosmos DB.

Uma introdução simplificada aos contêineres do Azure Cosmos DB

Antes de percorrermos nossa jornada com o Azure Cosmos DB, alguns conceitos básicos:

  • Uma conta do Azure Cosmos DB define um conjunto de contêineres e uma política de replicação

  • Cada contêiner é provisionado para uma determinada taxa de processamento, em unidades de requisição por segundo (RU/s)

  • Os dados de cada contêiner são distribuídos em shards conforme uma chave de partição lógica especificada, com limites documentados de armazenamento e taxa de processamento por chave de partição lógica

  • O Azure Cosmos DB distribui as chaves de partição lógica entre um número menor de partições físicas subjacentes. Ele divide essas partições físicas quando o armazenamento supera um limite ou quando o contêiner precisa de mais partições físicas para sustentar a taxa de processamento provisionada

Fase I: Usando as primitivas do Azure Cosmos DB

Originalmente, aceitávamos toda a carga dos clientes, contando com o limite declarado de 10 mil RU/s por chave de partição lógica para exercer contrapressão. No início, também usávamos apenas um contêiner padrão do Azure Cosmos DB em cada conta. Isso funcionava razoavelmente bem, mas se mostrou problemático por alguns motivos:

Limites das chaves de partição lógica

Devido a decisões iniciais de API, expusemos a seleção da chave de partição lógica diretamente aos clientes. Como resultado, temos colisões frequentes em chaves de partição muito usadas, como user_id ou workspace_id, entre diferentes casos de uso dos produtos. Como esses casos de uso compartilhavam os limites do Azure Cosmos DB nas mesmas chaves de partição lógica, o projeto restringia a taxa de processamento total de cada usuário.

Antes de migrarmos para o Habitat e o Azure Cosmos DB, um problema comum ao ampliar o Postgres era que muitas requisições de uma organização ou chave muito acessada — um locatário gerando carga desproporcionalmente alta — podiam derrubar todo o banco de dados. Dedicamos um esforço coletivo significativo para armazenar essas chaves em cache e incorporar mecanismos de lease às consultas sem resultado no cache, evitando que a carga resultante sobrecarregasse o banco de dados subjacente.

Figure 02a · Logical partition key limits

Different clients, the same partition key

Cosmos DB containerPhysical partitionPK: user-id-28104CapacityMemory / dreaming : capacity usedMemory / dreaming : capacity usedMemory / dreaming : capacity usedMemory / dreaming : capacity usedMemory / dreaming : capacity usedMemory / dreaming : capacity usedMemory / dreaming : capacity usedMemory / dreaming : capacity usedMemory / dreaming : capacity usedMemory / dreaming : capacity usedConversationsSuccess rateResponses returned in this animation loop—AuthSuccess rateResponses returned in this animation loop—Memory / dreamingSuccess rateResponses returned in this animation loop—

Vizinhos ruidosos

Embora os limites documentados de tamanho dos dados e taxa de processamento se apliquem às chaves de partição lógica, é na partição física que esses limites são de fato impostos. Na prática, isso significa que as partições lógicas não conseguem atingir 10.000 RU/s. Em vez disso, elas compartilham os limites da partição física com todas as outras chaves de partição lógica alocadas nela.

Isso permitia que vizinhos ruidosos afetassem muitas chaves de partição lógica sem relação entre si: cargas que operavam sobre dados de funcionalidades de nicho prejudicavam fluxos essenciais de login e cadastro.

Figure 02b · Noisy neighbors

Different users, the same physical partition

Cosmos DB containerPhysical partitionPKs: user-id-28104, user-id-10384Conversations user-id-28104: capacity usedConversations user-id-28104: capacity usedConversations user-id-28104: capacity usedConversations user-id-28104: capacity usedConversations user-id-28104: capacity usedConversations user-id-28104: capacity usedConversations user-id-28104: capacity usedConversations user-id-28104: capacity usedConversations user-id-28104: capacity usedConversations user-id-28104: capacity usedConversationsuser-id-28104Success rateResponses returned in this animation loop—Conversationsuser-id-10384Success rateResponses returned in this animation loop—

Partições fracas

O limite da taxa de processamento de uma partição física também varia conforme a taxa de processamento total atribuída ao contêiner do Azure Cosmos DB. A taxa de processamento provisionada do contêiner é distribuída de maneira aproximadamente uniforme entre suas partições físicas.

À medida que o volume de dados cresce, as partições físicas se dividem, aumentando o número total de partições, enquanto a taxa de processamento total provisionada permanece inalterada. Como resultado, o limite efetivo da taxa de processamento por partição diminui à medida que o volume de dados cresce.

Nos casos de uso que mais exigem armazenamento, com dados semelhantes a blobs, isso cria uma condição de falha: o crescimento do armazenamento, por si só, reduz a taxa de processamento disponível para cargas ativas, mesmo quando as taxas de requisições e o uso permanecem estáveis.

Figure 02C · Weak partitions

The limit falls below demand

A partition splits when it reaches its storage limit. Each child receives half the throughput capacity.

Before split: 10K RU/s capacity

After split: 5K RU/s capacity × 2 partitions

RU/s05K6K10K200200429

Fase II: Testando o isolamento de cargas e a arquitetura de locatário único

Contêineres separados ajudam a resolver parcialmente esses limites de chave de partição e o problema dos vizinhos ruidosos. Com contêineres separados, cada um pode receber partições físicas independentes, e apenas as cargas dentro do próprio contêiner podem ser vizinhos ruidosos ou ter sobreposição no espaço de chaves de partição. Por outro lado, provisionar novos contêineres tem um custo operacional: cada um exige planejamento de capacidade individualizado. Por isso, queremos criá-los apenas quando a separação por serviço ou caso de uso fizer sentido.

Começamos a usar contêineres separados do Azure Cosmos DB para os novos casos de uso mais críticos que exigiam isolamento rigoroso. Combinando isso com um script para gerenciar partições fracas, que sincronizava a taxa de processamento total provisionada de cada contêiner com seu número de partições físicas, evitamos a maior parte dos problemas que enfrentávamos.

No entanto, como começamos com um contêiner padrão, muitos casos de uso críticos legados infelizmente continuavam presos a ele, dependendo de uma migração de dados. Para proteger serviços críticos que ainda dependiam dos dados no contêiner padrão compartilhado, frequentemente orientávamos as equipes a criar contêineres separados para novos serviços ou funcionalidades importantes. À medida que ganhávamos escala, a pressão sobre o contêiner padrão aumentava, assim como os incidentes em produção. Passamos a provisionar contêineres para qualquer novo serviço ou grande funcionalidade de produto, apenas para proteger o contêiner padrão de mais carga.

Isso nos poupou de muitas indisponibilidades gerais, restringindo o impacto a falhas e degradações de funcionalidades ou serviços específicos. Porém, o custo operacional de provisionar novos contêineres acabou se tornando um problema:

Falta de crescimento agregado estável

No antigo contêiner padrão compartilhado, era improvável que um novo caso de uso que passasse de 0 a 1 milhão de QPS alterasse significativamente o uso agregado total. Em um contêiner isolado, porém, um novo caso de uso que passasse de 0 a 1 milhão de QPS poderia representar uma carga 1.000 vezes maior que a carga de referência gerada apenas pelo uso interno do produto.

Com contêineres dedicados, as equipes precisavam se lembrar de provisioná-los antecipadamente para a taxa de processamento esperada em seus lançamentos. As equipes de produto muitas vezes colocavam funcionalidades em produção sem ampliar a capacidade antes. No dia do lançamento, acabávamos em salas de resposta a incidentes, tentando ampliar os contêineres de última hora.

A combinação de cargas é um benefício central dos sistemas multilocatários que perdemos em troca de maior isolamento com essa estratégia de contêineres.

Figure 03 · Lack of stable aggregate growth

The same workload, different headroom

1K RU/s during load testing → 1M RU/s at launch

Shared container

100M RU/s capacity · 80% utilized

Load test

1K20M=

0.005%

of headroom

Launch

1M20M=

5%

of headroom

New dedicated container

10K RU/s capacity · no other workloads

Load test

1K10K=

10%

of headroom

Launch

1M10K=

10,000%

of headroom

Planejamento de capacidade

Com o tempo, monitorar o uso dos contêineres dedicados também passou a exigir conhecimento profundo dos produtos para prever quando o tráfego mudaria ou cresceria.

Podemos fornecer um script básico do plano de controle para ampliar a taxa de processamento provisionada de cada contêiner conforme as tendências de crescimento. Mas, sem um crescimento agregado estável, dimensioná-los corretamente acabou envolvendo praticamente todas as equipes de produto da OpenAI no planejamento de capacidade.

Isso não se sustentou com o crescimento da organização, pois o cuidado de cada equipe responsável com o provisionamento do Azure Cosmos DB variava muito.

Fase III: Arquitetura multilocatária por padrão, com capacidade de movimentar dados

À medida que a organização crescia, esses problemas operacionais dificultavam a expansão. Sem uma única equipe central responsável pelo planejamento, muitas equipes acabavam planejando mal. Por isso, voltamos a uma solução multilocatária e trabalhamos em estreita colaboração com a equipe do Azure para corrigir os problemas originais, com um projeto de locação compartilhada:

Limitação de requisições para chaves muito acessadas

Limitar primeiro as requisições às chaves mais acessadas impede que vizinhos ruidosos consumam toda a taxa de processamento disponível de uma partição física. Isso reduz o efeito de vizinho ruidoso, em que uma única chave muito acessada pode afetar todo o serviço.

Qualidade de Serviço (QoS)

Da mesma forma, a QoS com classificação de requisições por níveis impede que cargas offline, como inserções em massa ou extrações de dados, consumam toda a taxa de processamento de uma partição física. Ao atribuir prioridade menor às requisições dessas cargas, elas são limitadas primeiro, evitando a limitação de requisições interativas de maior prioridade que atendem aos usuários finais.

Modo sem servidor

O Azure Cosmos DB já tinha um modo sem servidor que teria resolvido nosso problema de partições fracas no modo provisionado. Porém, havia uma grande desvantagem: ele escalava apenas com base no uso de armazenamento e limitava o consumo de RU a 5 mil RU/s por partição física. Isso resolveria o problema das partições fracas, mas nos impediria de ampliar casos de uso com alto consumo de RU.

A equipe do Azure Cosmos DB criou para nós um modo sem servidor aprimorado, que permitiu a cada partição física escalar até 10 mil RU/s e introduziu divisões baseadas no consumo de RU, além das baseadas no uso de armazenamento. Com isso, deixamos de monitorar e ampliar contêineres manualmente.

Com essas mudanças, voltamos a usar um único contêiner compartilhado. Isso simplificou significativamente o planejamento de capacidade inicial e contínuo das equipes de produto, preservando o isolamento entre cargas. Nos meses seguintes, não tivemos nenhum incidente de provisionamento ou de vizinhos ruidosos, apesar da aceleração no desenvolvimento de produtos.

Mais confiabilidade com serviços gerenciados em conjunto

Quando as empresas atingem a escala da OpenAI, os serviços gerenciados ficam menos "gerenciados". Muitas cargas de trabalho passam a fugir do padrão da infraestrutura do provedor de nuvem. À medida que a OpenAI se tornou uma das maiores usuárias do Azure Cosmos DB, operá-lo com sucesso exigiu outra abordagem: testes e painéis compartilhados, canais diretos entre equipes de engenharia e responsabilidade conjunta por falhas que só surgem na nossa escala. Hoje, nossa maior conta do Azure Cosmos DB armazena dezenas de petabytes de dados e atende a mais de 20 milhões de QPS. Até onde sabemos, somos a única empresa que implantou o Azure Cosmos DB nessa escala.

No fim de 2024, uma indisponibilidade regional deixou claro por que essa colaboração era necessária. Na ocasião, uma queda de energia atingiu a região primária do Azure de uma das nossas maiores contas do Azure Cosmos DB. Durante o failover resultante, percebemos que nossas maiores contas levariam várias horas para migrar para uma região secundária — algo que nem nossa equipe nem a do Azure Cosmos DB havia testado na nossa escala.

Cerca de um mês depois, ao retornar essas contas à região original, provocamos outra indisponibilidade grave. Uma avalanche de conexões com a região original sobrecarregou o gateway do Azure Cosmos DB dessa região. Uma peculiaridade no tratamento de failovers pelo cliente do Azure Cosmos DB em modo gateway fez com que todos os clientes estabelecessem conexões e enviassem requisições imediatamente à região original, embora apenas parte das partições físicas tivesse retornado a ela.

Em cada indisponibilidade, tanto a OpenAI quanto o Azure seguiram seus processos de gestão de incidentes, identificando várias causas raiz e implantando correções. Mas essas indisponibilidades eram sintomas de um problema sistêmico maior na forma como nossa equipe e a do Azure Cosmos DB operavam e testavam. No início, usar serviços gerenciados nos permitiu avançar rapidamente e focar nos objetivos de negócio. Em escala, os serviços gerenciados se tornam menos gerenciados e exigem integração profunda com o provedor em todos os níveis, do projeto à operação.

Hoje, as equipes de engenharia do Habitat e do Azure monitoram juntas todas as camadas do Habitat, desde nossos serviços até o armazenamento físico do Azure Cosmos DB. Operamos e testamos mudanças em uma conta do Azure Cosmos DB fora de produção, mas com o mesmo porte do ambiente de produção. Testamos e aprimoramos SDKs em conjunto e definimos as melhores práticas para ampliar e dimensionar nossas contas do Azure Cosmos DB. Temos contato direto entre as equipes de engenharia pelo Teams e até criamos meios de acionar diretamente os plantonistas uns dos outros, sem passar pelos níveis de suporte.

Ao longo do último ano, realizamos um amplo trabalho conjunto para melhorar a escalabilidade do plano de controle e do gateway do Azure Cosmos DB. Adicionamos proteção contra sobrecarga e cache de diversos metadados do Azure Cosmos DB no gateway para proteger a partição de metadados. Reduzimos a pressão dos nossos processos Python do habitat-service com pools de conexões e maior reutilização de conexões, colocamos cargas de trabalho na mesma região sempre que possível e isolamos cargas críticas das cargas offline usando VPCs diferentes.

Esse nível de colaboração em engenharia foi essencial para a estabilidade do nosso Azure Cosmos DB no último ano. Qualquer sistema suficientemente grande ou crítico exige esse tipo de trabalho em equipe: romper barreiras de responsabilidade e atuar além dos limites organizacionais.

Melhorando o desempenho em escala global

Como mencionamos na Parte I, nossa filosofia central é: primeiro fazer funcionar, depois acelerar e, por fim, reduzir custos. Primeiro confiabilidade, depois desempenho, depois eficiência. O Habitat havia se tornado uma infraestrutura crítica para a OpenAI, então a primeira prioridade era torná-lo confiável. À medida que o sistema se estabilizou em 2025 e a OpenAI se expandiu globalmente, a latência se tornou o próximo obstáculo para usuários e equipes de produto.

A capacidade de computação e a de armazenamento muitas vezes ficavam em regiões diferentes, tornando inevitáveis as requisições entre regiões.

Figure 04 · Improving performance at a global scale

Global traffic

Compute and storage capacity were often located in different regions, making cross-region requests unavoidable.

ComputeStorageIllustrative routes · Longer journeys take more time

As localizações geográficas dos recursos de computação e armazenamento são apenas ilustrativas.

A latência variava muito dependendo de onde os dados estavam armazenados e de onde a requisição era atendida. Para obter bom desempenho nas requisições ao Habitat, os desenvolvedores de produtos recorriam a cache adicional no cliente, agrupamento de requisições em lotes, redução de leituras e gravações no banco de dados e remoção de tarefas do caminho crítico sempre que possível. Embora isso tenha levado a alguns projetos de produto interessantes e mais resilientes a problemas no banco de dados, também aumentou a complexidade dos produtos e desacelerou sua evolução. Isso contrariava o objetivo do Habitat de promover o desenvolvimento rápido de produtos sem exigir conhecimento do banco de dados.

Esse tem sido um grande foco para nós em 2026. Desenvolvemos uma estratégia em camadas para otimizar o desempenho das leituras, que representam mais de 90% das requisições ao Habitat:

Armazenar dados perto dos usuários quando houver capacidade

Temos várias contas do Azure Cosmos DB em diferentes regiões do Azure ao redor do mundo para usuários com requisitos de residência de dados. Mesmo para usuários sem requisitos rígidos de residência de dados, armazenar os dados perto deles melhora a experiência ao reduzir a latência.

Na prática, não conseguimos fazer isso de forma ampla fora dos casos de residência de dados, porque a alocação é limitada pela capacidade física da nuvem. Devido ao tamanho dos nossos conjuntos de dados, muitas regiões não conseguem acomodar o enorme volume de armazenamento necessário para sua parcela proporcional do tráfego de usuários.

Em regiões com capacidade limitada de datacenter, energia ou refrigeração, às vezes precisamos escolher: reservar capacidade para armazenamento local e reduzir a latência do Habitat ou usá-la para ampliar a computação que atende às requisições e encaminhar as requisições de armazenamento para mais longe.

Assim, as decisões de alocação muitas vezes exigem que o produto equilibre: A) a otimização da latência para diferentes produtos e grupos de usuários e B) a capacidade bruta de armazenamento e computação.

Replicar amplamente apenas os conjuntos de dados menores e mais sensíveis à latência

Para as cargas de trabalho mais sensíveis à latência, como os metadados de autenticação necessários em toda requisição, reduzimos o tempo de ida e volta (RTT) entre a computação e o Habitat usando contas do Azure Cosmos DB com ampla replicação em muitas regiões secundárias. Algumas contas replicam dados para todas as 40 regiões do Azure onde atendemos tráfego; outras, para pelo menos uma região por continente.

Tivemos que incorporar ao Habitat uma camada transparente de movimentação e roteamento de dados antes do desejado, para poder mover conjuntos de dados entre contas com diferentes topologias de replicação.

No entanto, essa abordagem também está sujeita a restrições de capacidade e, por isso, se limita a alguns conjuntos de dados escolhidos criteriosamente.

Usar cache integrado para todo o restante

As cargas do Habitat são predominantemente de leitura, com aplicações buscando configurações, estados e outras propriedades a todo momento. Uma parcela desproporcional do tráfego vem de um conjunto relativamente pequeno de tipos acessados com frequência. Isso torna o sistema especialmente adequado ao uso de cache distribuído. Embora o cache melhore o desempenho em infraestruturas de uma única região, os ganhos se multiplicam em operações entre regiões, nas quais ele pode "ocultar" a latência entre elas.

Integramos ao Habitat uma camada de cache distribuído do tipo lookaside. Ela armazena cópias de objetos e arestas acessados recentemente em servidores Valkey na nossa infraestrutura, próximos de onde as requisições dos usuários são processadas. Em geral, esses caches usam um TTL que equilibra a taxa de acertos e a desatualização dos dados. TTLs curtos reduzem a desatualização, mas limitam os benefícios do cache, pois os itens expiram rapidamente e precisam ser buscados com mais frequência. TTLs mais longos aumentam a taxa de acertos, mas fornecem dados desatualizados por mais tempo, prejudicando a experiência do usuário e tornando o comportamento do produto imprevisível.

Outra abordagem é executar operações explícitas de invalidação quando a aplicação grava nos mesmos dados subjacentes. Isso mantém os dados em cache muito mais atualizados, mas pode ser difícil de implementar corretamente. Além disso, a abordagem continua sujeita a vários casos excepcionais, como falhas parciais, que deixam o cache desatualizado. Implantações em várias regiões agravam esses problemas: as redes entre regiões são menos confiáveis, e há condições de corrida entre o cache e a replicação do armazenamento subjacente. Complementar essa abordagem com TTLs limita a desatualização máxima, mas mantém o mesmo dilema dos TTLs discutido acima.

Adotamos uma abordagem mais avançada de invalidação, seguindo o exemplo de sistemas como o TAO, da Meta. O cache integrado do Habitat usa captura de dados de alteração (CDC) pelo feed de alterações do Azure Cosmos DB para propagar invalidações globalmente em segundos, alcançando altas taxas de acerto com baixa desatualização. Um serviço na nossa infraestrutura consome esse feed e invalida os caches locais quando os dados subjacentes são atualizados. Assim, na próxima leitura, os dados não são encontrados no cache, que então é preenchido com a versão mais recente.

Reduzir o custo de processamento do proxy com Rust

Também reduzimos bastante a latência ao eliminar custos de processamento no próprio serviço Habitat, reescrevendo o código em Rust, que oferece mais desempenho que o Python original.

Juntas, essas mudanças reduziram nosso p50 global de leitura de cerca de 120 ms para cerca de 10 ms, uma melhoria de 12 vezes desde que começamos a focar em desempenho no início deste ano.

Figure 05 · Improving performance at a global scale

p50 latency for reads

Three major design changes improved read latency

roughly 120 ms → roughly 10 ms

12x improvement

Milliseconds020406080100120140160Tempo123
  1. critical data replicated into nearby geos
  2. in-region caching launched
  3. rust rewrite launched

Embora o cache tenha reduzido muito a latência mediana, as requisições mais lentas ainda precisam buscar dados fora do cache no armazenamento subjacente, muitas vezes em regiões distantes. À medida que disponibilizamos mais capacidade e melhoramos a eficiência do armazenamento, planejamos enfrentar um desafio mais fundamental: colocar os dados perto de onde serão acessados desde o início.

Escalando a captura de dados de alteração

Uma CDC confiável e escalável — que propaga alterações do banco de dados para sistemas dependentes — é essencial não apenas para a estratégia de cache do Habitat. Milhões de alterações capturadas por segundo, em milhares de contêineres e milhões de partições, passam por mais de cem tópicos Kafka. Elas também alimentam índices secundários com consistência eventual, pipelines de movimentação de dados, análises offline e outras funcionalidades de produto em tempo real. Com a expansão global da nossa infraestrutura subjacente, monitorar alterações nas linhas se tornou cada vez mais complexo. Se um cliente quiser registrar um callback para executar sempre que linhas do seu tipo forem alteradas, primeiro precisa, entre outras coisas, identificar quais contas e contêineres do Cosmos contêm seus dados e qual implantação do serviço de CDC monitora esses contêineres nas respectivas regiões. Também precisa dimensionar corretamente os workers do serviço de CDC, o Kafka e seu consumidor. Nossa plataforma de CDC busca abstrair tudo isso dos desenvolvedores de produtos e oferecer uma interface simples: os clientes registram uma função para ser chamada quando suas linhas mudarem, e nós cuidamos de toda a infraestrutura e do dimensionamento.

Um plano de controle interno garante continuamente a captura de todos os contêineres necessários, escolhe de quais regiões do Cosmos ler e distribui o trabalho com eficiência entre milhares de workers em várias regiões geográficas. O uso de regiões de réplica e de leituras do feed com prioridade menor protege o tráfego do Habitat sensível à latência contra as cargas de captura em segundo plano. Em um conjunto tão grande de workers, falhas nos workers, problemas em contêineres, erros no armazenamento de leases, configurações inválidas e falhas nos destinos ocorrem continuamente. Tornamos mais robustos o ciclo de vida dos workers de CDC e o gerenciamento de leases, isolamos falhas entre fluxos e criamos proteções para mudanças de configuração e implantações. Usamos filas de mensagens não entregues para evitar que falhas permanentes de entrega bloqueiem o início da fila. Toleramos indisponibilidades regionais redirecionando os leitores para outras regiões do Cosmos. Na nossa escala, tivemos até que modificar o SDK de CDC do Azure para tornar sua implementação de checkpoints mais eficiente, agrupando-os em memória e persistindo-os apenas periodicamente.

Embora o uso interno do Azure Cosmos DB pelo Habitat seja complexo, sua proposta de valor sempre foi abstrair os detalhes de infraestrutura dos desenvolvedores de produtos para acelerar o desenvolvimento. Nossa plataforma de CDC segue o mesmo princípio.

Olhando para o futuro

Uma equipe pequena conseguiu sustentar uma plataforma de armazenamento em rápido crescimento mantendo a API de armazenamento deliberadamente restrita, ampliando continuamente o serviço Python e priorizando os desafios de engenharia mais urgentes. Primeiro, focamos na confiabilidade para o tráfego crítico dos produtos; depois, no desempenho de leitura para usuários no mundo todo; e, por fim, na eficiência operacional em escala. Essa abordagem permitiu o crescimento rápido e novos casos de uso, ao mesmo tempo que melhorou a confiabilidade, o desempenho e a velocidade de desenvolvimento de produtos.

Para ampliar o Habitat e o armazenamento de conversas para o próximo bilhão de usuários, precisamos superar a dificuldade de replicar nossos dados por toda a infraestrutura em uma escala ainda maior. Para nos antecipar a isso, estamos desenvolvendo internamente um sistema próprio de armazenamento online em escala de exabytes, otimizado para os tipos de dados volumosos do Habitat. Esse sistema em desenvolvimento combina o núcleo RocksDB Cloud da Rockset com replicação baseada em Raft. Ele implementa o mesmo modelo de documentos do Azure Cosmos DB, mas usa armazenamento desagregado e replicação física para reduzir a capacidade de memória flash necessária, em troca de um pico menor de QPS.

Se você tem interesse em trabalhar com esses desafios de infraestrutura de dados em escala de fronteira, confira nossas vagas abertas⁠.

Autor

OpenAI