Pular para o conteúdo

Design clássico · Staff

Agregação de cliques em anúncios

Projeto de entrevista clássico. Pontos centrais: semântica de processamento de streams e ledger e conciliação.

17 min de leitura · Conteúdo revisado em 22 de outubro de 2026

Resposta curta

Projeto de entrevista clássico. Pontos centrais: semântica de processamento de streams e ledger e conciliação. Um agregador de cliques em anúncios coleta cada clique que usuários dão em anúncios de um site ou app e entrega aos anunciantes métricas de desempenho.

01 · CONTEXTO E REQUISITOS

O que um agregador de cliques precisa fazer

Um agregador de cliques em anúncios coleta cada clique que usuários dão em anúncios de um site ou app e entrega aos anunciantes métricas de desempenho. São dois requisitos funcionais: levar o usuário ao site do anunciante e permitir que o anunciante consulte os cliques ao longo do tempo, com granularidade mínima de um minuto. É um bom exercício de arquitetura de análise em tempo real.

A escala de referência é de dez milhões de anúncios ativos e pico de dez mil cliques por segundo. Os requisitos não funcionais que mandam no desenho são: consultas do anunciante com baixa latência, coleta tolerante a falhas que não perca cliques, dados o mais próximos possível do tempo real e contagem idempotente, que não conte o mesmo clique duas vezes.

02 · O CAMINHO DO CLIQUE

Redirecionar e registrar, a versão ingênua

Há duas formas de redirecionar. No cliente, o anúncio já traz a URL de destino e o navegador navega sozinho, enquanto uma chamada paralela registra o clique; usuários sofisticados podem copiar a URL e ir direto, sem passar pelo rastreamento. No servidor, o clique chega ao nosso endpoint, que registra o evento e responde com um redirect 302 para o anunciante; é um pouco mais complexo, mas garante que todo clique seja visto.

  1. O usuário clica no anúncio e o navegador chama o serviço de cliques, que vai registrar o evento e responder com o redirecionamento.

    Diagrama da arquitetura: Cliques: versão ingênua
    CLNavegador
    CPServiço de cliques
    DBBanco único de eventos
    CLPainel do anunciante
  2. O serviço grava cada clique como uma linha no banco único de eventos.

    Diagrama da arquitetura: Cliques: versão ingênua
    CLNavegador
    CPServiço de cliquesregistra o clique
    DBBanco único de eventosuma linha por clique
    CLPainel do anunciante
  3. Quando o anunciante pede métricas, o mesmo banco precisa agrupar todas as linhas do período, e é aí que a conta deixa de fechar.

    Diagrama da arquitetura: Cliques: versão ingênua
    CLNavegador
    CPServiço de cliques
    DBBanco único de eventosagrega na hora da consulta
    CLPainel do anunciante

Na escala de pico, esse desenho não aguenta: o banco vira gargalo e a consulta com agrupamento fica lenta, quebrando o requisito de baixa latência. A saída é separar quem recebe os cliques de quem responde às consultas e fazer a agregação antes que o anunciante pergunte.

03 · DO LOTE AO STREAM

Agregar em lote e por que não basta

A melhoria natural grava os eventos brutos num event store otimizado para escrita e deixa um job periódico, por exemplo em Spark, ler esses eventos e gravar contagens por anúncio e por minuto num banco analítico. Bancos OLAP usam armazenamento colunar, muito rápido para agregações. Um banco de séries temporais serviria para consultas simples, mas com milhões de anúncios e várias dimensões de análise o OLAP atende melhor.

  1. O clique passa pelo balanceador e chega a uma instância do processador de cliques.

    Diagrama da arquitetura: Cliques: agregação em lote
    CLNavegador
    NWBalanceador
    CPProcessador de cliques
    DBEvent store
    CPJob de agregação em lote
    DBBanco analítico colunar
    CLPainel do anunciante
  2. O processador grava o evento bruto no event store, que absorve muitas escritas.

    Diagrama da arquitetura: Cliques: agregação em lote
    CLNavegador
    NWBalanceador
    CPProcessador de cliques
    DBEvent storeeventos brutos
    CPJob de agregação em lote
    DBBanco analítico colunar
    CLPainel do anunciante
  3. A cada intervalo, o job de agregação lê os eventos acumulados no event store.

    Diagrama da arquitetura: Cliques: agregação em lote
    CLNavegador
    NWBalanceador
    CPProcessador de cliques
    DBEvent store
    CPJob de agregação em loteroda por intervalo
    DBBanco analítico colunar
    CLPainel do anunciante
  4. O job agrega por anúncio e por minuto e grava as contagens no banco analítico.

    Diagrama da arquitetura: Cliques: agregação em lote
    CLNavegador
    NWBalanceador
    CPProcessador de cliques
    DBEvent store
    CPJob de agregação em lote
    DBBanco analítico colunarcontagens por minuto
    CLPainel do anunciante
  5. O anunciante consulta só o banco analítico, que já tem tudo agregado, e a resposta é rápida.

    Diagrama da arquitetura: Cliques: agregação em lote
    CLNavegador
    NWBalanceador
    CPProcessador de cliques
    DBEvent store
    CPJob de agregação em lote
    DBBanco analítico colunar
    CLPainel do anunciante

O custo é o atraso: o anunciante sempre enxerga dados com alguns minutos de idade. E numa rajada de cliques o próximo lote processa uma janela muito maior e pode demorar mais que o próprio intervalo, atrasando justo quando o anunciante mais quer olhar. Uma fila antes do event store ajudaria com os picos de escrita, mas não resolveria a latência.

04 · TEMPO REAL

Stream, janelas e o tempo do evento

A alternativa processa os eventos conforme chegam, em vez de esperar um job em lote: o processador de cliques escreve numa stream, como Kafka ou Kinesis, e um stream processor, como Flink, agrega em memória e grava o resultado no banco analítico. O Flink agrega pelo tempo do evento, quando o clique de fato ocorreu, e não pelo tempo em que o evento chegou, para acertar a contagem mesmo com eventos fora de ordem. Os watermarks acompanham o progresso do tempo do evento e tratam os eventos atrasados.

  1. Ao exibir o anúncio, o serviço de posicionamento entrega ao navegador um ID de impressão assinado, único para aquela exibição.

    Diagrama da arquitetura: Cliques: stream com reconciliação
    CPPosicionamento de anúnciosgera o ID assinado
    CLNavegador
    NWBalanceador
    CPProcessador de cliques
    CHCache de impressões
    QStream de cliques
    CPAgregador de stream
    DBData lake
    CPReconciliação em lote
    DBBanco analítico colunar
    CLPainel do anunciante
  2. No clique, o navegador envia o ID ao processador de cliques, que verifica a assinatura e consulta o cache de impressões.

    Diagrama da arquitetura: Cliques: stream com reconciliação
    CPPosicionamento de anúncios
    CLNavegador
    NWBalanceador
    CPProcessador de cliquesvalida e deduplica
    CHCache de impressõesjá contado?
    QStream de cliques
    CPAgregador de stream
    DBData lake
    CPReconciliação em lote
    DBBanco analítico colunar
    CLPainel do anunciante
  3. Se o clique é novo, o processador o grava na stream primeiro e só então registra o ID no cache; depois responde com o redirecionamento.

    Diagrama da arquitetura: Cliques: stream com reconciliação
    CPPosicionamento de anúncios
    CLNavegador
    NWBalanceador
    CPProcessador de cliques
    CHCache de impressões
    QStream de cliquesevento novo
    CPAgregador de stream
    DBData lake
    CPReconciliação em lote
    DBBanco analítico colunar
    CLPainel do anunciante
  4. O agregador de stream lê a stream, agrega por anúncio e por minuto e grava no banco analítico.

    Diagrama da arquitetura: Cliques: stream com reconciliação
    CPPosicionamento de anúncios
    CLNavegador
    NWBalanceador
    CPProcessador de cliques
    CHCache de impressões
    QStream de cliques
    CPAgregador de streamagrega por minuto
    DBData lake
    CPReconciliação em lote
    DBBanco analítico colunarcontagens quase em tempo real
    CLPainel do anunciante
  5. Em paralelo, a stream arquiva os eventos brutos no data lake, e a reconciliação em lote os reagrega e corrige o banco analítico se houver divergência.

    Diagrama da arquitetura: Cliques: stream com reconciliação
    CPPosicionamento de anúncios
    CLNavegador
    NWBalanceador
    CPProcessador de cliques
    CHCache de impressões
    QStream de cliques
    CPAgregador de stream
    DBData lakeeventos brutos
    CPReconciliação em lotereconcilia
    DBBanco analítico colunar
    CLPainel do anunciante
  6. O anunciante consulta o banco analítico e vê as métricas quase em tempo real.

    Diagrama da arquitetura: Cliques: stream com reconciliação
    CPPosicionamento de anúncios
    CLNavegador
    NWBalanceador
    CPProcessador de cliques
    CHCache de impressões
    QStream de cliques
    CPAgregador de stream
    DBData lake
    CPReconciliação em lote
    DBBanco analítico colunar
    CLPainel do anunciante

A janela pode fechar no limite do minuto enquanto os resultados parciais são descarregados a cada poucos segundos, então o minuto corrente aparece incompleto, como esperado, até acabar. Também é bem mais realista reduzir a janela do Flink do que aumentar a frequência de jobs Spark, por causa do overhead de cada job.

Um consumidor Kafka comum, com contador em memória, até funciona num cenário mais simples. Mas janelas por tempo do evento, watermarks e recuperação de estado construídos à mão sobre ele são viáveis e propensos a erro, e é isso que o stream processor entrega pronto.

05 · ESCALA E PARTIÇÕES QUENTES

Escalar cada etapa e o anúncio viral

Cada etapa escala horizontalmente: o processador atrás do balanceador, a stream por partições e o agregador com uma tarefa por partição. Particionar a stream por identificador do anúncio, o AdId, é natural, pois as partições ficam independentes e todos os eventos de um anúncio caem na mesma.

O problema que sobra é a partição quente: um anúncio que acabou de viralizar manda todos os cliques para uma só partição, que se sobrecarrega, aumenta a latência e, no pior caso, perde dados. Uma saída é anexar um número aleatório ao AdId na chave de partição, só para os anúncios populares, de modo que o tráfego se espalhe. Ao gravar no OLAP, o Flink remove o sufixo e usa o AdId original, e as somas das partições se combinam corretamente.

06 · NÃO PERDER, NÃO CONTAR EM DOBRO

Retenção, reconciliação e idempotência

Perder cliques é perder dinheiro, e a stream ajuda: por padrão ela é distribuída e tolerante a falhas, e pode reter os dados por um período mesmo depois de consumidos. Se o agregador cai, ele volta e relê a stream. Como as janelas são curtas, a queda custa no máximo um minuto de agregação, que se reprocessa a partir de um ponto conhecido da stream.

  1. O agregador de stream cai no meio do minuto, e o banco analítico para de receber contagens novas.

    Diagrama da arquitetura: Cliques: stream com reconciliação
    CPPosicionamento de anúncios
    CLNavegador
    NWBalanceador
    CPProcessador de cliques
    CHCache de impressões
    QStream de cliques
    CPAgregador de streamcaiu
    DBData lake
    CPReconciliação em lote
    DBBanco analítico colunar
    CLPainel do anunciante
  2. Os cliques continuam chegando à stream, que os retém mesmo sem ninguém consumindo.

    Diagrama da arquitetura: Cliques: stream com reconciliação
    CPPosicionamento de anúncios
    CLNavegador
    NWBalanceador
    CPProcessador de cliques
    CHCache de impressões
    QStream de cliquesretém os eventos
    CPAgregador de stream
    DBData lake
    CPReconciliação em lote
    DBBanco analítico colunar
    CLPainel do anunciante
  3. O agregador volta, relê a stream a partir de um ponto conhecido e reagrega o que faltava, e o banco analítico se atualiza.

    Diagrama da arquitetura: Cliques: stream com reconciliação
    CPPosicionamento de anúncios
    CLNavegador
    NWBalanceador
    CPProcessador de cliques
    CHCache de impressões
    QStream de cliques
    CPAgregador de streamreprocessa
    DBData lake
    CPReconciliação em lote
    DBBanco analítico colunarcontagem refeita
    CLPainel do anunciante

Mesmo assim, falhas de processamento, código com defeito ou eventos fora de ordem podem deixar pequenas imprecisões. Por isso os eventos brutos também vão para um data lake e um job periódico, por exemplo diário, em Spark, os reagrega. Se o resultado diverge do que a stream produziu, investiga-se a causa e corrige-se o banco analítico. Combinar uma camada rápida (Flink) com uma camada de lote (Spark) para correção é a arquitetura Lambda.

Para não contar o mesmo clique duas vezes, contar um clique por usuário e anúncio erra no retargeting, em que o mesmo anúncio é mostrado ao mesmo usuário várias vezes de propósito. O certo é contar um clique por instância de anúncio: o serviço de posicionamento gera um ID de impressão único a cada exibição, e o clique carrega esse ID como chave de idempotência.

A deduplicação precisa ocorrer antes da stream, porque um duplicado em lados opostos do limite do minuto contaria como dois cliques se a deduplicação ficasse dentro do agregador. Para impedir cliques forjados com IDs inventados, o ID é assinado com HMAC e chave secreta antes de ir ao navegador, e o processador verifica a assinatura.

Perguntas frequentes

O que é Agregação de cliques em anúncios?

Projeto de entrevista clássico. Pontos centrais: semântica de processamento de streams e ledger e conciliação.

O que o design de Agregação de cliques em anúncios cobre?

Ele está organizado nestas seções: O que um agregador de cliques precisa fazer, Redirecionar e registrar, a versão ingênua, Agregar em lote e por que não basta, Stream, janelas e o tempo do evento, Escalar cada etapa e o anúncio viral e Retenção, reconciliação e idempotência.

Quanto tempo leva Agregação de cliques em anúncios e qual é o nível?

Leva cerca de 17 minutos para ler e tem nível Staff.

Agora projete você mesmo

Rode este caso como uma entrevista na escola de System Design: você toma as decisões, o tutor as questiona e você vê a nota do seu desenho.