Pub/Sub: introdução à confiabilidade

Neste guia, você terá uma noção geral dos recursos de confiabilidade do Pub/Sub. Os tópicos abordados neste documento incluem o seguinte:

  • Por que usar o Pub/Sub?
  • Failover
  • Como ajustar os editores
  • Como ajustar os inscritos
  • Usar snapshots e buscar implantações seguras

Por que usar o Pub/Sub?

Como paradigma de mensagens, a publicação/assinatura foi projetada para separar os produtores das mensagens dos consumidores delas. Em vez de enviar solicitações diretas aos consumidores com os dados, os produtores publicam esses dados em um serviço do Pub/Sub, como o Pub/Sub. O serviço entrega essas mensagens de maneira 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. Isso permite que os produtores de dados escrevam mensagens em alta escala com baixa latência, independentemente do comportamento dos consumidores.

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

Failover

O Pub/Sub é um serviço global: tópicos e assinaturas não estão inerentemente vinculados a regiões específicas, e as mensagens fluem dentro do serviço do Pub/Sub entre as 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 locais para garantir que as mensagens fluam entre as regiões esperadas de maneira consistente. O restante desta seção explica como criar tópicos e assinaturas. Além disso, abordamos como 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 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 da Europa e da Austrália. Caso todos os assinantes tenham capacidade suficiente para receber mensagens, o fluxo delas ficará assim:

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

O P representa os editores, e o S representa os assinantes. O hexágono azul representa o serviço do Pub/Sub. Os cilindros representam os locais onde as mensagens são armazenadas (as mensagens são sempre mantidas em várias zonas na região em que são publicadas). O Pub/Sub prefere enviar mensagens dentro da mesma região em que foram publicadas quando os assinantes estão disponíveis. Caso contrário, ele envia as mensagens para a região mais próxima da rede com assinantes que tenham 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 permanecem na Austrália.

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

Os assinantes na Europa estão indisponíveis

Suponha que os assinantes na Europa tenham sido desativados ou falharem com frequência e não conseguirem manter uma conexão com o Pub/Sub. Se isso ocorresse, o serviço começaria a entregar mensagens para assinantes na Austrália:

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

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

Caso nenhum assinante esteja indisponível, o Pub/Sub armazena as mensagens até a duração da retenção de mensagens configurada.

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

Quando os assinantes se reconectarem, as mensagens serão entregues, a menos que a interrupção dure mais do que a duração da retenção de mensagens configurada. Por padrão, a retenção de mensagens de assinatura é definida como sete dias. Também é possível configurar a retenção de mensagens em um tema de até 31 dias. Não escolha uma duração de retenção de mensagem menor do que a interrupção máxima esperada ou que esteja disposta a tolerar.

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

Embora seja raro, você também pode querer lidar com casos em que o próprio Pub/Sub não esteja disponível. A indisponibilidade do Pub/Sub se manifesta como períodos extensos 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 não estivesse na região da Europa, o cenário seria muito parecido com o de quando os assinantes ficarem 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 fazem failover para outra região, mesmo se estiverem usando o endpoint global. O Pub/Sub não faz failover intencionalmente automaticamente. Imagine que os próprios assinantes estão causando um problema inesperado no Pub/Sub que resulta em indisponibilidade. Esse problema é tratado como uma grande falha temporária. No entanto, o escopo do impacto da interrupção pode estar contido na região a que os assinantes se conectaram. Se o serviço permitia fazer o failover para outra região, os assinantes também poderiam causar indisponibilidade lá, resultando em uma falha em cascata no serviço.

Editores na Austrália não estão disponíveis

Se os editores em uma região ficarem indisponíveis, as mensagens já 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 reconhecidas pelos assinantes. Ao enviar mensagens, o Pub/Sub tenta minimizar a distância da rede. Portanto, os assinantes na região da Austrália poderão parar de receber mensagens se na Europa tiverem capacidade suficiente para lidar com todas as mensagens publicadas nos Estados Unidos.

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

O Pub/Sub grava mensagens de maneira síncrona em várias zonas em uma região. Portanto, uma interrupção zonal não é suficiente para impedir a entrega de mensagens. A região inteira precisa estar indisponível. Se o Cloud Pub/Sub ficar indisponível em uma região onde os editores estão enviando mensagens, talvez as mensagens nessa região não sejam entregues até que o serviço esteja 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 será entregue (se o período de retenção de mensagens não tiver passado), atrasada pela duração da interrupção. Assim como os assinantes, os editores nos Estados Unidos também não realizam o failover para outra região quando o serviço falha. Esse comportamento ajuda a evitar a probabilidade de falhas em cascata entre as regiões devido a um editor ou assinante com falha.

Isolamento

A semântica padrão de failover 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 precisar de diferentes níveis de isolamento. Por exemplo, talvez você precise da entrega intrarregional de todas as mensagens.

Se você não quiser isolamento, a semântica de failover padrão detalhada será suficiente. É preciso criar um único tópico e uma única assinatura e colocar editores e assinantes em todas as regiões selecionadas. Se os assinantes ficarem indisponíveis ou o Pub/Sub ficar indisponível na região a que eles se conectam, a entrega falha para os assinantes de outra região.

Para isolamento regional, em que os dados têm a garantia de não 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 regional correspondente, respectivamente. Você também precisa usar endpoints regionais para garantir que os dados sejam movidos apenas dentro da região. No caso de falhas do editor, assinante ou 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 zonal, em que os dados têm a garantia de permanecer em uma única zona, não é possível no Pub/Sub. Se você precisar que 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 possam fluir dos editores para assinantes se houver uma interrupção temporária. As interrupções podem ocorrer em vários lugares, incluindo seus clientes, no serviço em que os editores ou assinantes são executados, na rede ou até raramente no próprio Pub/Sub. Se você precisar que seus serviços sejam resilientes a essas interrupções, precisará implementar suas próprias redundâncias. Normalmente, essas redundâncias incluem o uso de várias instâncias de editores e clientes assinantes, em que cada uma usa um endpoint de localização diferente.

Talvez você queira resiliência a dois escopos de impacto diferentes: zonal ou regional. Estas são as opções de configuração de cada um.

Resiliência zonal

O Pub/Sub tem replicação integrada entre zonas. Você não precisa tomar nenhuma medida especial para lidar com interrupções de zona única que afetam o serviço em si. No entanto, para ter resiliência a interrupções dos seus clientes ou da rede, é melhor executar editores e assinantes com capacidade suficiente em várias zonas dentro 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 alterações nesses clientes simultaneamente para que, se um bug ocorrer, as outras zonas intactas possam continuar a processar mensagens.

Resiliência regional

Para ser resiliente a falhas regionais, configure outras redundâncias nos seus 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.

Para 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 interrupção. As abordagens possíveis são uma troca entre a latência de entrega de mensagens completa e seu custo.

Para minimizar a latência caso o custo não seja 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 quantos clientes do editor houver regiões (um para cada região) e usa um endpoint de localização diferente para garantir que as mensagens sejam direcionadas para regiões distintas. Caso use tópicos separados, cada cliente editor precisa publicar no tópico por região correspondente. Para cada mensagem, o editor chama a publicação em cada cliente. Com as publicações redundantes, não é necessário repetir as publicações se uma única falhar.

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

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

  1. As falhas temporárias em uma única região não afetam o processamento das mensagens já publicadas nem das que foram publicadas durante a interrupção. Como as mensagens foram publicadas em várias regiões, elas ainda estarão disponíveis em outras regiões caso uma região esteja 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 do processamento de mensagens não é afetada quando uma das regiões pelas quais as mensagens fluem está disponível.
  3. O processamento de mensagens precisa ser idempotente. Como cada mensagem será entregue várias vezes, o processamento de mensagens precisa ser resiliente a cópias. No caso de uma falha temporária regional, algumas dessas cópias podem chegar muito depois da primeira entrega da mensagem. Essas duplicatas provavelmente vieram de uma região diferente que não estava passando por 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 é preferível. 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 extra do uso de rede inter-regional para mensagens que precisam ser movidas entre regiões.

Outra abordagem para a redundância é fazer o failover somente quando as solicitações falham ou as mensagens não estão fluindo de editores para assinantes como esperado. Nesse cenário, você tem uma região principal para onde direciona os editores e assinantes por meio de endpoints locais. Como antes, eles não precisam ser da mesma região. Você também terá uma região substituta para editores e assinantes que é usada quando a região principal está indisponível.

Os editores publicam apenas na região principal (por meio do endpoint local) quando as solicitações são enviadas com êxito. Sempre que a região estiver inativa, os editores começam a publicar na região substituta. Há duas maneiras de determinar se a região está inativa e fazer o failover. Isso pode ser feito por um processo manual e a configuração que é atualizada dinamicamente nos editores. Os editores também podem atualizar a configuração por conta própria se a taxa de erro nas solicitações de publicação for alta o suficiente.

Os assinantes precisam sempre se conectar à região principal por meio do endpoint local. Você pode decidir que o assinante pode usar a região substituta com um ou mais dos seguintes gatilhos:

  1. Sempre se inscreva na região substituta. Nesse caso, o assinante mantém uma conexão com a região principal e com a região substituta sempre. As mesmas regiões podem ser usadas para o banco de dados principal e o substituto para editores e assinantes. Se esse for o caso, o assinante só poderá receber mensagens pela região de backup se o editor tiver feito o failover.
  2. Detectar e alternar manualmente os assinantes para a região substituta por meio de uma configuração. Se detectar uma interrupção, faça o failover para a região substituta e volte à região principal quando a interrupção tiver diminuído.
  3. Fazer failover de erros de inscritos. Se as solicitações do assinante estiverem retornando erros, você pode usar isso como uma indicação de que precisa fazer o failover para a região de fallback. As bibliotecas de cliente do Pub/Sub repetem internamente as solicitações de envio de streaming em erros transitórios. Portanto, talvez você não consiga detectar que há longos períodos de erros inesperados. Além disso, a taxa de erro de pull de streaming deve ser de 100%, mesmo durante a operação normal.
  4. Faça o failover se o assinante passar muito tempo sem receber mensagens. Supondo que haja uma publicação consistente de mensagens, os assinantes podem sempre receber mensagens. Se eles passarem por um período prolongado sem receber mensagens, pode haver um problema de assinatura no Pub/Sub na região principal. Isso é corrigido com o failover para a região substituta.

Das quatro opções, a primeira é a ideal. Uma conexão de assinante não terá custos se não houver mensagens fluindo por ela. O único custo está no pegado da instância adicional da biblioteca de cliente do assinante, o que pode ser insignificante. Considere também o número de conexões de pull de streaming aberto 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 estar disponíveis até que ela seja resolvida. As mensagens armazenadas na região que está indisponível podem não ser capazes de ser entregues aos assinantes, independentemente de onde eles estejam conectados. As mensagens publicadas durante a interrupção na região substituta 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 de failover para a região de substituição.

Seja qual for a opção escolhida, esteja ciente de como isso pode interagir com os recursos do Pub/Sub. Tanto a entrega solicitada 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 substituta antes de serem publicadas na região principal, mesmo que elas tenham sido publicadas primeiro na região principal.

Como ajustar os editores

Seja qual for a opção de failover escolhida, há algumas etapas de ajuste extras que você quer realizar nos próprios editores. O ajuste do comportamento do editor garante a performance ideal sob carga alta. Agrupar mensagens em lote é uma maneira de negociar a latência com um custo reduzido, mas não é um problema de confiabilidade e, portanto, não é abordado aqui. Em vez disso, concentre-se em alguns dos outros parâmetros úteis para ajustar a confiabilidade, incluindo configurações de nova tentativa e de controle de fluxo.

As publicações podem falhar por diferentes motivos, incluindo aquelas temporárias, como indisponibilidade de rede, ou aquelas que exigem intervenção do usuário, como mudanças de permissão. A biblioteca de cliente do Pub/Sub repete erros temporários usando os parâmetros especificados nas configurações de nova tentativa. Essas configurações controlam o comportamento da espera exponencial em novas tentativas de publicação de RPCs que falham por motivos temporários. As configurações padrão geralmente funcionam bem na maioria dos cenários, mas há situações em que é recomendável ajustar esses valores.

As duas propriedades que você provavelmente vai ajustar são o tempo limite inicial da RPC e o tempo limite total. O tempo limite inicial da RPC é o tempo de conclusão da primeira RPC publicada. Se alguma RPC falhar ou expirar, outra será testada com um tempo limite maior 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 tiver uma rede restrita 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 capacidade da máquina em que o editor está sendo executado ou ser o resultado de outros serviços em execução na mesma máquina que fazem uso intensivo da rede. Com o tempo limite definido muito curto, as RPCs iniciais podem falhar várias vezes, resultando em mais tentativas (com tempos limite mais longos) necessárias para uma publicação bem-sucedida. 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 inicial pode ajudar. Um tempo limite total maior dá à RPC de publicação mais tempo para ser concluída. Quando as RPCs de publicação falham de forma consistente com erros de prazo excedido, considere ajustar esses valores.

Erros de prazo contínuo 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 de saída pode sobrecarregar a CPU, a memória ou a capacidade de rede do editor. Quando a publicação é sobrecarregada, ela não consegue processar as solicitações ou respostas de publicação antes dos tempos limite. Isso resulta em ainda mais solicitações de publicação e, por fim, o tempo limite total é atingido. 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 maneira mantém a utilização de recursos em um nível gerenciável, mesmo durante picos. Dependendo de como seu editor opera, é possível permitir que as RPCs de publicação subsequentes aguardem a capacidade, permitindo que a publicação bloqueie mais 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 atingida. Você configura como a biblioteca de cliente do editor responde com o comportamento de limite excedido.

Como ajustar os inscritos

O ajuste do assinante também pode ser necessário para garantir que operem de maneira confiável. Assim como acontece com os editores, é possível ajustar as configurações de controle de fluxo dos assinantes para que eles não sejam sobrecarregados. A biblioteca de cliente do assinante usa pull de streaming, em que o cliente abre um stream persistente para o servidor, que envia as mensagens à medida que elas se tornam disponíveis. No caso de um grande aumento nas mensagens publicadas, o assinante poderá receber mais mensagens do que consegue processar. Com o controle de fluxo, o número de mensagens não confirmadas pendentes para o cliente por vez é limitado. Isso reduz o número de mensagens processadas simultaneamente e propaga o processamento por um período mais longo. A propagação da carga permite que os assinantes permaneçam abaixo de todas as limitações de recursos que afetem o processamento de mensagens, o que pode resultar em um efeito cascata que se desenvolve para a incapacidade de processar mensagens.

O controle de fluxo por si só é suficiente se você espera apenas picos na quantidade de dados a serem processados que, por fim, recuam. Se o tráfego geralmente estiver aumentando ao longo do tempo devido ao aumento do uso, o controle de fluxo protegerá os assinantes. No entanto, isso pode resultar em um backlog que continua se acumulando e faz com que as mensagens não possam ser entregues antes que o período de retenção de mensagens passe. Nesses casos, também é possível definir o escalonamento automático para aumentar o número de assinantes em resposta a um número crescente de mensagens não confirmadas. A configuração desse recurso depende da plataforma de computação usada para seus assinantes. Por exemplo, o escalonador automático do Compute Engine permite fazer o escalonamento com base em métricas como o número de mensagens não entregues. Usar o escalonamento automático e o controle de fluxo permite que você garanta que seus assinantes sejam resilientes a outros picos de curto prazo na capacidade de processamento de mensagens e crescimento em longo prazo, que exigem mais poder de computação.

Usar snapshot e buscar 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 com êxito, o Pub/Sub não as entrega novamente. Portanto, um bug introduzido no novo código de assinante implantado que reconhece mensagens sem tê-las processadas corretamente pode resultar na perda de mensagens induzida pelo assinante. O Pub/Sub oferece o recurso de snapshot e busca, que pode ajudar você a garantir que todas as mensagens sejam processadas corretamente, mesmo diante de bugs do assinante.

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

Figura 7. Padrão para implantação do assinante.
Figura 7. Padrão para implantação do assinante.

O tempo de espera antes de 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 trabalhando. Nesse momento, o snapshot pode ser excluído.

O uso de snapshot e busca não substitui as práticas recomendadas sobre a primeira execução do software em um ambiente que não seja de produção e a implantação gradual na produção. Eles fornecem um nível adicional de proteção para garantir o processamento confiável dos dados. A desvantagem é que a busca por um snapshot pode resultar na entrega duplicada de mensagens processadas pelo assinante. No entanto, como o Pub/Sub tem semântica de entrega pelo menos uma vez por padrão, seus assinantes já são resilientes ao reenvio de mensagens.