Vista geral da arquitetura do Pub/Sub

O Pub/Sub é um serviço de mensagens assíncronas concebido para ser altamente fiável e escalável. O serviço é criado com base num componente de infraestrutura principal da Google no qual muitos produtos Google confiam há mais de uma década. Os produtos Google, incluindo o Google Ads, a Pesquisa e o Gmail, usam esta infraestrutura para enviar mais de 500 milhões de mensagens por segundo, totalizando mais de 1 TB/s de dados. Este artigo descreve as caraterísticas de design importantes que permitem ao Pub/Sub oferecer este tipo de escala de forma fiável.

Avaliar o desempenho de um serviço de mensagens

Um serviço de mensagens como o Pub/Sub pode ser avaliado com base no respetivo desempenho em três aspetos: escalabilidade, disponibilidade e latência. Estes três fatores estão frequentemente em conflito entre si, o que exige compromissos num para melhorar os outros dois.

Os termos "escalabilidade", "disponibilidade" e "latência" podem referir-se a diferentes propriedades de um sistema, pelo que as secções seguintes descrevem como são definidos no Pub/Sub.

Escalabilidade

Um serviço escalável deve conseguir processar aumentos na carga sem uma degradação percetível da latência ou da disponibilidade. "Carga" pode referir-se a várias dimensões de utilização no Pub/Sub:

  • Número de tópicos

  • Número de publicadores

  • Número de subscrições

  • Número de subscritores

  • Número de mensagens

  • Tamanho das mensagens

  • Taxa de mensagens (débito) publicadas ou consumidas

  • Tamanho da lista de pendências de qualquer subscrição

Disponibilidade

Num sistema distribuído, os tipos e a gravidade dos problemas podem variar muito. A disponibilidade de um sistema é medida com base na forma como lida com diferentes tipos de problemas, falhando graciosamente de uma forma impercetível para os utilizadores finais. As falhas podem ocorrer no hardware (por exemplo, as unidades de disco não funcionam ou problemas de conetividade de rede), no software e devido à carga. A falha devido ao carregamento pode ocorrer quando um aumento súbito no tráfego no serviço (ou noutros componentes de software executados no mesmo hardware ou em dependências de software) resulta na escassez de recursos. A disponibilidade também pode degradar-se devido a erro humano, quando se cometem erros na criação ou na implementação de software ou configurações.

Latência

A latência é uma medida baseada no tempo do desempenho de um sistema. Geralmente, um serviço quer minimizar a latência sempre que possível. Para o Pub/Sub, as duas métricas de latência mais importantes são:

  1. O tempo necessário para acusar a receção de uma mensagem publicada.

  2. O tempo necessário para entregar uma mensagem publicada a um subscritor.

Arquitetura básica do Pub/Sub

Esta secção explica a conceção do Pub/Sub para mostrar como o serviço atinge a escalabilidade e a baixa latência, mantendo a disponibilidade. O sistema foi concebido para ser horizontalmente escalável, em que um aumento no número de tópicos, subscrições ou mensagens pode ser processado aumentando o número de instâncias de servidores em execução.

Os servidores do Pub/Sub são executados em todas as regiões do Google Cloud em todo o mundo. Isto permite que o serviço ofereça um acesso rápido e global aos dados, ao mesmo tempo que dá aos utilizadores o controlo sobre a localização de armazenamento das mensagens. O Cloud Pub/Sub oferece acesso global a dados, uma vez que os clientes publicadores e subscritores não têm conhecimento da localização dos servidores aos quais se ligam nem de como esses serviços encaminham os dados.

Os mecanismos de equilíbrio de carga do Pub/Sub direcionam o tráfego do publicador para o centro de dados do Google Cloud mais próximo onde o armazenamento de dados é permitido, conforme definido na secção Restrição de localização de recursos da consola de administração e IAM. Isto significa que os publicadores em várias regiões podem publicar mensagens num único tópico com baixa latência. Cada mensagem individual é armazenada numa única região. No entanto, um tópico pode ter mensagens armazenadas em muitas regiões. Quando um cliente subscritor pede mensagens publicadas neste tópico, liga-se ao servidor mais próximo que agrega dados de todas as mensagens publicadas no tópico para entrega ao cliente.

O Pub/Sub está dividido em duas partes principais: o plano de dados, que processa a movimentação de mensagens entre publicadores e subscritores, e o plano de controlo, que processa a atribuição de publicadores e subscritores a servidores no plano de dados. Os servidores no plano de dados são denominados encaminhadores e os servidores no plano de controlo são denominados routers. Quando os publicadores e os subscritores estão ligados aos respetivos encaminhadores atribuídos, não precisam de informações dos routers (desde que esses encaminhadores permaneçam acessíveis). Por conseguinte, é possível atualizar o plano de controlo do Pub/Sub sem afetar os clientes que já estão ligados e a enviar ou receber mensagens.

Plano de controlo

O plano de controlo do Pub/Sub distribui os clientes pelos encaminhadores de uma forma que oferece escalabilidade, disponibilidade e baixa latência para todos os clientes. Qualquer encaminhador é capaz de publicar clientes para qualquer tópico ou subscrição. Quando um cliente se liga ao Pub/Sub, o router decide os centros de dados aos quais o cliente se deve ligar com base na distância da rede mais curta, uma medida da latência na ligação entre dois pontos. Em qualquer centro de dados, o router tenta distribuir a carga geral pelo conjunto de encaminhadores disponíveis. O router tem de equilibrar dois objetivos diferentes ao realizar esta atribuição: (a) uniformidade da carga (ou seja, idealmente, cada encaminhador é carregado igualmente); e (b) estabilidade das atribuições (ou seja, idealmente, uma alteração na carga ou uma alteração no conjunto de encaminhadores disponíveis altera o menor número de atribuições existentes). O router usa uma variante da aplicação de hash consistente desenvolvida pela Google Research para alcançar um equilíbrio ajustável entre a consistência e a uniformidade. O router fornece ao cliente uma lista ordenada de encaminhadores aos quais pode considerar estabelecer ligação. Esta lista ordenada pode mudar com base na disponibilidade do encaminhador e no formato do carregamento do cliente.

Um cliente recebe esta lista de encaminhadores e liga-se a um ou mais deles. O cliente prefere estabelecer ligação aos encaminhadores mais recomendados pelo router, mas também tem em consideração as falhas que ocorreram. Por exemplo, pode decidir experimentar encaminhadores num centro de dados diferente se várias tentativas aos mais próximos tiverem falhado. Para abstrair os clientes do Pub/Sub destes detalhes de implementação, existe um proxy de serviço entre os clientes e os encaminhadores que realiza esta otimização da ligação em nome dos clientes.

Plano de dados: o ciclo de vida de uma mensagem

O plano de dados recebe mensagens dos publicadores e envia-as para os clientes. Talvez a melhor forma de compreender o plano de dados do Pub/Sub seja analisar o ciclo de vida de uma mensagem, desde o momento em que é recebida pelo serviço até ao momento em que deixa de estar presente no serviço. Vamos analisar os passos de processamento de uma mensagem. Para efeitos desta secção, assumimos que o tópico no qual a mensagem é publicada tem, pelo menos, uma subscrição associada. Em geral, uma mensagem passa por estes passos:

  1. Um publicador envia uma mensagem.

  2. A mensagem é escrita no armazenamento.

  3. O Pub/Sub envia uma confirmação ao publicador de que recebeu a mensagem e garante a respetiva entrega a todas as subscrições anexadas.

  4. Ao mesmo tempo que escreve a mensagem no armazenamento, o Pub/Sub envia-a para os subscritores.

  5. Os subscritores enviam uma confirmação ao Pub/Sub de que processaram a mensagem.

  6. Assim que, pelo menos, um subscritor de cada subscrição tiver confirmado a mensagem, o Pub/Sub elimina a mensagem do armazenamento.

Primeiro, um publicador envia uma mensagem num tópico para o Pub/Sub. É encriptado pela camada de proxy e enviado para um encaminhador de publicação, um encaminhador ao qual o publicador está ligado. Para garantir a entrega, a mensagem é imediatamente escrita no armazenamento. O encaminhador escreve inicialmente a mensagem em N clusters (em que N é um número ímpar) e considera a mensagem persistente quando tiver sido escrita em, pelo menos, ⌈N/2⌉ clusters. Assim que uma mensagem é persistida, o encaminhador de publicação confirma a receção da mensagem ao publicador, momento em que o Pub/Sub garante que a mensagem é entregue a todas as subscrições anexadas.

Em cada cluster, a mensagem é escrita em M discos independentes (em que M é um número ímpar), o que requer que os dados estejam em ⌈M/2⌉ discos antes de serem considerados persistentes nesse cluster. No total, qualquer mensagem publicada é escrita em, pelo menos, ⌈M/2⌉ discos independentes em ⌈N/2⌉ clusters antes de ser considerada persistente e, eventualmente, é replicada para N*M discos.

O encaminhador de publicação tem uma lista de todas as subscrições associadas a um tópico. É responsável por persistir as mensagens publicadas e os metadados que descrevem que mensagens foram reconhecidas por cada subscrição. O conjunto de mensagens recebidas e armazenadas por um encaminhador de publicação para um tópico específico, juntamente com este acompanhamento de mensagens reconhecidas, é denominado "origem de mensagens de publicação". Consoante os requisitos de débito para o tópico, um único publicador pode enviar as respetivas mensagens para vários encaminhadores de publicação e armazenar mensagens em várias origens de mensagens de publicação. Diferentes publicadores para o mesmo tópico também podem enviar mensagens para diferentes encaminhadores de publicação. Cada mensagem é enviada apenas para um encaminhador de publicação. O Pub/Sub ajusta dinamicamente o número de encaminhadores de publicação que recebem mensagens para um tópico específico à medida que o débito muda.

Os subscritores recebem mensagens através da ligação a encaminhadores de subscrição, encaminhadores através dos quais as mensagens fluem para os subscritores a partir dos publicadores. "Estabelecer ligação" no caso de um subscritor de obtenção significa emitir um pedido de obtenção. "Estabelecer ligação" no caso de um subscritor de push significa ter o ponto final de push registado no Pub/Sub. Uma vez criada uma subscrição, é garantido que todas as mensagens publicadas após esse momento são entregues nessa subscrição, o que chamamos de garantia de ponto de sincronização.

Cada encaminhador subscritor tem de pedir mensagens a encaminhadores publicadores que tenham fontes de mensagens de publicação para o tópico. Tal como os publicadores, os subscritores podem estabelecer ligação a mais do que um encaminhador de subscrições para receber mensagens. Desta forma, nem todos os encaminhadores subscritos têm de estar cientes ou receber mensagens de todas as origens de mensagens de publicação para um tópico, uma propriedade importante para o Pub/Sub poder ser dimensionado horizontalmente. Com base no débito das mensagens entregues aos subscritores, o Pub/Sub ajusta dinamicamente o número de encaminhadores subscritos através dos quais os subscritores recebem mensagens para um tópico específico à medida que o débito muda.

Um encaminhador subscritor faz pedidos a um ou mais encaminhadores publicadores que têm origens de mensagens de publicação para um tópico para pedir as mensagens de que precisa. O encaminhador de publicação envia as mensagens não reconhecidas para o encaminhador de subscrição, que retransmite as mensagens para um subscritor.

Quando um subscritor processa uma mensagem, envia uma confirmação de volta para o encaminhador subscrito. O encaminhador subscrito retransmite esta confirmação ao encaminhador de publicação, que armazena a confirmação na origem da mensagem de publicação. Assim que todas as subscrições num tópico tiverem confirmado uma mensagem, a mensagem é eliminada de forma assíncrona da origem da mensagem de publicação e do armazenamento.

As diferentes mensagens para um único tópico e subscrição podem fluir através de muitos publicadores, subscritores, encaminhadores de publicação e encaminhadores de subscrição. Os publicadores podem publicar em vários encaminhadores em simultâneo e os subscritores podem estabelecer ligação a vários encaminhadores de subscrição para receber mensagens. Por conseguinte, o fluxo de mensagens através de ligações entre publicadores, subscritores e encaminhadores pode ser complexo. O diagrama seguinte mostra como as mensagens podem fluir para um único tópico e subscrição, em que as diferentes cores indicam os diferentes caminhos que as mensagens podem percorrer dos publicadores para os subscritores:

As mensagens de vários publicadores fluem através de encaminhadores de publicação e subscrição para os subscritores.

Manter o Pub/Sub em funcionamento

Garantir que um sistema distribuído como o Pub/Sub se mantém em funcionamento e serve eficazmente todos os clientes requer um grande nível de visibilidade e controlo do sistema. A manutenção do serviço é da responsabilidade dos nossos engenheiros de fiabilidade de sites (EFS). Para o Pub/Sub, estes engenheiros estão localizados em vários locais em todo o mundo para oferecer cobertura 24 horas por dia, 7 dias por semana.

Ambientes

A primeira parte da manutenção de um sistema como o Pub/Sub é ter a capacidade de testar o software antes de ser usado pelos clientes. Para tal, existem três ambientes do Pub/Sub: teste, preparação e produção. Os ambientes de teste e de preparação não contêm tráfego de clientes. Contêm apenas os nossos testes e monitorização em execução contínua que ajudam a encontrar problemas com os lançamentos. Estes ambientes recebem novos lançamentos do software antes da produção. A diferença entre o teste e a preparação é que esta última é uma réplica exata do que está (ou estará muito em breve) no ambiente de produção, incluindo a versão do software e as flags da linha de comandos. A primeira pode ter funcionalidades ativadas nas quais os programadores estão a trabalhar e que planeiam lançar no futuro.

Implementação

O procedimento de implementação e teste do Pub/Sub foi concebido para minimizar o potencial impacto. Vejamos os passos típicos para a implementação de uma nova versão do Pub/Sub:

  1. Certifique-se de que todos os testes de unidades e testes de integração são aprovados.

  2. Crie uma nova versão de todos os servidores.

  3. Implemente os novos servidores nos ambientes de teste e preparação.

  4. Execute os servidores no ambiente de teste e preparação durante vários dias.

  5. Se não existirem problemas conhecidos, lance os servidores para o teste canário, um subconjunto do ambiente de produção que tem uma pequena quantidade de tráfego de clientes.

  6. Se não forem detetados problemas no teste canary, implemente progressivamente os servidores em mais produção ao longo de vários dias até serem lançados em todo o lado.

Uma vez que o Pub/Sub foi concebido para ser resiliente a falhas, por exemplo, através da separação do plano de controlo e do plano de dados, as implementações de novas versões de servidores são totalmente integradas para os clientes e não devem ter impacto no desempenho que observam.

Monitorização

A chave para manter o Pub/Sub em funcionamento é detetar e mitigar automaticamente os problemas antes de ficarem visíveis para os utilizadores finais. Para o conseguir, é necessária uma monitorização extensiva do sistema. A equipa de engenharia de fiabilidade de sites (EFS) mantém um conjunto de indicadores do nível de serviço (INSs), métricas bem definidas que descrevem o comportamento do sistema. As métricas podem incluir "a quantidade de tempo que um pedido CreateSubscription demora a ser concluído" ou "a taxa de erros gerados por pedidos de publicação". Estas métricas são medidas de várias formas. Alguns deles são estritamente internos aos nossos encaminhadores e routers. Por exemplo, medem o tempo necessário para escrever mensagens no disco.

Todas estas medidas ajudam a definir objetivos ao nível do serviço (SLOs) internos, alvos específicos para os INSs. Por exemplo, "um pedido CreateSubscription não deve demorar mais de cinco segundos a ser concluído". Os ERSs recebem alertas de violações de SLOs e têm de responder aos alertas no prazo de cinco minutos.

Um contrato de nível de serviço (SLA) indica os SLOs que definem as nossas garantias de desempenho para os utilizadores finais e as consequências se não os cumprirmos. Pode ler o ANS do Pub/Sub.

Mantemos um conjunto de clientes que publicam e subscrevem de forma previsível. Estes são chamados sondadores. Existem sondas para o plano de dados e o plano de controlo. Cada um dos nossos testadores realiza ações específicas tal como um cliente e mede o tempo que as operações demoram. Por exemplo, temos uma sonda que cria uma nova subscrição, publica uma mensagem e vê quanto tempo demorou a criar a subscrição e a receber a mensagem. Se as sondas determinarem que alguma das métricas medidas não é o esperado, os engenheiros de fiabilidade do site são alertados.

As métricas dos nossos servidores e sondas são resumidas em vários painéis de controlo internos, o primeiro local que os SREs consultam sempre que diagnosticam potenciais problemas. Estas páginas oferecem acesso rápido a estatísticas e gráficos de todo o serviço. Também podem ser discriminadas por tópico, centro de dados ou tarefa individual.

As métricas mais interessantes para os utilizadores do serviço são expostas através do Google Cloud Monitoring.

Controlos

Temos à nossa disposição vários controlos para ajudar a otimizar o desempenho do Pub/Sub. Alguns destes controlos foram concebidos para ajudar com interrupções de máquinas ou centros de dados. Podemos colocar restrições de encaminhamento em alguns ou todos os tópicos, que são regras que especificam conjuntos de clientes que podem e/ou não podem estabelecer ligação a conjuntos de encaminhadores. Usamos restrições de encaminhamento para desviar o tráfego de tarefas de encaminhamento individuais ou de centros de dados completos que não estejam a funcionar como esperado.

Outra funcionalidade ajustável que temos é o controlo de fluxo. Esta funcionalidade permite-nos maximizar o débito e, ao mesmo tempo, evitar a sobrecarga no serviço. O controlo de fluxo é uma forma de modelação do tráfego em que os picos inesperados e súbitos na carga podem ser suavizados ao longo do tempo para uma maior estabilidade do serviço. O controlo de fluxo funciona ao nível do sistema ou por tópico ou subscritor para limitar o número de mensagens ou o número de bytes que são transferidos ou pendentes. Neste caso, "pendente" significa entregue ao cliente, mas ainda não confirmado. O controlo de fluxo e as restrições de encaminhamento permitem-nos otimizar o desempenho do Pub/Sub sem que os clientes tenham de se preocupar com estes detalhes de baixo nível.

Resumo

As vantagens em termos de escalabilidade, disponibilidade e latência de um serviço como o Pub/Sub definem a proposta de valor para os clientes que estão a considerar mudar para serviços de nuvem geridos. Qualquer serviço de mensagens assíncronas tem de ser criado de raiz tendo em conta estas funcionalidades. Com mais de uma década de experiência na entrega fiável de muitas mensagens rapidamente, a equipa do Pub/Sub criou e mantém um serviço que consegue acompanhar as exigências dos produtos mais fundamentais da Google. Agora, esse mesmo serviço está disponível para todos os clientes externos que queiram enviar as suas mensagens em todo o mundo sem se preocuparem se o respetivo sistema de mensagens consegue processar 2, 10 ou 100 vezes a carga atual.

Glossário

Vigência Descrição
cluster Um agrupamento lógico de máquinas que geralmente partilham o mesmo domínio de falha (por exemplo, rede local partilhada e energia partilhada).
plano de controlo A camada do Pub/Sub que processa a atribuição de publicadores e subscritores a servidores no plano de dados.
plano de dados A camada do Pub/Sub que processa a movimentação de mensagens entre publicadores e subscritores.
transitário Um servidor no plano de dados.
acesso global aos dados Os clientes publicadores e subscritores do Pub/Sub não têm conhecimento da localização dos dados. Todo o encaminhamento e armazenamento é feito pelo próprio serviço, de acordo com a política de restrição de localização.
escalável horizontalmente A capacidade de um serviço processar mais carga de forma integrada, aumentando o número de instâncias de componentes do serviço.
mensagem Os dados que se movem através do Pub/Sub.
distância da rede Uma medida da latência na ligação entre dois pontos.
prober Uma tarefa que atua como cliente e executa previsivelmente uma ou mais ações nos servidores do Pub/Sub.
origem da mensagem de publicação Um conjunto de mensagens recebidas e armazenadas por um encaminhador de publicação e o conjunto de IDs de mensagens reconhecidas por todas as subscrições anexadas.
Serviço de publicação/subscrição (Pub/Sub) Um serviço de mensagens em que os remetentes de mensagens estão separados dos destinatários de mensagens
editora Um cliente do Pub/Sub que cria mensagens e as envia (publica) num tópico especificado.
router Um servidor no plano de controlo.
restrições de planeamento de trajetos Uma lista de regras que indicam que encaminhadores devem ou não ser enviados pelos routers aos clientes como possíveis pontos finais para estabelecer ligação.
contrato de nível de serviço (SLA) Uma lista de SLOs que definem as garantias de desempenho de um sistema para os clientes e descrevem as consequências se não forem cumpridas.
indicador do nível de serviço (INS) Uma métrica bem definida que descreve o comportamento do sistema.
objetivo ao nível do serviço (SLO) Um objetivo específico para um indicador do nível de serviço.
subscritor Um cliente do Pub/Sub que recebe mensagens numa subscrição especificada.
subscrição Uma entidade com nome que representa um interesse em receber todas as mensagens sobre um tópico específico.
garantia de ponto de sincronização A hora em que uma subscrição é criada, em que todas as mensagens publicadas subsequentes são entregues aos subscritores.
tópico Uma entidade nomeada que representa um feed de mensagens.