Pular para o conteúdo

Arquitetura real · Staff

Facebook: escalando o Memcache (NSDI 2013)

Arquitetura real em produção. Pontos centrais: controle de sobrecarga.

18 min de leitura · Fonte: Facebook · Conteúdo revisado em 23 de outubro de 2026

Resposta curta

Arquitetura real em produção. Pontos centrais: controle de sobrecarga. O Facebook servia uma rede social em que as pessoas consomem muito mais conteúdo do que criam. Essa assimetria entre leitura e escrita é o ponto de partida do artigo: se a carga é dominada por busca de dados, um cache rende muito.

01 · CONTEXTO

Um cache na frente de um banco que não aguentaria sozinho

O Facebook servia uma rede social em que as pessoas consomem muito mais conteúdo do que criam. Essa assimetria entre leitura e escrita é o ponto de partida do artigo: se a carga é dominada por busca de dados, um cache rende muito. O sistema descrito, construído sobre o memcached, chegou a tratar bilhões de requisições por segundo e a guardar trilhões de itens.

O padrão de base é o cache look-aside preenchido sob demanda. Na leitura, o servidor web pergunta ao cache; num miss, busca no banco e grava o par chave-valor no cache. Na escrita, ele grava no banco e envia um delete ao cache para invalidar o dado velho. A escolha por apagar em vez de atualizar tem uma razão explícita: deletes são idempotentes. E o cache não é a fonte da verdade, então pode descartar itens.

  1. O usuário pede uma página. O servidor web precisa de vários dados para montá-la e começa pelo cache.

    Diagrama da arquitetura: Cache look-aside na frente do banco
    CLUsuário
    CPServidor webmonta a página
    CHMemcache
    DBBanco MySQL
  2. O servidor web pergunta ao cache pela chave. Se o item está lá, é um hit e o banco nem é consultado.

    Diagrama da arquitetura: Cache look-aside na frente do banco
    CLUsuário
    CPServidor web
    CHMemcachehit
    DBBanco MySQL
  3. Se o item não está no cache, é um miss: o servidor web busca o dado no banco, que guarda a cópia autoritativa.

    Diagrama da arquitetura: Cache look-aside na frente do banco
    CLUsuário
    CPServidor web
    CHMemcache
    DBBanco MySQLconsulta no miss
  4. Com o dado em mãos, o servidor web grava o par chave-valor no cache. A próxima leitura da mesma chave será atendida pela memória.

    Diagrama da arquitetura: Cache look-aside na frente do banco
    CLUsuário
    CPServidor web
    CHMemcachepreenchido sob demanda
    DBBanco MySQL
  5. Numa escrita, o servidor web grava no banco e depois manda um delete ao cache. O dado velho some e a próxima leitura recarrega o valor novo.

    Diagrama da arquitetura: Cache look-aside na frente do banco
    CLUsuário
    CPServidor web
    CHMemcachechave apagada
    DBBanco MySQLgrava primeiro

Dois objetivos guiam as escolhas do projeto. Um deles é incomum: a probabilidade de ler dado ligeiramente velho é tratada como um parâmetro a ajustar, como a responsividade. O time aceita expor dado levemente velho para proteger o armazenamento de carga excessiva.

02 · NO CLUSTER: LATÊNCIA E CARGA

Milhares de servidores, uma página que pede centenas de itens

Uma página popular carregava, em média, 521 itens distintos do memcache, e os itens se espalham pelos servidores por hashing consistente. O resultado é que os servidores web acabam falando com todos os servidores de cache em curto intervalo. Esse padrão todos-com-todos pode causar congestionamento por incast ou transformar um único servidor em gargalo para muitos clientes.

A complexidade fica no cliente, não no servidor. Os servidores de memcached não conversam entre si; roteamento, serialização, compressão e agrupamento de pedidos vivem num cliente sem estado, que pode ser uma biblioteca ou o proxy mcrouter. Para gets, o cliente usa UDP, que reduz latência e custo; erro de get vira miss, e o servidor web evita reinserir a entrada para não sobrecarregar uma rede ou servidor já pressionado. Sets e deletes vão por TCP, via mcrouter na mesma máquina, porque precisam de confirmação. Para limitar o incast, uma janela deslizante controla os pedidos em andamento: ela cresce devagar a cada sucesso e encolhe quando um pedido fica sem resposta.

Duas falhas de coerência aparecem no cache sob demanda. O stale set acontece quando atualizações concorrentes chegam fora de ordem e um servidor grava no cache um valor que já não é o mais recente. A manada de leituras (thundering herd) acontece quando uma chave muito lida e muito escrita é invalidada sem parar e muitas leituras caem no caminho caro. A solução do artigo são os leases: no miss, o memcached entrega ao cliente um token ligado àquela chave, e só quem apresenta um token ainda válido consegue gravar. Se um delete invalidou o token, a gravação é recusada. Um ajuste simples cura a manada: o servidor devolve um token só uma vez a cada 10 segundos por chave, e quem pede nesse intervalo recebe a orientação de esperar um pouco.

  1. Um cliente pede uma chave popular que acabou de ser invalidada. O servidor de cache dá miss e entrega a esse cliente um lease para aquela chave.

    Diagrama da arquitetura: Um cluster de memcache com mcrouter e Gutter
    CPServidores web com cliente
    CPmcrouter
    CHMemcached Aemite o lease
    CHMemcached B
    CHGutter
    DBBanco MySQL
  2. Outros clientes pedem a mesma chave logo depois. Em vez de um segundo token, recebem a orientação de esperar um pouco e tentar de novo, e a manada não chega ao banco.

    Diagrama da arquitetura: Um cluster de memcache com mcrouter e Gutter
    CPServidores web com cliente
    CPmcrouter
    CHMemcached Asegura os demais
    CHMemcached B
    CHGutter
    DBBanco MySQL
  3. Quem detém o lease busca o valor no banco e o grava no cache apresentando o token. Os que esperavam voltam e, em geral, já encontram o dado.

    Diagrama da arquitetura: Um cluster de memcache com mcrouter e Gutter
    CPServidores web com cliente
    CPmcrouter
    CHMemcached A
    CHMemcached B
    CHGutter
    DBBanco MySQLsó um cliente consulta
  4. Se um delete chegar antes dessa gravação, o token é invalidado e o set é recusado. Assim, uma escrita atrasada não põe valor velho por cima de um mais novo.

    Diagrama da arquitetura: Um cluster de memcache com mcrouter e Gutter
    CPServidores web com cliente
    CPmcrouter
    CHMemcached Atoken invalidado
    CHMemcached B
    CHGutter
    DBBanco MySQL

Em uma medição de uma semana sobre chaves especialmente sujeitas à manada, o pico de consultas ao banco foi de 17 mil por segundo sem leases e de 1,3 mil por segundo com leases. Como o banco é dimensionado pelo pico, isso vira ganho de eficiência. O mesmo mecanismo permite um atalho: aplicações que progridem com dado ligeiramente velho podem aceitar o valor marcado como stale em vez de esperar o banco.

Cargas diferentes disputam a mesma memória, então o cluster é dividido em pools. Sem isso, chaves de baixo giro ainda valiosas eram expulsas antes de chaves de alto giro que ninguém mais acessava; colocar chaves de giro diferente em pools distintos evita essa interferência e permite dimensionar cada pool pelo custo do miss. Em alguns pools o artigo prefere replicar um conjunto pequeno de chaves muito pedidas a dividi-lo ainda mais, e isso exige entregar as invalidações a todas as réplicas.

03 · FALHAS E O POOL GUTTER

Quando o cache falha, o banco paga

Não conseguir buscar do cache gera carga excessiva nos serviços de trás e pode provocar falhas em cascata. A remediação automática de poucos hosts não é instantânea e pode levar alguns minutos, tempo suficiente para a cascata acontecer. Para cobrir esse intervalo, uma pequena frota dedicada, chamada Gutter, assume as responsabilidades de alguns servidores falhos. Ela representa cerca de 1% dos servidores de memcached de um cluster.

  1. Um servidor de cache cai. O cliente pede uma chave dele e não recebe resposta.

    Diagrama da arquitetura: Um cluster de memcache com mcrouter e Gutter
    CPServidores web com cliente
    CPmcrouter
    CHMemcached Asem resposta
    CHMemcached B
    CHGutter
    DBBanco MySQL
  2. O cliente supõe que o servidor falhou e repete o pedido num pool Gutter, uma frota separada de servidores ociosos.

    Diagrama da arquitetura: Um cluster de memcache com mcrouter e Gutter
    CPServidores web com cliente
    CPmcrouter
    CHMemcached A
    CHMemcached B
    CHGuttersegunda chance
    DBBanco MySQL
  3. Se o Gutter também der miss, o cliente busca no banco e insere o par no Gutter. Os pedidos seguintes da mesma chave já acham o dado ali.

    Diagrama da arquitetura: Um cluster de memcache com mcrouter e Gutter
    CPServidores web com cliente
    CPmcrouter
    CHMemcached A
    CHMemcached B
    CHGutterpreenchido após o miss
    DBBanco MySQLmenos consultas
  4. As entradas do Gutter duram pouco: o preço da proteção ao banco é servir, por um tempo curto, dado levemente velho.

    Diagrama da arquitetura: Um cluster de memcache com mcrouter e Gutter
    CPServidores web com cliente
    CPmcrouter
    CHMemcached A
    CHMemcached B
    CHGutterdado levemente velho
    DBBanco MySQL

Por que não redistribuir as chaves do servidor falho entre os demais? Porque o acesso por chave é desigual: quem herdar uma chave muito quente pode se sobrecarregar, e a falha vira cascata. O Gutter desvia a carga para servidores ociosos e limita esse risco. Segundo o artigo, o mecanismo reduz em 99% a taxa de falhas visíveis ao cliente.

04 · NA REGIÃO: REPLICAÇÃO ENTRE CLUSTERS

Mais clusters, menos dependência de um só

Comprar mais servidores não resolve tudo: o incast piora conforme o número de servidores de memcached aumenta. O Facebook então dividiu web e memcached em vários clusters de front-end que, junto de um cluster de armazenamento com os bancos, formam uma região. A troca é explícita: abre-se mão de replicação de dados em troca de domínios de falha mais independentes.

O cluster de armazenamento tem a cópia autoritativa e responde por invalidar os clusters de front-end. Para isso, os comandos SQL que alteram estado são ampliados com as chaves de cache a invalidar quando a transação confirma, e um daemon (mcsqueal) em cada banco lê os deletes dos commits e os transmite aos caches de todos os clusters da região, em lotes para reduzir pacotes. Como a invalidação está nos logs confiáveis do banco, o mcsqueal pode reexecutar invalidações perdidas ou mal roteadas, algo que o envio direto pelos servidores web não permite.

Cada cluster guarda o que os seus usuários pedem, e replicar tudo em todos os clusters desperdiça memória. Para reduzir o número de réplicas, vários clusters compartilham o mesmo conjunto de servidores de memcached: é o pool regional. A troca é declarada: cruzar fronteiras de cluster custa mais latência e a rede tem 40% menos banda média entre clusters do que dentro de um, enquanto a replicação gasta mais servidores para ter menos tráfego entre clusters, latência menor e melhor tolerância a falhas. Por isso a escolha entre replicar e manter uma única cópia por região depende do item.

Um cluster novo, ou um que volta de manutenção, tem cache vazio e taxa de acerto péssima. O Cold Cluster Warmup deixa os clientes do cluster frio lerem de um cluster quente em vez do armazenamento persistente, e leva a recuperação da capacidade plena de poucos dias para poucas horas. Para evitar inconsistência por corrida, os deletes no cluster frio levam por padrão um hold-off de dois segundos, durante o qual operações add são rejeitadas: se o add falha, o cliente sabe que há dado mais novo no banco e o busca lá. O artigo admite que resta a possibilidade teórica de um delete atrasar mais que isso, e a considera rara.

05 · ENTRE REGIÕES: CONSISTÊNCIA

A réplica do banco pode estar atrasada

Com várias regiões, uma região guarda os bancos mestres e as demais têm réplicas somente de leitura. Nesse desenho, manter a consistência entre memcache e armazenamento persistente vira o principal desafio técnico, e ele nasce de um só problema: a réplica do banco pode estar atrasada em relação ao mestre. O modelo escolhido é consistência eventual de melhor esforço, com ênfase em desempenho e disponibilidade; as ideias de semântica mais estrita raramente saem da fase de projeto por serem caras demais.

Considere uma escrita na região mestre. Se o servidor web invalidasse o cache de uma região réplica logo após gravar, a invalidação poderia chegar antes de os dados chegarem à réplica, e a leitura seguinte recolocaria dado velho no cache. Por isso a invalidação sai do cluster de armazenamento, por daemon, e o fluxo de deletes compartilha o canal da replicação do banco.

Agora, uma escrita numa região não mestre com a réplica muito atrasada: a pessoa pode não ver a própria mudança. O artigo usa um marcador remoto. O servidor web cria um marcador para a chave na região, escreve no mestre embutindo a chave e o marcador a invalidar no SQL e apaga a chave no cluster local. Na leitura seguinte, o miss leva o servidor a checar o marcador: se ele existe, a consulta vai ao mestre; se não, à réplica local. É uma troca explícita, com mais latência no miss em troca de menor chance de ler dado velho.

  1. Escrita na região mestre: o servidor web grava no MySQL mestre, e o SQL carrega as chaves de cache a invalidar.

    Diagrama da arquitetura: Região mestre e região réplica
    CPWeb da região mestre
    DBMySQL mestregrava e registra as chaves
    CPmcsqueal da região mestre
    CHMemcache da região mestre
    DBMySQL réplica
    CPmcsqueal da região réplica
    CHMemcache da região réplica
    CHMarcador remoto
    CPWeb da região réplica
  2. O mcsqueal lê o que o banco confirmou e apaga as chaves nos caches da região mestre.

    Diagrama da arquitetura: Região mestre e região réplica
    CPWeb da região mestre
    DBMySQL mestre
    CPmcsqueal da região mestre
    CHMemcache da região mestrechave apagada
    DBMySQL réplica
    CPmcsqueal da região réplica
    CHMemcache da região réplica
    CHMarcador remoto
    CPWeb da região réplica
  3. A replicação leva a mudança à réplica; só depois o mcsqueal da região réplica, que lê a réplica, apaga a chave no cache de lá. A invalidação nunca passa à frente do dado.

    Diagrama da arquitetura: Região mestre e região réplica
    CPWeb da região mestre
    DBMySQL mestre
    CPmcsqueal da região mestre
    CHMemcache da região mestre
    DBMySQL réplicarecebe a mudança
    CPmcsqueal da região réplica
    CHMemcache da região réplicachave apagada depois
    CHMarcador remoto
    CPWeb da região réplica
  4. Escrita numa região não mestre: o servidor web cria o marcador da chave, escreve no mestre e apaga a chave no cache local.

    Diagrama da arquitetura: Região mestre e região réplica
    CPWeb da região mestre
    DBMySQL mestrerecebe a escrita
    CPmcsqueal da região mestre
    CHMemcache da região mestre
    DBMySQL réplica
    CPmcsqueal da região réplica
    CHMemcache da região réplica
    CHMarcador remotomarca a chave
    CPWeb da região réplica
  5. Na leitura seguinte, o cache local dá miss e o servidor encontra o marcador, então manda a consulta ao mestre. A réplica, que ainda pode estar atrasada, é evitada.

    Diagrama da arquitetura: Região mestre e região réplica
    CPWeb da região mestre
    DBMySQL mestre
    CPmcsqueal da região mestre
    CHMemcache da região mestre
    DBMySQL réplicapode estar atrasada
    CPmcsqueal da região réplica
    CHMemcache da região réplica
    CHMarcador remotoaponta para o mestre
    CPWeb da região réplica

06 · TRADE-OFFS

O que cada mecanismo compra e cobra

MecanismoProblema que atacaCusto assumido
LeaseStale set e manada de leituras no missClientes que pedem no intervalo esperam um pouco
GutterQueda de poucos servidores sem inundar o bancoDado levemente velho por um tempo curto
Pool regionalRéplicas demais de itens grandes e pouco acessadosMais latência ao cruzar a fronteira do cluster
Marcador remotoLer uma réplica de banco atrasada após uma escritaLatência adicional no miss
UDP nos getsLatência e custo de manter conexõesErro de get vira miss, sem tentativa de recuperação

Repare no padrão: quase todo mecanismo aceita um pouco de dado velho ou de latência em troca de proteger o banco. É o objetivo declarado do projeto aplicado a cada escala: no cluster, leases e Gutter; na região, pools regionais e invalidação por commit; entre regiões, o marcador remoto.

Perguntas frequentes

O que é Facebook: escalando o Memcache (NSDI 2013)?

Arquitetura real em produção. Pontos centrais: controle de sobrecarga.

O que o design de Facebook: escalando o Memcache (NSDI 2013) cobre?

Ele está organizado nestas seções: Um cache na frente de um banco que não aguentaria sozinho, Milhares de servidores, uma página que pede centenas de itens, Quando o cache falha, o banco paga, Mais clusters, menos dependência de um só, A réplica do banco pode estar atrasada e O que cada mecanismo compra e cobra.

Quanto tempo leva Facebook: escalando o Memcache (NSDI 2013) e qual é o nível?

Leva cerca de 18 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.