Pular para o conteúdo

Design clássico · Sênior

Amigos por perto

Projeto de entrevista clássico. Pontos centrais: WebSocket e presença e indexação geoespacial.

16 min de leitura · Conteúdo revisado em 23 de outubro de 2026

Resposta curta

Projeto de entrevista clássico. Pontos centrais: WebSocket e presença e indexação geoespacial. O exercício pede o backend de um aplicativo em que as pessoas compartilham a própria posição e descobrem quais amigos estão por perto. Diferente do caso de serviço de proximidade, aqui as localizações mudam o tempo todo, enquanto os endereços de estabelecimentos quase não mudam.

01 · CONTEXTO

Posições que não param de mudar

O exercício pede o backend de um aplicativo em que as pessoas compartilham a própria posição e descobrem quais amigos estão por perto. Diferente do caso de serviço de proximidade, aqui as localizações mudam o tempo todo, enquanto os endereços de estabelecimentos quase não mudam.

Em vez de consultar pontos parados, o sistema precisa distribuir uma corrente de atualizações a quem se interessa por elas.

No lado funcional, cada amigo aparece com distância e hora da atualização da posição, e a lista é atualizada a cada poucos segundos. "Perto" é um raio de cinco milhas, configurável, e o histórico de posições deve ser guardado, por exemplo para aprendizado de máquina.

No lado não funcional, a latência baixa importa para receber as atualizações sem muito atraso. Perder ocasionalmente um ponto de dados é aceitável, desde que o sistema esteja em geral disponível, e o armazenamento de posição não precisa de consistência forte.

02 · ESCALA

As contas que mandam no desenho

As premissas da fonte: a posição é atualizada a cada 30 segundos, porque quem anda a pé se move devagar; cem milhões de usuários usam a funcionalidade por dia, com 10% simultâneos, ou seja, dez milhões; e cada usuário tem em média 400 amigos, todos usando a funcionalidade.

Dividindo os dez milhões de usuários simultâneos pelo intervalo de 30 segundos, saem cerca de 334 mil atualizações de posição por segundo. Com 400 amigos e 10% deles online, cada atualização recebida gera cerca de 40 atualizações a encaminhar.

03 · ARQUITETURA

Servidor compartilhado e um canal por usuário

AbordagemO que a fonte diz
Ponto a pontoPouco prática para celular com conexão instável e restrição de energia
Servidor compartilhadoServe como mecanismo de fan-out para os amigos que se quer alcançar

O servidor compartilhado recebe as posições de todos os usuários ativos, acha para cada atualização os usuários ativos que devem recebê-la e a encaminha, sem repassar quando a distância entre os amigos passa do limite configurado.

Os servidores WebSocket são com estado e encaminham as atualizações aos clientes. O cache de localização guarda a posição mais recente de cada usuário ativo e cada entrada tem prazo de validade: ao expirar, o usuário deixa de ser ativo e seus dados saem do cache. O Pub/sub é um barramento leve com um canal por usuário. Servidores REST cuidam de tarefas auxiliares como amizades e perfis.

O histórico de posições não é necessariamente usado pela funcionalidade em si, e um banco como o Cassandra pode guardá-lo por ser otimizado para carga pesada de escrita.

  1. O celular envia a posição ao balanceador, que a encaminha à conexão persistente do cliente no servidor WebSocket.

    Diagrama da arquitetura: Caminho de uma atualização de posição
    CLCelular do usuárioenvia posição
    NWBalanceador
    CPServidor WebSocket do usuárioconexão persistente
    DBHistórico de posições
    CHCache de localização
    QPub/sub por usuário
    CPServidor WebSocket dos amigos
    CLCelular do amigo
    CPServidor REST
    DBBanco de usuários e amizades
  2. O servidor grava a posição no histórico e atualiza o cache de localização.

    Diagrama da arquitetura: Caminho de uma atualização de posição
    CLCelular do usuário
    NWBalanceador
    CPServidor WebSocket do usuário
    DBHistórico de posiçõesgrava
    CHCache de localizaçãoatualiza
    QPub/sub por usuário
    CPServidor WebSocket dos amigos
    CLCelular do amigo
    CPServidor REST
    DBBanco de usuários e amizades
  3. O servidor publica a posição no canal do usuário, via Pub/sub.

    Diagrama da arquitetura: Caminho de uma atualização de posição
    CLCelular do usuário
    NWBalanceador
    CPServidor WebSocket do usuário
    DBHistórico de posições
    CHCache de localização
    QPub/sub por usuáriocanal do usuário
    CPServidor WebSocket dos amigos
    CLCelular do amigo
    CPServidor REST
    DBBanco de usuários e amizades
  4. O Pub/sub difunde a atualização a todos os assinantes do canal, isto é, aos servidores responsáveis pelos amigos.

    Diagrama da arquitetura: Caminho de uma atualização de posição
    CLCelular do usuário
    NWBalanceador
    CPServidor WebSocket do usuário
    DBHistórico de posições
    CHCache de localização
    QPub/sub por usuáriodifunde
    CPServidor WebSocket dos amigosassinante
    CLCelular do amigo
    CPServidor REST
    DBBanco de usuários e amizades
  5. Cada servidor assinante calcula a quem a atualização deve ir e a envia ao celular do amigo.

    Diagrama da arquitetura: Caminho de uma atualização de posição
    CLCelular do usuário
    NWBalanceador
    CPServidor WebSocket do usuário
    DBHistórico de posições
    CHCache de localização
    QPub/sub por usuário
    CPServidor WebSocket dos amigoscalcula destinatários
    CLCelular do amigorecebe
    CPServidor REST
    DBBanco de usuários e amizades

04 · FAN-OUT

Quem assina o quê

Na inicialização, o servidor busca os amigos do usuário, assina os canais deles no Pub/sub, lê as posições no cache e as repassa ao cliente. Em regime, os servidores WebSocket assinam canais para os usuários conectados a eles, e cada publicação no canal de alguém chega aos servidores responsáveis por seus amigos.

  1. O servidor do remetente publica a posição no canal do usuário.

    Diagrama da arquitetura: Fan-out de uma posição pelos canais
    CPServidor WebSocket do remetentepublica
    QCanal do usuário
    CPServidor com amigo perto
    CPServidor com amigo longe
    CLAmigo perto
    CLAmigo longe
  2. O canal difunde a mesma atualização a todos os servidores que o assinam.

    Diagrama da arquitetura: Fan-out de uma posição pelos canais
    CPServidor WebSocket do remetente
    QCanal do usuáriodifunde
    CPServidor com amigo perto
    CPServidor com amigo longe
    CLAmigo perto
    CLAmigo longe
  3. Cada servidor assinante calcula a quem a atualização deve ir.

    Diagrama da arquitetura: Fan-out de uma posição pelos canais
    CPServidor WebSocket do remetente
    QCanal do usuário
    CPServidor com amigo pertocalcula distância
    CPServidor com amigo longecalcula distância
    CLAmigo perto
    CLAmigo longe
  4. Onde o amigo está dentro do limite de distância, a posição é repassada ao celular dele.

    Diagrama da arquitetura: Fan-out de uma posição pelos canais
    CPServidor WebSocket do remetente
    QCanal do usuário
    CPServidor com amigo pertorepassa
    CPServidor com amigo longe
    CLAmigo pertorecebe
    CLAmigo longe
  5. Onde a distância passa do limite configurado, o servidor não repassa a posição.

    Diagrama da arquitetura: Fan-out de uma posição pelos canais
    CPServidor WebSocket do remetente
    QCanal do usuário
    CPServidor com amigo perto
    CPServidor com amigo longedescarta
    CLAmigo perto
    CLAmigo longe

No Pub/sub, o publicador não conhece os assinantes: as mensagens são categorizadas em canais, e os assinantes as recebem na ordem em que foram publicadas. Canal criado e sem uso não consome memória, o que permite pré-alocar canais para todos os usuários da funcionalidade.

05 · GARANTIAS

O que o Pub/sub promete e o que não promete

A documentação do Redis diz que o Pub/sub entrega no máximo uma vez, e que, se o assinante não consegue tratar a mensagem, ela se perde para sempre. Do lado do requisito, perder ocasionalmente um ponto de dados é aceitável.

MecanismoO que a documentação diz
Pub/sub do RedisEntrega no máximo uma vez; a mensagem que o assinante não consegue tratar se perde para sempre
Redis StreamsAs mensagens são persistidas

06 · BARRAMENTO

Espalhando os canais por muitos servidores

Na estimativa da fonte, é preciso empurrar cerca de 14 milhões de atualizações por segundo. Supondo 100 mil pushes por segundo por servidor, são necessários pelo menos 140 servidores Redis, e por isso um cluster distribuído por causa da carga de CPU.

Para sustentar o cluster, a fonte usa um componente de descoberta de serviço, como ZooKeeper ou etcd, para saber quais servidores estão vivos. Os servidores WebSocket usam os dados guardados ali para achar onde mora cada canal, e o anel de hash pode ficar em memória em cada um deles.

  1. O servidor WebSocket precisa saber onde mora o canal; ele consulta o anel de hash vindo da descoberta de serviço, que pode ficar em memória nele.

    Diagrama da arquitetura: Barramento de canais distribuído
    CPServidores WebSocket
    DBDescoberta de serviçoanel de hash
    QNó de Pub/sub A
    QNó de Pub/sub B
    QNó de Pub/sub novo
  2. O canal do usuário cai no nó indicado pelo anel.

    Diagrama da arquitetura: Barramento de canais distribuído
    CPServidores WebSocket
    DBDescoberta de serviço
    QNó de Pub/sub A
    QNó de Pub/sub Bdono do canal
    QNó de Pub/sub novo
  3. O servidor publica e assina o canal diretamente nesse nó.

    Diagrama da arquitetura: Barramento de canais distribuído
    CPServidores WebSocket
    DBDescoberta de serviço
    QNó de Pub/sub A
    QNó de Pub/sub Bpublica e assina
    QNó de Pub/sub novo
  4. Quando um nó é acrescentado, o hash consistente minimiza os canais que mudam de lugar.

    Diagrama da arquitetura: Barramento de canais distribuído
    CPServidores WebSocket
    DBDescoberta de serviço
    QNó de Pub/sub A
    QNó de Pub/sub B
    QNó de Pub/sub novonovo nó
  5. Os servidores WebSocket refazem as assinaturas dos canais movidos, e algumas atualizações podem se perder nesse intervalo.

    Diagrama da arquitetura: Barramento de canais distribuído
    CPServidores WebSocketreassinam canais
    DBDescoberta de serviço
    QNó de Pub/sub A
    QNó de Pub/sub B
    QNó de Pub/sub novo

A documentação do Redis descreve ainda o Pub/sub fragmentado, que ajuda a escalar o Pub/sub em modo cluster e limita o tráfego no barramento do cluster em comparação com o Pub/sub global, em que cada mensagem vai a todos os nós.

A fonte também cita Erlang como alternativa ao Redis, que permitiria criar milhões de pequenos processos que se comunicam entre si, ao custo de ser uma linguagem de nicho em que pode ser difícil contratar pessoas com experiência.

07 · BORDAS

Casos de borda

Para usuários com muitos amigos, a fonte sugere limitar o número de amigos, por exemplo com um teto de cinco mil. O servidor de um usuário assim pode ter mais carga, mas com servidores suficientes fica bem.

Para a variação em que aparecem pessoas aleatórias por perto, define-se um conjunto de canais de Pub/sub por geohash, e é possível assinar vários geohashes para cobrir quem está perto mas em um geohash vizinho.

Ao retirar um servidor, marca-se o servidor como draining no balanceador para parar de mandar conexões a ele.

Perguntas frequentes

O que é Amigos por perto?

Projeto de entrevista clássico. Pontos centrais: WebSocket e presença e indexação geoespacial.

O que o design de Amigos por perto cobre?

Ele está organizado nestas seções: Posições que não param de mudar, As contas que mandam no desenho, Servidor compartilhado e um canal por usuário, Quem assina o quê, O que o Pub/sub promete e o que não promete e Espalhando os canais por muitos servidores.

Quanto tempo leva Amigos por perto e qual é o nível?

Leva cerca de 16 minutos para ler e tem nível Sênior.

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.