Pub/Sub: introdução à confiabilidade

Este guia oferece uma visão geral dos recursos de confiabilidade do Pub/Sub. Os tópicos abordados neste documento incluem:

  • Por que usar o Pub/Sub?
  • Failover
  • Ajustar publishers
  • Ajustar os inscritos
  • Como usar o snapshot e a busca para implantações seguras

Por que usar o Pub/Sub?

Como um paradigma de mensagens, o publish/subscribe foi projetado para separar os produtores de mensagens dos consumidores delas. Em vez de enviar solicitações diretas aos consumidores com os dados, os produtores os publicam em um serviço do Pub/Sub, como o Pub/Sub. O serviço entrega essas mensagens de forma assíncrona aos consumidores interessados que se inscreveram.

O resultado é que o serviço absorve todas as complexidades de encontrar consumidores interessados nos dados. O serviço também gerencia a taxa em que os consumidores recebem os dados com base na capacidade deles. A separação permite que os produtores de dados gravem mensagens em grande escala com baixa latência, independentemente do comportamento dos consumidores.

O Pub/Sub oferece entrega de mensagens altamente confiável e escalonável. Embora o serviço processe grande parte disso automaticamente, você tem controle sobre diferentes aspectos dos editores e assinantes que podem afetar a disponibilidade e o desempenho. O restante deste guia apresenta alguns detalhes sobre esses aspectos.

Failover

O Pub/Sub é um serviço global: os tópicos e as assinaturas não são inerentemente vinculados a regiões específicas, e as mensagens fluem dentro do serviço do Pub/Sub entre regiões quando necessário. Ao usar o endpoint global, pubsub.googleapis.com, os editores e assinantes se conectam à região mais próxima da rede em que o Pub/Sub é executado. Ao usar os endpoints de localização, como us-central1-pubsub.googleapis.com, os editores e assinantes se conectam ao Pub/Sub na região especificada. Ao executar editores ou assinantes fora do Google Cloud, é melhor usar endpoints de localização para garantir que as mensagens fluam entre as regiões esperadas de forma consistente. O restante desta seção explica como criar tópicos e assinaturas. Além disso, também é discutida a forma de posicionar editores e assinantes para oferecer suporte a diferentes tipos de failover e redundância de dados.

Semântica de failover padrão

Considere um caso em que há um único tópico e uma assinatura. Os editores estão localizados em regiões dos Estados Unidos e da Austrália, e os assinantes estão localizados nas regiões do Google Cloud na Europa e na Austrália. No caso em que todos os assinantes têm capacidade suficiente para receber mensagens, o fluxo de mensagens é parecido com este:

Figura 1. Todos os assinantes têm capacidade suficiente para receber mensagens.
Figura 1. Todos os assinantes têm capacidade suficiente para receber mensagens.

Os Ps representam os editores, e os Ss representam os assinantes. O hexágono azul representa o serviço do Pub/Sub. Os cilindros representam os locais em que as mensagens são armazenadas. Elas são sempre armazenadas em várias zonas na região em que são publicadas. O Pub/Sub prefere enviar mensagens na mesma região em que foram publicadas quando os assinantes estão disponíveis. Caso contrário, as mensagens são enviadas para a região mais próxima da rede com assinantes que têm capacidade. Portanto, como mostrado na imagem anterior, as mensagens publicadas nos Estados Unidos são entregues aos assinantes na Europa, e as mensagens publicadas na Austrália ficam na Austrália.

As seções a seguir discutem o que acontece em diferentes cenários de falha.

Assinantes na Europa não estão disponíveis

Suponha que os assinantes na Europa foram desativados ou falharam com frequência e não conseguiram manter uma conexão com o Pub/Sub. Se isso acontecer, o serviço vai começar a enviar mensagens aos assinantes na Austrália:

Figura 2. Os assinantes na Europa não estão disponíveis.
Figura 2. Assinantes na Europa não estão disponíveis.

Os assinantes na Europa e na Austrália não estão disponíveis

Se todos os assinantes estiverem indisponíveis, o Pub/Sub armazenará as mensagens até a duração de retenção de mensagens configurada.

Figura 3. Assinantes na Europa e na Austrália não estão disponíveis.
Figura 3. Assinantes na Europa e na Austrália não estão disponíveis.

Quando os assinantes se reconectam, as mensagens são entregues, a menos que a interrupção dure mais do que a duração de retenção de mensagens configurada. Por padrão, a retenção de mensagens de assinatura é definida como 7 dias. Também é possível configurar a retenção de mensagens em um tópico por até 31 dias. Não escolha uma duração de retenção de mensagem menor que a interrupção máxima que você espera ou está disposto a tolerar.

O Pub/Sub não está disponível na Europa

Embora seja raro, você também pode lidar com casos em que o Pub/Sub não está disponível. A indisponibilidade do Pub/Sub se manifesta como períodos prolongados de erros inesperados em solicitações de publicação ou assinatura ou a incapacidade de entregar mensagens publicadas aos assinantes. Por exemplo, se o Pub/Sub estiver inativo na região da Europa, o cenário será semelhante ao que acontece quando os assinantes estão inativos:

Figura 4. O Pub/Sub não está disponível na Europa.
Figura 4. O Pub/Sub não está disponível na Europa.

Nesse caso, os assinantes na Europa não falham em outra região, mesmo que usem o endpoint global. O Pub/Sub não falha automaticamente. Imagine que os assinantes estão causando um problema inesperado no Pub/Sub que resulta em indisponibilidade. Esse problema é tratado como uma falha grave. No entanto, o escopo do impacto da falha pode ser contido na região em que os assinantes se conectaram. Se o serviço permitisse a falha em outra região, os assinantes também poderiam causar indisponibilidade, resultando em uma falha em cascata em todo o serviço.

Os editores na Austrália estão indisponíveis

Se os editores de uma região ficarem indisponíveis, as mensagens que já foram publicadas ainda serão entregues aos assinantes mais próximos:

Figura 5. Os editores na Austrália não estão disponíveis.
Figura 5. Os editores na Austrália não estão disponíveis.

Eventualmente, todas as mensagens são consumidas e confirmadas pelos assinantes. Ao enviar mensagens, o Pub/Sub tenta minimizar a distância da rede. Portanto, os assinantes na região da Austrália podem parar de receber mensagens se os assinantes na Europa tiverem capacidade suficiente para processar todas as mensagens publicadas nos Estados Unidos.

O Pub/Sub não está disponível nos Estados Unidos

O Pub/Sub grava mensagens de forma síncrona em várias zonas dentro de uma região. Portanto, uma interrupção por zona não é suficiente para impedir o envio de mensagens. A região inteira precisa estar indisponível. Se o Cloud Pub/Sub ficar indisponível em uma região em que os editores estão enviando mensagens, as mensagens nessa região podem não ser entregues até que o serviço seja totalmente restaurado:

Figura 6. O Pub/Sub não está disponível nos Estados Unidos
Figura 6. O Pub/Sub não está disponível nos Estados Unidos.

A mensagem ainda é entregue (supondo que o período de retenção da mensagem não tenha passado), atrasada pela duração da interrupção. Assim como os assinantes, os editores nos Estados Unidos também não fazem failover para outra região quando o serviço falha. Esse comportamento ajuda a evitar a probabilidade de falhas em cascata em várias regiões devido a um editor ou assinante com falha.

Isolamento

A semântica de failover padrão detalhada afeta o isolamento de dados e como a indisponibilidade de editores, assinantes ou o próprio Pub/Sub pode afetar o fluxo de mensagens. Seu caso de uso pode exigir diferentes níveis de isolamento. Por exemplo, você pode exigir a entrega de todas as mensagens dentro da região.

Se você não quiser isolamento, a semântica de failover padrão detalhada será suficiente. Você precisa criar um tópico, uma assinatura e colocar editores e assinantes em todas as regiões selecionadas. Se os assinantes ficarem indisponíveis ou o Pub/Sub estiver inativo na região a que eles se conectam, o envio vai falhar para assinantes em outra região.

Para o isolamento regional, em que os dados não podem sair de uma região, crie um tópico e uma assinatura para processar mensagens em cada região. Localize editores e assinantes em cada uma dessas regiões e peça que eles publiquem e se inscrevam no tópico e na assinatura regionais correspondentes, respectivamente. Você também precisa usar endpoints regionais para garantir que os dados sejam movidos apenas dentro da região. Em caso de falhas do editor, do assinante ou do Pub/Sub em uma única região, a entrega de mensagens é interrompida nessa região. A entrega de mensagens em tópicos e assinaturas para outras regiões não é afetada.

Por fim, o isolamento por zona, em que os dados permanecem em uma única zona, não é possível no Pub/Sub. Se você precisar que as zonas individuais sejam independentes, use o Pub/Sub Lite.

Failover e redundância controlados pelo cliente

A semântica de failover padrão do Pub/Sub pode não garantir totalmente que as mensagens sempre fluam dos editores para os assinantes se houver uma interrupção no meio. As interrupções podem ocorrer em vários lugares, incluindo nos seus clientes, no serviço em que seus editores ou assinantes são executados, na rede ou até mesmo no próprio Pub/Sub. Se você precisar que seus serviços sejam resilientes a essas interrupções, implemente suas próprias redundâncias. Normalmente, essas redundâncias incluem o uso de várias instâncias de clientes de editores e assinantes, em que cada um usa um endpoint de localização diferente.

Talvez você queira ter resiliência para dois escopos de impacto diferentes: zonal ou regional. Confira as opções de configuração de cada uma delas.

Resiliência zonal

O Pub/Sub tem replicação entre zonas integrada. Não é necessário tomar medidas especiais para lidar com interrupções de zona única que afetam o serviço. No entanto, para ter resiliência a interrupções de clientes ou da rede, é melhor executar editores e assinantes com capacidade suficiente em várias zonas da região. Se uma única zona estiver inativa, os clientes na outra zona poderão receber o tráfego e processar as mensagens. É uma prática recomendada não publicar mudanças nesses clientes simultaneamente para que, se um bug for introduzido, as outras zonas não afetadas continuem processando mensagens.

Resiliência regional

Para ser resistente a falhas regionais, configure redundâncias adicionais nos editores e assinantes. É possível executar editores e assinantes em várias regiões para lidar com a possibilidade de interrupções nesses clientes ou na rede.

Se você quiser ser resiliente a possíveis falhas do Pub/Sub em uma região, é necessário ter um mecanismo de failover pronto para lidar com essa falha. As abordagens possíveis são uma compensação entre a latência de entrega de mensagens de ponta a ponta e o custo.

Para minimizar a latência no caso de o custo não ser um problema, a melhor estratégia é sempre publicar e assinar simultaneamente em diferentes regiões. Primeiro, escolha o número de regiões em que você quer redundância. Em seguida, embora não seja estritamente necessário, você pode configurar um tópico e uma assinatura para cada uma dessas regiões.

Cada editor cria tantos clientes de editor quantos regiões (um para cada região) e usa um endpoint de localização diferente para garantir que as mensagens sejam direcionadas a regiões distintas. Se você usar tópicos separados, cada cliente do editor precisa publicar no tópico correspondente de cada região. Para cada mensagem, o editor chama o método publish em cada cliente. Com as publicações redundantes, não é preciso tentar novamente se uma delas falhar.

Da mesma forma, cada assinante cria vários clientes de assinante, um para cada região, e usa um endpoint de localização para se conectar a uma região diferente. Se você usar assinaturas diferentes para cada região, cada cliente assinante precisará usar a assinatura correspondente. As regiões usadas para editores e assinantes não precisam ser necessariamente as mesmas. Os assinantes recebem mensagens nas três assinaturas e as processam.

Essa configuração tem vários recursos e requisitos importantes:

  1. Qualquer falha temporária em uma única região não afeta o processamento de mensagens já publicadas nem as publicadas durante a falha. Como as mensagens foram publicadas em várias regiões, elas ainda estão disponíveis em outras regiões no evento em que uma estava inativa. Durante a interrupção, as chamadas de publicação falham na região afetada, mas são bem-sucedidas nas outras.
  2. A latência de processamento de mensagens não é afetada, desde que qualquer uma das regiões por onde as mensagens estão fluindo esteja disponível.
  3. O processamento de mensagens precisa ser idempotente. Como cada mensagem será enviada várias vezes, o processamento de mensagens precisa ser resistente a duplicatas. No caso de uma interrupção regional, algumas dessas duplicações podem ser enviadas muito depois da primeira vez que a mensagem foi entregue. Essas duplicações provavelmente vieram de uma região diferente que não estava com uma falha temporária.

A execução com esse tipo de redundância oferece a maior resiliência a qualquer tipo de interrupção. Para serviços internos do Google que dependem do Pub/Sub e exigem a maior disponibilidade, essa configuração é a preferida. No entanto, essa configuração tem a desvantagem de multiplicar o custo da entrega de mensagens pelo número de regiões usadas. Há também o custo adicional do uso de rede inter-regional para mensagens que precisam ser transferidas entre regiões.

Outra abordagem para a redundância é falhar apenas quando as solicitações falharem ou as mensagens não forem enviadas dos editores aos assinantes conforme o esperado. Nesse cenário, você tem uma região principal para direcionar editores e assinantes por meio de endpoints de localização. Como antes, elas não precisam estar na mesma região. Você também terá uma região substituta para editores e assinantes que será usada quando a região principal estiver indisponível.

Os editores publicam apenas na região principal (pelo endpoint de local) quando as solicitações são enviadas. Sempre que a região estiver inativa, os editores vão começar a publicar na região de substituição. É possível determinar que a região está inativa e que a falha pode ser feita de duas maneiras. Isso pode ser feito por um processo manual, e a configuração é atualizada dinamicamente nos editores. Os editores também podem atualizar a configuração por conta própria se a taxa de erros nas solicitações de publicação for suficientemente alta.

Os assinantes precisam se conectar à região principal pelo endpoint de localização. Você pode decidir se o assinante pode usar a região de substituição com um ou mais dos seguintes gatilhos:

  1. Sempre se inscreva na região de substituição. Nesse caso, o assinante mantém uma conexão com a região principal e a de fallback o tempo todo. As mesmas regiões podem ser usadas para o principal e o substituto para editores e assinantes. Nesse caso, o assinante só vai receber mensagens pela região de backup se o editor falhar.
  2. Detecte e mude manualmente os assinantes para a região de substituição usando uma configuração. Se você detectar uma interrupção, poderá fazer o failover para a região de fallback e voltar para a região principal quando a interrupção for resolvida.
  3. Falha em caso de erros do assinante. Se as solicitações do assinante retornarem erros, use isso como uma indicação de que você precisa fazer o failover para a região de fallback. As bibliotecas de cliente do Pub/Sub tentam novamente as solicitações de pull de streaming internamente em erros temporários. Portanto, talvez não seja possível detectar que há longos períodos de erros inesperados. Além disso, a taxa de erro de pull de streaming é esperada em 100%, mesmo durante a operação normal.
  4. Falha se o assinante passar por um tempo inesperadamente longo sem receber mensagens. Supondo que haja uma publicação consistente de mensagens, os assinantes sempre poderão receber mensagens. Se eles passarem por um longo período sem receber mensagens, talvez haja um problema de assinatura no Pub/Sub na região principal. Isso é corrigido com a falha na região de fallback.

Das quatro opções, a primeira é a ideal. Uma conexão de assinante não custa dinheiro se não houver mensagens fluindo por ela. O único custo é o da instância adicional da biblioteca de cliente do assinante, que pode ser insignificante. Também é preciso considerar o número de conexões de pull de streaming abertas por cota de região.

A vantagem desse segundo modelo é que não há um multiplicador no custo do Pub/Sub, já que as mensagens são publicadas apenas uma vez. No entanto, a desvantagem é que, para determinados tipos de interrupções, as mensagens publicadas antes do início da interrupção podem não ficar disponíveis até que ela seja resolvida. As mensagens armazenadas na região indisponível podem não ser entregues aos assinantes, independentemente de onde eles estejam conectados. As mensagens publicadas durante a interrupção na região de fallback podem estar disponíveis. Além disso, pode haver um período de indisponibilidade com taxas de erro maiores para os editores ou assinantes. Isso depende do método usado para detectar uma interrupção e do tempo para falhar na região de fallback.

Independentemente da opção escolhida, saiba como ela pode interagir com os recursos do Pub/Sub. Tanto a entrega ordenada quanto a entrega exatamente uma vez oferecem garantias em uma região. Por exemplo, se você usar a técnica de redundância de failover, a entrega de mensagens só será garantida para mensagens publicadas na mesma região. O assinante pode receber mensagens publicadas na região de fallback antes das mensagens publicadas na região principal, mesmo que as mensagens tenham sido publicadas na região principal primeiro.

Ajustar publishers

Não importa qual das opções de failover você escolher, há algumas etapas de ajuste adicionais que você precisa realizar nos editores. O ajuste do comportamento do editor garante um desempenho ideal sob carga alta. Mensagens em lote é uma maneira de trocar a latência por um custo reduzido, mas não é uma preocupação com a confiabilidade e, portanto, não é abordada aqui. Em vez disso, concentre-se em alguns dos outros parâmetros que são úteis para ajustar a confiabilidade, incluindo configurações de nova tentativa e de controle de fluxo.

As publicações podem falhar por vários motivos, incluindo temporários, como a falta de rede ou que exigem intervenção do usuário, como mudanças de permissão. A biblioteca de cliente do Pub/Sub tenta novamente erros temporários usando os parâmetros especificados nas configurações de repetição. Essas configurações controlam o comportamento da espera exponencial em novas tentativas de RPCs de publicação que falham por motivos temporários. Embora as configurações padrão geralmente funcionem bem na maioria dos cenários, há situações em que é necessário ajustar esses valores.

As duas propriedades que você provavelmente vai querer ajustar são o tempo limite inicial do RPC e o tempo limite total. O tempo limite inicial da RPC é o tempo que a primeira RPC de publicação tem para ser concluída. Se algum RPC falhar ou expirar, outro será tentado com um tempo limite mais longo até que o número total de solicitações ou o tempo limite total seja excedido.

O tempo limite inicial pode ser ajustado se o editor estiver limitado pela rede ou longe do data center do Google Cloud mais próximo que executa o Pub/Sub. As restrições de rede podem ser limitações na taxa de transferência da máquina em que o editor está sendo executado ou podem ser o resultado de outros serviços executados na mesma máquina que exigem muita rede. Com o tempo limite definido muito curto, os RPCs iniciais podem falhar repetidamente, resultando em mais tentativas (com tempos limite mais longos) necessárias para publicar. A necessidade repetida de novas tentativas aumenta a latência de publicação. Nessa situação, aumentar o tempo limite inicial pode resultar em publicações mais rápidas.

Se a conexão de rede não for confiável, aumentar o tempo limite total e o tempo limite inicial pode ajudar. Um aumento no tempo limite total dá ao RPC de publicação mais tempo para ser concluído. Quando as RPCs de publicação falharem constantemente com erros de prazo excedido, ajuste esses valores.

Erros contínuos de prazo excedido na publicação também podem indicar a necessidade de ajustar o controle de fluxo do editor. Essas configurações permitem que você garanta que seus editores sejam resilientes a picos de tráfego de entrada que geram mais mensagens a serem enviadas ao Pub/Sub. Um grande aumento nas solicitações enviadas pode sobrecarregar a CPU, a memória ou a capacidade de rede do editor. Quando a publicação está sobrecarregada, ela não consegue processar solicitações ou respostas de publicação antes dos tempos limite. Isso resulta em ainda mais solicitações de publicação e, por fim, atinge o tempo limite total. O controle de fluxo do editor limita o número de mensagens ou bytes que podem estar pendentes sem uma resposta da solicitação de publicação. Limitar o número de solicitações dessa forma mantém a utilização de recursos em um nível gerenciável, mesmo durante picos. Dependendo de como o editor funciona, você pode permitir que as RPCs de publicação posteriores aguardem a capacidade, permitindo que a publicação bloqueie outras solicitações. Como alternativa, é possível retornar aos autores de chamada do serviço fazendo com que o controle de fluxo retorne um erro quando a capacidade for alcançada. Você configura como a biblioteca de cliente do editor responde com o comportamento de limite excedido.

Ajustar os inscritos

A sintonia do assinante também pode ser necessária para garantir a confiabilidade do funcionamento. Assim como os editores, você pode ajustar as configurações de controle de fluxo dos assinantes para garantir que eles não fiquem sobrecarregados. A biblioteca de cliente do assinante usa o pull de streaming, em que o cliente abre um stream persistente para o servidor, e o servidor envia mensagens conforme elas ficam disponíveis. Em caso de um grande aumento nas mensagens publicadas, o assinante pode receber mais mensagens do que pode processar. Com o controle de fluxo em vigor, o número de mensagens pendentes não confirmadas para o cliente em um momento é limitado. Isso reduz o número de mensagens processadas simultaneamente e distribui o processamento delas por um período mais longo. A distribuição da carga permite que os assinantes permaneçam abaixo de qualquer limitação de recurso que afete o processamento de mensagens, o que pode resultar em um efeito cascata que se desenvolve na incapacidade de processar qualquer mensagem.

O controle de fluxo por si só é suficiente se você espera que os picos na quantidade de dados a serem processados diminuam. Se o tráfego aumentar com o tempo devido ao aumento do uso, o controle de fluxo vai proteger os assinantes. No entanto, isso pode resultar em um backlog que continua aumentando e faz com que as mensagens não sejam entregues antes que a duração da retenção de mensagens termine. Nesses casos, você também pode configurar o escalonamento automático para aumentar o número de assinantes em resposta a um número crescente de mensagens não reconhecidas. A configuração depende da plataforma de computação que você está usando para os assinantes. Por exemplo, o escalonador do Compute Engine permite escalonar com base em métricas como o número de mensagens não entregues. Usar o dimensionamento automático e o controle de fluxo permite garantir que seus assinantes sejam resilientes a outros picos de curto prazo na taxa de mensagens e crescimento de longo prazo que exigem mais capacidade de computação.

Use o snapshot e procure implantações seguras

A perda de mensagens geralmente é um evento catastrófico. O Pub/Sub oferece entrega pelo menos uma vez para todas as mensagens publicadas. No entanto, o processamento correto dessas mensagens depende do comportamento do assinante. Se as mensagens forem confirmadas, o Pub/Sub não as reenviará. Portanto, um bug introduzido no novo código de assinante implantado que confirma mensagens sem processá-las corretamente pode resultar na perda de mensagens induzidas pelo assinante. O Pub/Sub oferece o recurso de snapshot e busca, que pode ajudar a garantir que todas as mensagens sejam processadas corretamente, mesmo em caso de bugs do assinante.

O padrão para cada implantação de assinante precisa ser o seguinte:

Figura 7. Padrão para implantação de assinantes.
Figura 7. Padrão de implantação de assinantes.

O tempo de espera para determinar se o novo assinante está funcionando pode variar de acordo com seu caso de uso. A única maneira de sair do fluxo de etapas é quando um assinante é considerado ativo, momento em que o snapshot pode ser excluído.

O uso de snapshots e buscas não substitui as práticas recomendadas para executar o software primeiro em um ambiente que não seja de produção e implantar gradualmente na produção. Eles oferecem um nível extra de proteção para garantir o processamento confiável de dados. A desvantagem é que a busca do snapshot pode resultar em entrega duplicada de mensagens que o assinante processou. No entanto, como o Pub/Sub tem a semântica de entrega pelo menos uma vez por padrão, seus assinantes já são resilientes ao reenvio de mensagens.