Orivel Orivel
Abrir menu

Projetar um Sistema de Notificações em Tempo Real para um Aplicativo de Mídia Social

Compare as respostas dos modelos para esta tarefa de benchmark em Design de sistemas e reveja pontuações, comentários e exemplos relacionados.

Entre ou cadastre-se para usar curtidas e favoritos. Cadastrar

X f L

Índice

Visão geral da tarefa

Gêneros de comparação

Design de sistemas

Modelo criador da tarefa

Modelos participantes

Modelos avaliadores

Enunciado da tarefa

Você é um engenheiro de software sênior encarregado de projetar um sistema de notificações em tempo real para um aplicativo de mídia social em rápido crescimento. O sistema precisa ser escalável, confiável e entregar notificações com baixa latência. Forneça uma proposta de design de sistema detalhada.

Informação complementar

O aplicativo de mídia social possui as seguintes características e requisitos:

Escala:

  • 10 milhões de Usuários Ativos Diários (DAU).
  • Cada usuário recebe em média 20 notificações por dia.
  • O tráfego de pico pode chegar a até 5 vezes o tráfego médio.

Requisitos Funcionais:

  • Tipos de Notificação: Curtidas, comentários, novos seguidores, mensagens diretas.
  • Entrega: As notificações devem ser entregues em quase tempo real (latência inferior a 2 segundos).
  • Canais: Suporte tanto p...
Mostrar mais

O aplicativo de mídia social possui as seguintes características e requisitos:

Escala:

  • 10 milhões de Usuários Ativos Diários (DAU).
  • Cada usuário recebe em média 20 notificações por dia.
  • O tráfego de pico pode chegar a até 5 vezes o tráfego médio.

Requisitos Funcionais:

  • Tipos de Notificação: Curtidas, comentários, novos seguidores, mensagens diretas.
  • Entrega: As notificações devem ser entregues em quase tempo real (latência inferior a 2 segundos).
  • Canais: Suporte tanto para push notifications dentro do app (para dispositivos móveis) quanto para notificações por e-mail.
  • Histórico: Os usuários devem poder visualizar suas últimas 100 notificações.
  • Preferências: Os usuários podem ativar/desativar tipos específicos de notificações.

Requisitos Não Funcionais:

  • Alta Disponibilidade: O sistema deve ser altamente disponível com tempo de inatividade mínimo.
  • Confiabilidade: Nenhuma notificação deve ser perdida.
  • Escalabilidade: A arquitetura deve poder escalar para suportar 100 milhões de DAU no futuro.
  • Custo-Efetividade: O design deve levar em conta os custos operacionais.

Sua proposta deve cobrir a arquitetura de alto nível, os componentes-chave, escolhas de tecnologia, modelo de dados e estratégias para garantir escalabilidade e confiabilidade. Certifique-se de explicar os trade-offs considerados em seu design.

Política de avaliação

Uma resposta de alta qualidade deve apresentar um design de sistema coerente e bem fundamentado. Avalie a resposta com base nos seguintes critérios:

  1. Architecture: A arquitetura de alto nível proposta é lógica e completa? Identifica claramente componentes principais como gateways de API, serviços de notificação, filas de mensagens, bancos de dados e serviços de push de terceiros?
  2. Technology Choices: As escolhas tecnológicas (por exemplo, Kafka vs. RabbitMQ, NoSQL vs. SQL, escolhas específicas de banc...
Mostrar mais

Uma resposta de alta qualidade deve apresentar um design de sistema coerente e bem fundamentado. Avalie a resposta com base nos seguintes critérios:

  1. Architecture: A arquitetura de alto nível proposta é lógica e completa? Identifica claramente componentes principais como gateways de API, serviços de notificação, filas de mensagens, bancos de dados e serviços de push de terceiros?
  2. Technology Choices: As escolhas tecnológicas (por exemplo, Kafka vs. RabbitMQ, NoSQL vs. SQL, escolhas específicas de banco de dados como Cassandra ou Redis) são apropriadas para os requisitos e as justificativas dessas escolhas são sólidas?
  3. Scalability and Reliability: O design aborda efetivamente como o sistema irá escalar para lidar com cargas de pico e crescimento futuro? Mecanismos para confiabilidade e tolerância a falhas, como tentativas de reenvio, dead-letter queues e replicação de banco de dados, estão claramente explicados?
  4. Trade-offs: A resposta demonstra um entendimento profundo dos princípios de design de sistemas discutindo explicitamente os trade-offs feitos (por exemplo, consistência vs. disponibilidade, custo vs. desempenho, mecanismos push vs. pull)?
  5. Completeness: O design aborda todos os requisitos funcionais e não funcionais especificados, incluindo histórico de notificações, preferências de usuário e múltiplos canais de entrega?

Respostas

Design de Sistema de Notificações em Tempo Real para um Aplicativo de Mídia Social

1. Recapitulação dos Requisitos e Estimativa Preliminar

Estimativa de Tráfego:

  • 10M DAU × 20 notificações/dia = 200M notificações/dia
  • Taxa média = 200M / 86.400s ≈ 2.315 notificações/seg
  • Taxa de pico (5x) ≈ 11.500 notificações/seg
  • A 100M DAU (futuro): média ~23.000/s, pico ~115.000/s

Estimativa de Armazenamento:

  • Cada registro de notificação ~500 bytes (metadados + payload)
  • Armazenamento diário: 200M × 500B = 100GB/dia → ~36TB/ano (antes de compressão/arquivamento)
  • Requisito de histórico (últimos 100 p...
Mostrar resposta completa

Design de Sistema de Notificações em Tempo Real para um Aplicativo de Mídia Social

1. Recapitulação dos Requisitos e Estimativa Preliminar

Estimativa de Tráfego:

  • 10M DAU × 20 notificações/dia = 200M notificações/dia
  • Taxa média = 200M / 86.400s ≈ 2.315 notificações/seg
  • Taxa de pico (5x) ≈ 11.500 notificações/seg
  • A 100M DAU (futuro): média ~23.000/s, pico ~115.000/s

Estimativa de Armazenamento:

  • Cada registro de notificação ~500 bytes (metadados + payload)
  • Armazenamento diário: 200M × 500B = 100GB/dia → ~36TB/ano (antes de compressão/arquivamento)
  • Requisito de histórico (últimos 100 por usuário) é um padrão de acesso "quente" com muitas leituras, favorecendo um design onde notificações recentes são baratas de buscar (por exemplo, lista limitada por usuário), enquanto o histórico completo vai para armazenamento frio.

Isso confirma que estamos lidando com um sistema intensivo em gravação, intensivo em fan-out, sensível à latência que deve desacoplar a ingestão da entrega.


2. Arquitetura de Alto Nível

[Produtores de Eventos] → [Barramento de Eventos / Kafka] → [Serviço de Notificação (Consumidores)]
                                                    │
                        ┌───────────────────────────┼───────────────────────────┐
                        ▼                            ▼                           ▼
                 [Serviço de Preferências]    [Renderização/Template]     [Limitador de Taxa/Deduplicação]
                        │                            │                           │
                        └───────────────┬────────────┴───────────────────────────┘
                                        ▼
                          [Distribuidor / Roteador de Entrega]
                       ┌─────────────┬─────────────┬─────────────┐
                       ▼             ▼             ▼             ▼
                 [Serviço Push]  [Gateway WebSocket/  [Serviço de Email]  [Armazenamento In-App
                 (FCM/APNs)]     SSE]           (SES/SendGrid)   (Escrita - DynamoDB/Cassandra)]
                       │             │
                  [Dispositivos Móveis][Clientes Conectados]

Fluxo:

  1. Um sistema de origem (por exemplo, Serviço de Curtidas, Serviço de Comentários, Serviço de Seguidores, Serviço de Mensagens) emite um evento (por exemplo, user_liked_post) para um barramento de mensagens durável (Kafka).
  2. O Orquestrador de Notificações consome esses eventos, verifica as preferências do usuário, aplica lógica de deduplicação/limitação de taxa/agrupamento (por exemplo, "John e outras 5 pessoas curtiram sua postagem") e gera um objeto de notificação.
  3. O orquestrador persiste a notificação (para histórico) e a envia para um Distribuidor de Entrega, que faz o fan-out para os canais apropriados com base na preferência do usuário e no estado do dispositivo (online vs. offline).
  4. Os trabalhadores de entrega lidam com a transmissão real: provedores de notificação push (FCM para Android, APNs para iOS), WebSocket/SSE para atualizações de badge em tempo real no aplicativo e e-mail via provedor de e-mail transacional.

3. Componentes Chave

3.1 Camada de Ingestão de Eventos — Apache Kafka

  • Todos os serviços de origem publicam eventos em tópicos do Kafka (particionados por user_id para preservar a ordem por usuário).
  • O Kafka fornece durabilidade (fator de replicação 3), alta taxa de transferência e buffer natural durante picos de tráfego — crítico, pois o tráfego de pico é 5x a média.
  • Tópicos: notification.likes, notification.comments, notification.followers, notification.messages (ou um único tópico com campo de tipo de evento, dependendo das necessidades de evolução do esquema).

Por que Kafka em vez de SQS/RabbitMQ? O Kafka lida com taxa de transferência muito alta com baixa sobrecarga por mensagem e suporta repetição (útil para reprocessar lotes com falha ou preenchimento posterior). O SQS é mais simples operacionalmente, mas mais difícil de escalar para >100k msg/s de forma econômica e não suporta semânticas de repetição de grupo de consumidores de forma tão limpa.

3.2 Serviço Orquestrador de Notificações

  • Grupo de consumidores sem estado lendo do Kafka.
  • Responsabilidades:
    • Verificação de Preferências: Consultar um armazenamento rápido de chave-valor (Redis ou DynamoDB) para as configurações de notificação do usuário antes de processar mais. Isso evita trabalho desperdiçado gerando notificações que um usuário optou por não receber.
    • Deduplicação/Agrupamento: Usar uma janela de agregação de curta duração (por exemplo, conjuntos ordenados do Redis com TTL) para agrupar eventos semelhantes (por exemplo, várias curtidas na mesma postagem em 60 segundos se tornam uma notificação).
    • Fan-out para seguidores: Para eventos como "nova postagem de alguém que você segue", isso pode exigir fan-out para milhões de seguidores (problema da celebridade). Use um modelo de fan-out híbrido:
      • Fan-out na escrita para usuários regulares (enviar para o feed de notificações de cada seguidor imediatamente).
      • Fan-out na leitura para contas de celebridades/alto número de seguidores (calcular no momento da leitura para evitar uma tempestade de escrita).
  • Escalável horizontalmente — escalar instâncias de consumidor com base na contagem de partições e no atraso do Kafka.

3.3 Armazenamento de Notificações (Camada de Persistência)

  • Armazenamento primário: Um banco de dados NoSQL de colunas largas como Apache Cassandra ou DynamoDB, particionado por user_id, clusterizado/ordenado por timestamp (decrescente).
    • Este modelo é ideal porque o padrão de acesso dominante é "obter as últimas 100 notificações para o usuário X", que é uma consulta de intervalo simples em uma partição — sem junções necessárias.
    • O Cassandra oferece consistência ajustável e escalabilidade horizontal bem além de 100M de usuários; o DynamoDB oferece uma alternativa totalmente gerenciada com menos sobrecarga operacional (troca: custo mais alto em escala muito grande e risco de partição quente para usuários extremamente ativos, a menos que as chaves de partição sejam salgadas).
  • TTL/Arquivamento: Manter apenas notificações recentes (por exemplo, 30-90 dias) no armazenamento quente; dados mais antigos arquivados em armazenamento mais barato (S3 + Glacier) para conformidade/auditoria, com o limite de "últimos 100" aplicado no momento da escrita (uma lista limitada por usuário, ou aparada por compactação periódica).

3.4 Distribuidor de Entrega

  • Lê o objeto de notificação finalizado e determina os canais a serem usados com base em:
    • Preferências de canal do usuário (push/email/ambos/nenhum)
    • Status online do usuário (rastreado por um serviço de presença com suporte do Redis, atualizado por WebSocket/heartbeat)
  • Roteia para:
    • Serviço de Notificação Push: Integra-se com FCM (Android) e APNs (iOS). Empacotar em uma camada de abstração interna para normalizar retentativas, formatos de payload e gerenciamento de tokens de dispositivo (tokens armazenados em uma tabela user_devices, atualizados no lançamento do aplicativo).
    • Entrega em Tempo Real no Aplicativo: Para usuários ativamente conectados via WebSocket/SSE, enviar diretamente para um gateway de conexão (por exemplo, uma frota de servidores WebSocket atrás de um balanceador de carga, usando algo como Socket.IO ou um serviço gerenciado como AWS API Gateway WebSockets). O mapeamento conexão-servidor é rastreado no Redis para que qualquer nó distribuidor possa encontrar qual instância do gateway possui a conexão de um usuário.
    • Serviço de Email: Para notificações menos sensíveis ao tempo (por exemplo, resumo semanal) ou como fallback para usuários offline em certos tipos de notificação, integrar com um provedor como Amazon SES ou SendGrid, usando uma fila separada de menor prioridade, pois os SLAs de e-mail são mais flexíveis (segundos a minutos está bom).

3.5 Serviço de Preferências

  • Serviço simples com suporte de um banco de dados relacional (Postgres) ou DynamoDB, com cache agressivo no Redis (preferências mudam com pouca frequência, lidas com extrema frequência — candidato perfeito para cache).
  • Esquema: user_id, notification_type, channel, enabled.

4. Modelo de Dados

Tabela de Notificações (Cassandra/DynamoDB)

Chave de Partição: user_id
Chave de Clusterização: notification_id (UUID baseado em tempo, ordenado decrescente)
Atributos:
  - type (like, comment, follow, message)
  - actor_id (quem o acionou)
  - actor_ids (array, para notificações agrupadas)
  - target_object_id (post_id, comment_id, etc.)
  - message_preview
  - created_at
  - read_status (booleano)
  - delivered_channels (array: push, email, in-app)

Tabela de Preferências do Usuário

Chave de Partição: user_id
Atributos: { likes: {push: true, email: false}, comments: {...}, follows: {...}, messages: {...} }

Tabela de Tokens de Dispositivo

Chave de Partição: user_id
Chave de Clusterização: device_id
Atributos: platform (ios/android), token, last_active

5. Garantindo Confiabilidade ("Nenhuma notificação perdida")

  1. Mensagens duráveis: Kafka com fator de replicação ≥3 e acks=all nos produtores garante que os eventos não sejam perdidos antes do processamento.
  2. Processamento de pelo menos uma vez com idempotência: Os consumidores podem reprocessar em caso de falha/reinicialização, portanto, os IDs de notificação são gerados deterministicamente (por exemplo, hash do ID do evento de origem + tipo) para permitir gravações idempotentes — evita notificações duplicadas na retentativa.
  3. Filas de mensagens mortas (DLQ): Entregas com falha (por exemplo, tempo limite do provedor push) vão para um tópico DLQ com retentativa de backoff exponencial (por exemplo, 3 retentativas com jitter), e depois para revisão manual/alerta se ainda falharem.
  4. Escrever notificação no armazenamento ANTES de tentar a entrega: Isso desacopla "notificação existe" (durabilidade/histórico) de "notificação entregue" (melhor esforço em tempo real). Mesmo que a entrega push falhe, o usuário a verá na próxima vez que abrir o aplicativo e consultar a API de notificações.
  5. Padrão de outbox nos serviços de origem: Para evitar problemas de gravação dupla (gravação no DB + publicação de evento), use o padrão de outbox transacional para que, quando uma "curtida" for registrada no DB do serviço de origem, o evento seja garantido para ser publicado no Kafka via uma ferramenta de captura de dados de alteração (CDC) como Debezium.

6. Estratégia de Escalabilidade (10M → 100M DAU)

  • Kafka: Aumentar a contagem de partições (particionadas por hash do user_id) — escala linearmente com mais brokers/consumidores.
  • Orquestrador e Distribuidor de Notificações: Sem estado, escaláveis horizontalmente atrás de grupos de consumidores; escalar via HPA do Kubernetes com base no atraso do consumidor do Kafka.
  • Cassandra: Adicionar nós ao anel; o hashing consistente distribui a carga automaticamente. Observar partições quentes de conteúdo viral/contas de celebridades — mitigar via bucketing (por exemplo, dividir o fan-out de uma celebridade em várias chaves de shard).
  • Gateway WebSocket: Escalar horizontalmente; usar sessões fixas via um registro de conexão no Redis para que os distribuidores saibam qual nó do gateway possui a conexão de um usuário, independentemente de quantos nós do gateway existam.
  • Provedores Push/Email: Estes são serviços gerenciados de terceiros (FCM, APNs, SES) que escalam independentemente; nossa responsabilidade é agrupar e limitar a taxa para permanecer dentro das cotas do provedor.
  • Cache: Cache agressivo no Redis de preferências e dados de presença reduz a carga do DB à medida que o número de usuários cresce 10x.

7. Principais Compromissos

| Decisão | Compromisso |
|---|---|
| Kafka vs. fila mais simples (SQS) | Kafka adiciona complexidade operacional (precisa de expertise de operações dedicada, gerenciamento de ZooKeeper/KRaft), mas fornece taxa de transferência e capacidade de repetição muito superiores necessárias nesta escala. |
| Cassandra vs. DynamoDB | Cassandra oferece mais controle e potencialmente menor custo em escala muito grande, mas requer operações internas; DynamoDB é totalmente gerenciado (mais rápido para construir, menos sobrecarga operacional), mas pode ficar caro em escala extrema e tem restrições mais rígidas de tamanho de item/particionamento de taxa de transferência. |
| Fan-out na escrita vs. fan-out na leitura | Fan-out no momento da escrita oferece menor latência de leitura (ótimo para o SLA de 2 segundos), mas arrisca uma tempestade de escrita "thundering herd" para celebridades; fan-out na leitura evita isso, mas adiciona latência e computação no momento da leitura. A abordagem híbrida equilibra ambos, mas adiciona complexidade de design/código (dois caminhos de código). |
| Armazenar histórico completo vs. 100 notificações recentes quentes + arquivo | Reduz os custos de armazenamento quente e mantém as consultas rápidas, mas requer um caminho de arquivamento/recuperação para conformidade ou recursos de "carregar mais", adicionando complexidade. |
| Entrega de pelo menos uma vez + idempotência vs. exatamente uma vez | Semântica de exatamente uma vez em sistemas distribuídos são caras/complexas (precisa de consumidores transacionais); entrega de pelo menos uma vez + gravações idempotentes alcançam a mesma garantia prática (nenhuma notificação visível duplicada) a um custo operacional muito menor. |
| Push em tempo real para tudo vs. agrupamento/agregação | Agrupar notificações semelhantes (por exemplo, "10 pessoas curtiram sua foto") reduz a fadiga de notificações e o volume de entrega, melhorando a experiência do usuário e o custo, ao custo de uma lógica de orquestração um pouco mais complexa e um pequeno atraso de buffer (ainda bem dentro do SLA de 2 segundos se a janela for curta, por exemplo, máximo de 5-10s antes de descarregar). |


8. Monitoramento e Alertas

  • Rastrear atraso do consumidor do Kafka, taxa de sucesso/falha de entrega por canal, latência ponta a ponta P50/P95/P99 (ingestão de eventos → entrega no dispositivo) e profundidade da DLQ.
  • Dashboards de SLA alertam o plantão se a latência P95 exceder 2s ou o crescimento da DLQ indicar uma falha de entrega sistêmica (por exemplo, interrupção do provedor FCM), acionando lógica de failover automática (por exemplo, fila de espera + retentativa com backoff em vez de descarte).

Resumo

O design desacopla a geração de notificações (orientado a eventos, baseado em Kafka, idempotente) da entrega (distribuidor multicanal com retentativa/backoff por canal), suportado por um armazenamento de colunas largas otimizado para o padrão de acesso "histórico recente por usuário". Essa separação é o que permite que o sistema atenda ao SLA de latência de 2 segundos, garantindo nenhuma perda de dados, e ele escala horizontalmente em todos os níveis (ingestão, processamento, armazenamento, entrega) para suportar 10x o crescimento futuro com sobrecarga operacional e de custo gerenciável.

Resultado

#2

Votos de vitória

0 / 3

Pontuação média

83
Modelos avaliadores OpenAI GPT-5.5

Pontuação total

85

Comentário geral

A Resposta A é uma proposta de design de sistema robusta, com estimativas de capacidade precisas, uma arquitetura lógica orientada a eventos, uso apropriado de Kafka, Cassandra/DynamoDB, Redis, WebSockets, APNs/FCM e provedores de e-mail, além de boa cobertura de persistência, preferências, retentativas, DLQs, idempotência, monitoramento e trade-offs. Suas principais fraquezas são que algumas áreas são menos precisas do que poderiam ser, como o limite exato de latência, a estratégia de HA/DR, detalhes do caminho de leitura/API, priorização de sobrecarga e semânticas de entrega nuances em relação a provedores externos.

Ver detalhes da avaliação

Qualidade da arquitetura

Peso 30%
85

A Resposta A apresenta uma arquitetura coerente com produtores de eventos, Kafka, orquestração de notificações, verificações de preferências, armazenamento, despachantes, entrega via WebSocket, provedores de push e workers de e-mail. O fluxo é lógico e completo, embora alguns detalhes do caminho de leitura/API e da separação de comandos de canal sejam menos explícitos.

Completude

Peso 20%
83

A Resposta A cobre os requisitos principais: tipos de notificação, entrega quase em tempo real, canais push/e-mail/in-app, histórico dos últimos 100, preferências, escalabilidade, confiabilidade, custo, monitoramento e modelos de dados. É um pouco mais leve em detalhes de API, segurança/privacidade, recuperação de desastres e comportamento operacional exato durante sobrecarga ou falhas de provedores.

Análise de trade-offs

Peso 20%
84

A Resposta A inclui uma tabela útil de trade-offs cobrindo Kafka vs. SQS, Cassandra vs. DynamoDB, fan-out-on-write vs. fan-out-on-read, armazenamento quente limitado vs. arquivo, at-least-once vs. exactly-once, e entrega em lote vs. em tempo real. O raciocínio é sólido, embora alguns trade-offs sejam resumidos em vez de estarem profundamente ligados às consequências operacionais.

Escalabilidade e confiabilidade

Peso 20%
85

A Resposta A oferece mecanismos robustos de escalabilidade e confiabilidade: replicação e replay do Kafka, escritas idempotentes, DLQs, retentativas, padrão outbox, escalonamento horizontal, particionamento Cassandra/DynamoDB, cache Redis e escalonamento de WebSocket. É menos detalhada em recuperação multirregional, priorização de sobrecarga, disciplina de offset do consumidor, limites de entrega do provedor e semânticas exatas de SLO.

Clareza

Peso 10%
88

A Resposta A é claramente estruturada, fácil de seguir e utiliza diagramas, marcadores, esquemas e uma tabela concisa de trade-offs de forma eficaz. Ela comunica o design de forma eficiente com o mínimo de ambiguidade.

Modelos avaliadores Anthropic Claude Opus 5

Pontuação total

80

Comentário geral

A Resposta A é uma proposta de design polida e bem estruturada que seria bem recebida em uma entrevista. Ela acerta na matemática de capacidade, fornece um diagrama de arquitetura legível, modelos de dados concretos, uma tabela de trade-offs clara e aborda o padrão outbox, idempotência, DLQs e escalabilidade horizontal em todos os níveis. Suas fraquezas são a profundidade e a amplitude em algumas áreas: sem design de API/caminho de leitura, sem discussão de segurança ou privacidade, sem topologia HA ou recuperação de desastres, sem isolamento de prioridade entre classes de notificação e aceita acriticamente o SLA de ponta a ponta de 2 segundos sem notar que provedores de terceiros o tornam inexequível. A sugestão de fan-out-on-read também é um ajuste um tanto estranho para uma caixa de entrada de notificações.

Ver detalhes da avaliação

Qualidade da arquitetura

Peso 30%
82

Apresenta uma arquitetura em camadas clara com um diagrama ASCII, barramento de eventos (Kafka), orquestrador, serviço de preferência, despachante, gateway WebSocket, workers de push/email e um armazenamento wide-column. O fluxo é fácil de seguir e os componentes são bem delineados. Pequenas fraquezas: a discussão de fan-out-on-read é um tanto mal aplicada a notificações (é um conceito de feed), e a camada de API/caminho de leitura mais gateway de API são mal abordadas, apesar de terem sido destacadas na política de julgamento.

Completude

Peso 20%
76

Cobre estimativa, todos os quatro tipos de notificação, canais push/email/in-app, histórico via lista limitada mais arquivamento, preferências com esquema, tokens de dispositivo, confiabilidade, escalabilidade e monitoramento. Ausente ou fino: design de API/caminho de leitura, segurança e privacidade, recuperação de desastres e estratégia multirregional, contagens de não lidos e topologia HA explícita (distribuição AZ).

Análise de trade-offs

Peso 20%
80

Uma tabela de trade-offs dedicada cobre Kafka vs SQS, Cassandra vs DynamoDB, fan-out na escrita vs leitura, armazenamento quente vs arquivo, at-least-once vs exactly-once, e batching vs imediatismo. Cada entrada nomeia tanto o benefício quanto o custo, o que é claro e legível. No entanto, os trade-offs são em sua maioria convencionais e declarados brevemente, com menos profundidade em limites de consistência, garantias de ordenação ou nuances de definição de SLO.

Escalabilidade e confiabilidade

Peso 20%
80

Sólido: particionamento e replicação do Kafka, acks=all, at-least-once com IDs idempotentes determinísticos, DLQ com backoff exponencial e jitter, write-before-deliver, outbox transacional com Debezium, HPA em lag do consumidor, expansão do anel do Cassandra, salting de partição quente e registro de conexão Redis. Falta HA explícita multi-AZ/multirregional, procedimentos de DR/failover, backpressure ou isolamento de prioridade entre classes de notificação e semântica de commit de offset.

Clareza

Peso 10%
85

Excelente legibilidade: seções numeradas, um diagrama de arquitetura ASCII, blocos de código para o modelo de dados, uma tabela de trade-offs e um resumo conciso de encerramento. Fácil de percorrer e rápido de entender o design rapidamente.

Modelos avaliadores Google Gemini 2.5 Pro

Pontuação total

85

Comentário geral

A Resposta A fornece um design de sistema muito forte e bem estruturado. Seus principais pontos fortes são a clareza e a organização, usando um diagrama e uma tabela para tornar conceitos complexos fáceis de entender. Ela cobre todos os requisitos centrais da solicitação, propondo uma arquitetura lógica com escolhas de tecnologia apropriadas e estratégias sólidas para escalabilidade e confiabilidade. No entanto, falta a profundidade e a amplitude da Resposta B, particularmente em áreas como design de API, segurança e planejamento detalhado de recuperação de desastres.

Ver detalhes da avaliação

Qualidade da arquitetura

Peso 30%
85

A arquitetura proposta é lógica, completa e bem adequada para a tarefa. Ela identifica claramente todos os componentes principais e suas interações, e a inclusão de um diagrama auxilia muito na compreensão. O fluxo de produtores de eventos para canais de entrega é bem definido.

Completude

Peso 20%
80

A resposta aborda todos os requisitos funcionais e não funcionais especificados na solicitação. Ela cobre os principais aspectos do design, incluindo estimativas, componentes, modelos de dados e estratégias de escalabilidade e confiabilidade.

Análise de trade-offs

Peso 20%
85

A resposta discute claramente os principais trade-offs em uma tabela dedicada, o que é muito eficaz. Ela fornece raciocínio sólido para escolhas como Kafka em vez de SQS e Cassandra em vez de DynamoDB, demonstrando um bom entendimento dos princípios envolvidos.

Escalabilidade e confiabilidade

Peso 20%
85

O design aborda efetivamente a escalabilidade e a confiabilidade. Ele propõe técnicas padrão e eficazes como escalonamento horizontal para serviços, particionamento em Kafka e Cassandra, e o uso de DLQs e idempotência para confiabilidade. As estratégias são sólidas e bem explicadas.

Clareza

Peso 10%
90

A resposta é excepcionalmente clara e bem organizada. O uso de títulos, um diagrama de fluxo e uma tabela de trade-offs torna o design complexo fácil de seguir e digerir. A escrita é direta e objetiva.

Resposta B: OpenAI GPT-5.6

VISÃO GERAL

O sistema deve tratar cada notificação como um registro durável e específico do destinatário e entregá-la assincronamente por meio de um ou mais canais. A caixa de entrada durável no aplicativo é a fonte da verdade; notificações push para dispositivos móveis e e-mail são tentativas de entrega derivadas desse registro. Essa separação oferece baixa latência sem fazer com que as ações sociais voltadas para o usuário esperem por provedores externos, como APNs, FCM ou um serviço de e-mail.

ESTIMATIVAS DE CAPACIDADE

Com 10 milhões de DAUs e 20 notificações por usuário por dia, o sistema cria cerca de 200...

Mostrar resposta completa

VISÃO GERAL

O sistema deve tratar cada notificação como um registro durável e específico do destinatário e entregá-la assincronamente por meio de um ou mais canais. A caixa de entrada durável no aplicativo é a fonte da verdade; notificações push para dispositivos móveis e e-mail são tentativas de entrega derivadas desse registro. Essa separação oferece baixa latência sem fazer com que as ações sociais voltadas para o usuário esperem por provedores externos, como APNs, FCM ou um serviço de e-mail.

ESTIMATIVAS DE CAPACIDADE

Com 10 milhões de DAUs e 20 notificações por usuário por dia, o sistema cria cerca de 200 milhões de notificações por dia. Isso é aproximadamente 2.315 notificações por segundo em média e 11.600 por segundo no pico declarado de 5x. Com 100 milhões de DAUs, as taxas correspondentes são de cerca de 23.000 por segundo em média e 116.000 por segundo no pico.

Essas são taxas de destinatário-notificação, não meramente taxas de evento de origem. Uma postagem de celebridade pode produzir um pico de chave quente ou de fan-out, portanto, as camadas de ingestão e enfileiramento devem ser provisionadas acima do pico calculado, inicialmente para cerca de 25.000 notificações por segundo e, eventualmente, para pelo menos 200.000 por segundo. As cargas úteis devem permanecer pequenas, com mídia e conteúdo completo da postagem referenciados por ID em vez de incorporados.

ARQUITETURA DE ALTO NÍVEL

Serviços sociais como Curtir, Comentar, Seguir e Mensagem Direta gravam seu próprio estado e um evento de notificação em uma outbox transacional na mesma transação de banco de dados. Publicadores de outbox transferem continuamente esses eventos para um log de eventos durável, como Apache Kafka. Isso evita a falha de gravação dupla em que uma ação social é bem-sucedida, mas seu evento de notificação é perdido.

Um Processador de Notificações consome os eventos de origem, valida-os, identifica destinatários, gera um ID de notificação determinístico, carrega as preferências de notificação, realiza enriquecimento leve e grava a notificação do destinatário no armazenamento da caixa de entrada. Em seguida, publica um comando de entrega durável por canal habilitado em tópicos Kafka específicos do canal.

Trabalhadores de Notificações Push consomem comandos push e invocam APNs ou FCM. Trabalhadores de E-mail renderizam modelos e invocam um provedor como Amazon SES, SendGrid ou um serviço de transferência de e-mail interno. Um Gateway WebSocket também pode consumir comandos de entrega no aplicativo e atualizar imediatamente os clientes conectados; clientes desconectados ainda veem a caixa de entrada durável ao reconectar. Os resultados da entrega e as novas tentativas são registrados de forma assíncrona.

O fluxo principal é:

Serviço social e outbox transacional → Tópicos de eventos de origem Kafka → Processador de Notificações → Armazenamento de caixa de entrada durável → Tópicos de comandos de canal → Trabalhadores WebSocket, APNs/FCM e de e-mail.

O fluxo de leitura é:

Cliente → Gateway de API → API de Notificação → Armazenamento de caixa de entrada e armazenamento de preferências.

COMPONENTES PRINCIPAIS

O Gateway de API lida com autenticação, limitação de taxa, roteamento de solicitação e proteção contra abusos. A API de Notificação suporta a busca de notificações recentes, paginação baseada em cursor, contagens de não lidas, marcação de um ou mais itens como lidos e gerenciamento de preferências.

O Kafka fornece buffer durável, suavização de tráfego, repetição, isolamento do consumidor e escalabilidade horizontal. Os tópicos são replicados em pelo menos três zonas de disponibilidade. Os tópicos de origem podem ser particionados por ID de usuário destinatário após a expansão do destinatário, preservando a ordem por usuário enquanto distribuem os usuários entre as partições. A expansão de alto fan-out pode usar um pool de trabalhadores separado para que um grande evento não possa bloquear o tráfego normal.

O Processador de Notificações deve ser sem estado e escalado automaticamente usando atraso da fila, latência de processamento, CPU e taxa de transferência. Ele realiza a avaliação de preferências antes de emitir comandos de canal. As preferências podem ser armazenadas em cache no Redis, mas o valor autoritativo permanece em um armazenamento durável. Eventos de invalidação de cache são emitidos sempre que as preferências mudam.

O armazenamento da caixa de entrada deve ser um banco de dados de chave-valor ou coluna larga horizontalmente escalável, como DynamoDB, Cassandra ou ScyllaDB. O DynamoDB oferece menor carga operacional e opções multirregionais gerenciadas; Cassandra ou ScyllaDB podem ser mais baratos em escala grande sustentada, mas exigem mais conhecimento operacional. Um banco de dados relacional é menos adequado para a caixa de entrada principal porque o volume de gravação, o crescimento da partição e o dimensionamento entre shards se tornariam caros.

O Redis pode armazenar em cache contagens de não lidas e a primeira página da caixa de entrada, mas não deve ser o sistema de registro. Gateways WebSocket são sem estado, exceto pelo estado da conexão ativa. Um diretório de presença no Redis ou um armazenamento efêmero semelhante mapeia usuários para instâncias de gateway.

MODELO DE DADOS

Um registro de notificação contém notification_id, recipient_user_id, type, actor_user_id, object_type, object_id, creation_time, template_version, dados de renderização compactos, read_time e informações opcionais de agrupamento. O estado do canal deve conter os canais solicitados e o status de entrega, como pendente, despachado, falhou ou suprimido. Corpos grandes e conteúdo social mutável não devem ser copiados para o registro, a menos que um instantâneo imutável seja necessário.

Uma chave de caixa de entrada adequada é partition_key = recipient_user_id mais um bucket de tempo opcional, e sort_key = reverse_timestamp mais notification_id. A ordenação cronológica reversa torna a página mais recente eficiente. Em volume comum, uma partição por usuário é suficiente; contas excepcionalmente ativas podem usar buckets mensais. A API consulta o bucket mais novo primeiro e segue um cursor opaco para buckets mais antigos.

O requisito expõe apenas as últimas 100 notificações. O serviço pode reter um pouco mais, como 30 a 90 dias, e aplicar expiração TTL, enquanto a API de leitura retorna no máximo 100. O corte ou expiração assíncrona de registros é mais seguro e barato do que realizar uma exclusão síncrona em cada inserção. Se o armazenamento físico estrito de exatamente 100 registros for necessário, um compactador em segundo plano pode remover entradas mais antigas.

As preferências são indexadas por ID de usuário e contêm configurações por tipo, por canal, por exemplo, likes.push, likes.email, comments.push e comments.email, além de mudo global, local, fuso horário e uma versão monotonicamente crescente. Os tokens de dispositivo são armazenados separadamente por ID de usuário e ID de dispositivo, com plataforma, token, hora da última visualização e status de validade. Os tokens devem ser criptografados e invalidados após erros permanentes de APNs ou FCM.

Um ID de notificação determinístico pode ser derivado de source_event_id, recipient_user_id, tipo de notificação e versão semântica. A gravação na caixa de entrada é condicional a esse ID, tornando a repetição e o consumo duplicado seguros. Um comando de entrega tem um ID determinístico semelhante com base no ID da notificação e no canal.

SEMÂNTICA DE ENTREGA E CONFIABILIDADE

A garantia prática é o processamento durável de pelo menos uma vez com efeitos idempotentes. A entrega exatamente uma vez entre bancos de dados, Kafka, APNs, FCM e e-mail não é alcançável de ponta a ponta. Outboxes transacionais garantem que as ações de origem aceitas sejam eventualmente publicadas. A replicação do Kafka e as gravações confirmadas evitam a perda da fila. As gravações condicionais na caixa de entrada suprimem registros duplicados. Os trabalhadores de canal armazenam ou deduplicam IDs de tentativa de entrega, reduzindo envios duplicados durante novas tentativas.

Uma notificação é considerada aceita somente após a transação de origem contendo sua linha de outbox ser confirmada. Ela é considerada criada duravelmente após a gravação na caixa de entrada ser bem-sucedida. Os offsets do Kafka são confirmados somente após a gravação durável correspondente ou a entrega ao provedor ter sido concluída. Falhas transitórias usam backoff exponencial com jitter. Após um número limitado de tentativas, os comandos são movidos para um tópico de dead-letter com o erro, referência de carga útil e histórico de novas tentativas. Os operadores podem reproduzir este tópico após a remediação.

Provedores móveis e infraestrutura de e-mail não podem garantir que um dispositivo ou caixa de correio apresentará uma notificação em dois segundos. Portanto, o serviço deve definir o objetivo de latência como o tempo desde o evento de origem confirmado até a visibilidade na caixa de entrada durável e o primeiro despacho do provedor. Um SLO razoável é 99% abaixo de dois segundos sob carga suportada. Reconhecimentos de APNs e FCM significam aceitação do provedor, não exibição pelo usuário. A caixa de entrada durável garante que interrupções do provedor ou dispositivos offline não percam a notificação do histórico do usuário.

Para clientes atualmente conectados, o caminho WebSocket normalmente fornece a entrega mais rápida. Mensagens WebSocket carregam IDs de notificação, e os clientes os deduplicam em relação aos registros da caixa de entrada buscados. Ao reconectar, os clientes buscam notificações após seu último cursor, para que mensagens de soquete perdidas não criem lacunas.

ESCALABILIDADE

Os tópicos do Kafka devem começar com partições suficientes para paralelismo esperado e ser expandidos antes de atingir os limites de taxa de transferência de partição. O particionamento por ID de destinatário distribui usuários comuns uniformemente. Eventos de celebridades não devem usar o ID do ator como chave de partição, pois isso cria uma partição quente. A expansão de destinatários pode dividir uma grande audiência em blocos e publicar cada bloco independentemente.

Processadores, gateways WebSocket e trabalhadores de canal são sem estado e escaláveis horizontalmente. A escalabilidade automática deve considerar o atraso do Kafka e a idade da mensagem mais antiga, em vez de apenas a CPU. Grupos de consumidores e cotas separados isolam mensagens diretas de curtidas e e-mails de menor prioridade. Sob sobrecarga, a capacidade é reservada para mensagens diretas e comentários, enquanto e-mails e curtidas de baixa prioridade podem ser enfileirados sem serem descartados.

A capacidade da caixa de entrada cresce linearmente com os usuários, mas permanece limitada pelo TTL e pelo requisito de histórico limitado. Com 100 milhões de DAUs e 20 notificações por dia, o design deve lidar com cerca de dois bilhões de gravações diárias. Partições de usuário com bucket de tempo, capacidade de banco de dados sob demanda ou provisionada, registros compactados e sem fan-out síncrono de índice secundário mantêm isso gerenciável. Consultas globais caras devem ser atendidas a partir de um pipeline de análise, não da caixa de entrada transacional.

ALTA DISPONIBILIDADE E RECUPERAÇÃO DE DESASTRES

Todos os componentes síncronos são executados em pelo menos três zonas de disponibilidade atrás de balanceadores de carga com verificação de integridade. O Kafka usa fator de replicação três com configurações de confirmação fortes e um número mínimo apropriado de réplicas em sincronia. Os armazenamentos de caixa de entrada e preferências usam replicação multizona e backups pontuais. Implantações usam estratégias canário ou de rolagem, esquemas de eventos compatíveis com versões anteriores e versionamento de esquemas por meio de um registro.

Um projeto inicial econômico usa uma região ativa com redundância multizona e uma região de standby quente replicada assincronamente. Procedimentos de recuperação promovem o standby, restauram consumidores de offsets replicados ou eventos retidos e reproduzem com segurança porque o processamento é idempotente. Para disponibilidade regional mais rigorosa, o sistema pode evoluir para ingestão regional ativa-ativa, com usuários atribuídos a uma região de origem e IDs de evento globalmente exclusivos. Ativo-ativo melhora o tempo de recuperação, mas aumenta o custo do banco de dados, o tratamento de duplicatas, a complexidade da ordenação e os desafios de consistência de preferências.

Alterações de preferência devem usar gravações fortemente consistentes na região de origem do usuário. Uma notificação já criada duravelmente antes de uma alteração de preferência ainda pode ser entregue; essa fronteira deve ser documentada. Para supressão legalmente exigida ou exclusão de conta, os trabalhadores devem realizar uma verificação autoritativa adicional imediatamente antes da entrega externa.

OTIMIZAÇÕES DE LATÊNCIA

O caminho crítico não contém chamadas síncronas para provedores APNs, FCM ou de e-mail. As cargas úteis de eventos incluem metadados de ator e objeto suficientes para renderização básica, evitando várias chamadas de serviço downstream. O enriquecimento opcional ausente deve produzir uma notificação genérica em vez de bloquear a entrega. Registros de preferências e modelos são armazenados em cache localmente ou no Redis, e as conexões com Kafka, bancos de dados e provedores são agrupadas.

A renderização e o despacho de e-mail usam um tópico separado porque o e-mail é mais lento e mais caro do que a entrega no aplicativo. Se os requisitos do produto permitirem, curtidas não urgentes podem ser agrupadas ou enviadas como e-mails de resumo, enquanto comentários, seguimentos e mensagens diretas permanecem imediatos. O agrupamento reduz o custo e a fadiga do usuário, mas altera a semântica da notificação, portanto, deve ser uma decisão explícita do produto.

PROJETO DE API

GET /v1/notifications?cursor=...&limit=... retorna registros cronológicos reversos, limitados aos últimos 100. POST /v1/notifications/read aceita um ou mais IDs de notificação ou um timestamp de leitura. GET e PUT /v1/notification-preferences leem e atualizam configurações versionadas. POST e DELETE endpoints de device-token registram e revogam dispositivos. Todos os endpoints de mutação suportam chaves de idempotência.

Contagens de não lidas podem ser mantidas como um contador eventualmente consistente atualizado a partir de eventos de caixa de entrada e de leitura. Como novas tentativas podem corromper incrementos ingênuos, as atualizações de contador devem ser idempotentes ou reconciliadas periodicamente a partir de registros autoritativos. Se contagens exatas de não lidas forem necessárias, o serviço pode consultar um índice de não lidas com escopo de usuário com maior custo de leitura e armazenamento.

OBSERVABILIDADE E OPERAÇÕES

Métricas incluem taxa de aceitação de eventos, latência de ponta a ponta por tipo de notificação e canal, atraso do Kafka, comando mais antigo na fila, erros de gravação na caixa de entrada, códigos de resposta do provedor, contagens de novas tentativas, volume de dead-letter, contagem de conexões WebSocket, taxa de acerto do cache de preferências e taxa de supressão de duplicatas. O rastreamento distribuído carrega source_event_id e notification_id em todas as etapas. Logs estruturados excluem corpos de mensagens e tokens confidenciais.

Alertas devem ser baseados em taxas de queima de SLO e idade da mensagem mais antiga. Usuários sintéticos geram eventos continuamente e verificam os caminhos da caixa de entrada, WebSocket, provedor de push e provedor de e-mail. A repetição de dead-letter, failover regional, interrupção do provedor, perda de partição do Kafka e limitação do banco de dados devem ser exercitados regularmente por meio de runbooks e testes de injeção de falhas.

SEGURANÇA E PRIVACIDADE

Serviços se autenticam com identidades de curta duração e recebem acesso de privilégio mínimo. Os dados são criptografados em trânsito e em repouso, e tokens de dispositivo e endereços de e-mail recebem proteção adicional. Cargas úteis de notificação exibidas em uma tela bloqueada devem evitar conteúdo de mensagem direta confidencial, a menos que o usuário habilite explicitamente as pré-visualizações. As APIs impõem que os usuários só possam acessar sua própria caixa de entrada e preferências. Requisitos de retenção, exclusão de conta, registro de auditoria e residência de dados regional devem ser incorporados ao ciclo de vida do armazenamento.

CUSTOS E COMPROMISSOS

O Kafka é preferível a chamadas síncronas de serviço a serviço porque absorve rajadas e permite repetição, embora introduza complexidade operacional e consistência eventual. Um serviço Kafka gerenciado reduz o risco operacional a um custo direto mais alto. O DynamoDB é operacionalmente simples e elástico, enquanto Cassandra ou ScyllaDB podem reduzir o custo de armazenamento em estado estacionário, mas exigem uma equipe de operações capaz.

Gravar a caixa de entrada antes de emitir comandos de canal garante que o histórico seja autoritativo e que nenhum comando de canal se refira a um registro ausente, ao custo de uma pequena latência de gravação adicional. A entrega de pelo menos uma vez é escolhida em vez de um suposto design de exatamente uma vez porque permanece correta em falhas e novas tentativas de provedores externos quando combinada com IDs determinísticos e idempotência.

O particionamento por chave de destinatário preserva a ordem por usuário, mas não fornece ordem global, o que é desnecessário. A ordenação estrita em todas as notificações reduziria a taxa de transferência e a disponibilidade. Da mesma forma, caches de preferências melhoram a latência, mas podem servir brevemente valores desatualizados; invalidação versionada e uma verificação final para supressão sensível equilibram desempenho e correção.

A implantação inicial recomendada é um cluster Kafka gerenciado, armazenamento de caixa de entrada e preferências gerenciado estilo DynamoDB, Redis para cache efêmero e presença, serviços sem estado conteinerizados no Kubernetes ou uma plataforma de contêiner gerenciada, APNs/FCM para push móvel e SES ou um provedor de e-mail comparável. Essa arquitetura suporta confortavelmente o pico atual, escala horizontalmente em direção a 100 milhões de DAUs, retém um histórico durável visível pelo usuário e isola falhas de entrega externas da aplicação social principal.

Resultado

#1 | Vencedor

Votos de vitória

3 / 3

Pontuação média

90
Modelos avaliadores OpenAI GPT-5.5

Pontuação total

93

Comentário geral

A Resposta B é um projeto excepcionalmente completo e bem fundamentado. Ela separa claramente a criação de caixas de entrada duráveis das tentativas de entrega externas, inclui tratamento transacional de caixa de saída, filas específicas para destinatários, processamento idempotente de pelo menos uma vez, workers específicos do canal, design de armazenamento escalável, comportamento da API, HA/DR, observabilidade, segurança, considerações de custo e análise de trade-offs nuançada. É um pouco longa, mas a estrutura permanece clara e o detalhe adicionado é diretamente relevante para os requisitos de design do sistema.

Ver detalhes da avaliação

Qualidade da arquitetura

Peso 30%
92

A Resposta B fornece uma arquitetura muito forte com outbox transacional, tópicos de origem Kafka, processadores stateless, armazenamento de caixa de entrada durável, tópicos de comando específicos do canal, workers WebSocket/APNs/FCM/email, gateway de API e APIs de leitura. A separação entre a criação de notificações duráveis e as tentativas de entrega é especialmente bem projetada.

Completude

Peso 20%
94

A Resposta B aborda quase todos os requisitos especificados e implícitos em profundidade, incluindo histórico, preferências, múltiplos canais, contagens de não lidos, tokens de dispositivo, novas tentativas, DLQs, endpoints de API, observabilidade, segurança, retenção, HA/DR e escalonamento futuro para 100 milhões de DAUs. Ela também lida com casos nuançados como preferências desatualizadas, limitações do provedor e comportamento de reconexão.

Análise de trade-offs

Peso 20%
93

A Resposta B demonstra um raciocínio profundo sobre trade-offs em toda a proposta, incluindo infraestrutura gerenciada vs. auto-operada, durabilidade primeiro na caixa de entrada vs. latência, pelo menos uma vez vs. exatamente uma vez, regiões ativo-passivo vs. ativo-ativo, desatualização do cache de preferências, particionamento de destinatários vs. ordenação global, e custo vs. desempenho.

Escalabilidade e confiabilidade

Peso 20%
95

A Resposta B é excelente em escalabilidade e confiabilidade. Ela cobre planejamento de capacidade por taxa de destinatário, mitigação de hot fan-out, estratégia de particionamento, autoescalonamento por lag e idade da mensagem mais antiga, IDs determinísticos idempotentes, escritas condicionais, regras de commit de offset, DLQs, replay, implantação multi-AZ, standby quente, evolução ativo-ativo e limites de falha do provedor externo.

Clareza

Peso 10%
89

A Resposta B é muito clara e organizada, com seções bem rotuladas e redação precisa. É mais longa e densa que a Resposta A, mas o detalhe é relevante e o design principal permanece fácil de entender.

Modelos avaliadores Anthropic Claude Opus 5

Pontuação total

86

Comentário geral

A Resposta B é um projeto mais profundo e operacionalmente maduro. Estabelece a caixa de entrada durável como o sistema de registro e deriva as entregas de canal a partir dela, usa outboxes transacionais e tópicos de comando por canal com IDs determinísticos e escritas condicionais, e define limites precisos de aceitação/durabilidade com ordenação de commit de offset. Vai muito além de A no design da API, consistência de contagem de não lidas, particionamento por bucket de tempo, HA entre AZs, recuperação de desastres e failover regional, isolamento de prioridade sob sobrecarga, observabilidade com sondas sintéticas e injeção de falhas, e segurança/privacidade. Criticamente, também reformula o objetivo de latência de 2 segundos como um SLO para visibilidade da caixa de entrada e despacho do provedor — uma visão genuinamente sênior. Sua principal fraqueza é a apresentação: prosa densa e ininterrupta, sem diagramas, tabelas ou esquemas formatados, o que a torna mais difícil de analisar rapidamente do que A.

Ver detalhes da avaliação

Qualidade da arquitetura

Peso 30%
87

Arquitetura muito forte: outbox transacional com publicadores estilo CDC, tópicos de origem Kafka, Processador de Notificações sem estado que escreve a caixa de entrada durável como fonte da verdade, depois tópicos de comando duráveis por canal consumidos por workers de push/email/WebSocket. Separa explicitamente os caminhos de escrita e leitura, inclui um gateway de API e API de Notificação com endpoints concretos, diretório de presença e pools de workers separados para alto fan-out. O design do tópico de comando de canal e o enquadramento 'caixa de entrada como fonte da verdade' são mais rigorosos do que o modelo de dispatcher de A. A única desvantagem é a ausência de um diagrama visual, embora o fluxo textual seja explícito.

Completude

Peso 20%
88

Cobre essencialmente todos os requisitos e mais: estimativas de capacidade para o estado atual e 100M de DAUs, modelo de dados com chaves de partição/ordenação e bucket de tempo, versionamento de preferências e invalidação de cache, ciclo de vida de token de dispositivo e criptografia, API REST explícita com cursores e chaves de idempotência, consistência de contagem de não lidas, HA entre três AZs, DR com standby quente e procedimento de failover, observabilidade com canários sintéticos, e segurança/privacidade incluindo previews de tela de bloqueio e residência de dados. Pouquíssimas lacunas.

Análise de trade-offs

Peso 20%
85

Os trade-offs são tecidos ao longo e consolidados em uma seção de custos: Kafka vs chamadas síncronas, gerenciado vs auto-hospedado, DynamoDB vs Cassandra/ScyllaDB, custo de latência de escrita na caixa de entrada antes do despacho, at-least-once com IDs determinísticos, ordenação por usuário vs global, staleness de cache vs correção com uma verificação autoritativa pré-envio para supressão legal, ativo-ativo vs standby quente, e agrupamento de digestos como uma decisão explícita de produto. Notavelmente, também desafia a premissa da SLA de 2 segundos, redefinindo a latência como commit de origem para a caixa de entrada durável e o primeiro despacho do provedor — uma visão de nível sênior genuíno. O formato é menos escaneável que a tabela de A.

Escalabilidade e confiabilidade

Peso 20%
89

Excepcionalmente completo: alvos de provisionamento excessivo acima do pico calculado, particionamento por chave de destinatário com aviso explícito contra partições quentes por chave de ator, expansão de destinatários em chunks, autoescalonamento por lag e idade da mensagem mais antiga em vez de CPU, grupos de consumidores e cotas separados para priorizar DMs sobre likes sob sobrecarga, commit de offset apenas após escrita durável, escritas condicionais para dedup, DLQ com replay, RF=3 com min-ISR, multi-AZ, DR com standby quente e replay idempotente, armazenamento com limite de TTL e análise de 2B escritas diárias a 100M de DAUs. Injeção de falhas e exercícios de runbook adicionam credibilidade operacional.

Clareza

Peso 10%
74

Bem organizado com cabeçalhos de seção claros e prosa técnica precisa e densa, mas são parágrafos uniformemente longos sem diagramas, tabelas e esquemas formatados em código. Maior carga cognitiva e mais difícil de analisar rapidamente, embora o conteúdo em si seja inequívoco e logicamente ordenado.

Modelos avaliadores Google Gemini 2.5 Pro

Pontuação total

92

Comentário geral

A Resposta B é uma proposta de design de sistema excepcional e abrangente que demonstra um profundo nível de especialização. Ela não só atende a todos os requisitos, mas vai significativamente além deles, discutindo aspectos críticos como design de API, segurança, estratégias detalhadas de HA/DR e observabilidade com rigor profissional. As escolhas arquitetônicas são sutis e bem justificadas, e a discussão sobre escalabilidade e confiabilidade é particularmente detalhada e prática. Embora sua prosa densa a torne um pouco menos acessível que a Resposta A, sua profundidade técnica e completude são notáveis.

Ver detalhes da avaliação

Qualidade da arquitetura

Peso 30%
90

A arquitetura é excepcionalmente bem concebida, demonstrando um entendimento maduro de sistemas distribuídos. Ela enfatiza corretamente o padrão transactional outbox desde o início e propõe um fluxo refinado com tópicos separados para eventos de origem e comandos de canal. A inclusão do gateway de API e considerações de design de API tornam a arquitetura mais completa.

Completude

Peso 20%
95

Esta resposta é excepcionalmente completa. Ela não só cobre todos os requisitos da solicitação, mas também se aprofunda em áreas relacionadas cruciais, como design de API, segurança e privacidade, estratégias detalhadas de alta disponibilidade e recuperação de desastres, e observabilidade. Essa abordagem abrangente reflete uma mentalidade holística e pronta para produção.

Análise de trade-offs

Peso 20%
90

A discussão de trade-offs é sofisticada e tecida em todo o design, com um resumo conciso no final. Ela abrange uma ampla gama de decisões, desde escolhas de tecnologia até padrões arquitetônicos como modelos de disponibilidade regional e semânticas de entrega, demonstrando profundo conhecimento.

Escalabilidade e confiabilidade

Peso 20%
95

O tratamento de escalabilidade e confiabilidade é notável. Ela fornece estratégias altamente específicas e práticas, como particionamento por ID do destinatário para evitar gargalos induzidos por celebridades, uso de filas de prioridade e definição de SLOs de latência realistas. A seção detalhada sobre HA/DR é um ponto forte significativo.

Clareza

Peso 10%
85

A resposta está bem estruturada e escrita com precisão técnica. No entanto, sua prosa é bastante densa e a falta de recursos visuais, como diagramas ou tabelas, a torna um pouco menos acessível imediatamente que a Resposta A, exigindo uma leitura mais focada para compreender todos os detalhes.

Resumo comparativo

Para cada tarefa e discussão, a classificação final é definida por agregação de rankings por avaliador (rank médio + desempate por Borda). A pontuação média é exibida como referência.

Avaliadores: 3

Votos de vitória

0 / 3

Pontuação média

83
Ver esta resposta

Votos de vitória

3 / 3

Pontuação média

90
Ver esta resposta

Resultados da avaliação

Modelos avaliadores Google Gemini 2.5 Pro

Motivo do vencedor

A Resposta B é a vencedora clara devido à sua profundidade, completude e nuance técnica superiores. Embora a Resposta A forneça um design muito bom e padrão, a Resposta B opera a um nível mais elevado de detalhe e previsão, característico de um engenheiro sénior. Aborda considerações críticas do mundo real que A ignora, como design de API, segurança e planos detalhados de recuperação de desastres. As discussões de B sobre escalabilidade (por exemplo, lidar com o fan-out de celebridades) e fiabilidade (por exemplo, definir SLOs realistas) são mais avançadas e práticas. Estas forças nos critérios mais ponderados — arquitetura, completude e escalabilidade/fiabilidade — tornam-na a melhor resposta.

Modelos avaliadores Anthropic Claude Opus 5

Motivo do vencedor

A resposta B vence no resultado ponderado. Ela supera A na qualidade da arquitetura (30%) através do modelo de caixa de entrada como fonte da verdade, separação explícita do caminho de leitura/escrita e tópicos de comando por canal, e vence decisivamente na completude (20%), escalabilidade e confiabilidade (20%), e raciocínio sobre trade-offs (20%) ao adicionar design de API, HA/DR, isolamento de prioridade, semântica de commit de offset, segurança, observabilidade e um requadro crítico do SLO de latência. A resposta A é claramente melhor na clareza (10%) graças ao seu diagrama, tabelas e estrutura, mas essa única vantagem levemente ponderada não pode compensar a superioridade de B nos quatro critérios mais pesados.

Modelos avaliadores OpenAI GPT-5.5

Motivo do vencedor

A Resposta B vence porque fornece um design mais completo e tecnicamente preciso nos critérios de peso elevado. Ambas as respostas propõem arquiteturas orientadas a eventos sólidas, mas a B define de forma mais explícita as semânticas de entrega, os limites de falha, o comportamento de repetição, a alta disponibilidade e recuperação de desastres, o tratamento de sobrecarga, o comportamento da API, as compensações de segurança/privacidade e custo. A sua discussão sobre fiabilidade e escalabilidade é mais profunda e mais fundamentada operacionalmente, ao mesmo tempo que aborda todos os requisitos funcionais.

X f L