Esta página explica como receber e acusar a receção de mensagens através da funcionalidade exatamente uma vez do Pub/Sub, que lhe permite acompanhar e impedir o processamento duplicado de mensagens. Quando a funcionalidade está ativada, o Pub/Sub oferece a seguinte semântica:
Os subscritores podem determinar se os reconhecimentos de mensagens foram bem-sucedidos.
Não ocorre uma nova entrega após a mensagem ser reconhecida com êxito.
Não ocorre reenvio enquanto houver uma mensagem pendente. Uma mensagem é considerada pendente até o prazo de confirmação expirar ou a mensagem ser confirmada.
No caso de várias entregas válidas, devido à expiração do prazo de confirmação ou à confirmação negativa iniciada pelo cliente, só é possível usar o ID de confirmação mais recente para confirmar a mensagem. Todas as solicitações com um ID de confirmação anterior falham.
Com a opção "Exatamente uma vez" ativada, os subscritores podem garantir que as mensagens são processadas uma vez seguindo estas diretrizes:
Confirmar a receção de mensagens dentro do prazo de confirmação.
Manter informações sobre o progresso do processamento de uma mensagem até que seja confirmada com êxito.
Use as informações sobre o progresso do processamento de uma mensagem para evitar trabalho duplicado quando uma confirmação falha.
Apenas o tipo de subscrição pull suporta a entrega exatamente uma vez, incluindo subscritores que usam a API StreamingPull. As subscrições de envio e exportação não suportam a entrega exatamente uma vez.
O Pub/Sub suporta a entrega exatamente uma vez, numa região da nuvem, com base num ID da mensagem exclusivo definido pelo Pub/Sub.
Versões da biblioteca cliente recomendadas
- Para um melhor desempenho, use a versão mais recente da biblioteca cliente, Python v2.13.6 ou superior, Java v1.139.0 ou superior, PHP v1.39.0 ou superior, C# v3.2.0 ou superior, C++ v2.1.0, Go v1.25.1 ou superior, Node v3.2.0 ou superior e Ruby v2.12.1 ou superior.
Reenvio versus duplicado
É importante compreender a diferença entre reenvios esperados e inesperados.
Uma nova entrega pode ocorrer devido a uma confirmação negativa iniciada pelo cliente de uma mensagem ou quando o cliente não prolonga o prazo de confirmação da mensagem antes de este expirar. As reentregas são consideradas válidas e o sistema está a funcionar conforme previsto.
Para resolver problemas de reenvios, consulte o artigo Lidar com duplicados.
Um duplicado ocorre quando uma mensagem é reenviada após uma confirmação bem-sucedida ou antes da expiração do prazo de confirmação.
Uma mensagem reenviada mantém o mesmo ID da mensagem entre as tentativas de reenvio.
As subscrições com a entrega exatamente uma vez ativada não recebem entregas duplicadas.
Suporte de entrega exatamente uma vez nas bibliotecas cliente
As bibliotecas cliente suportadas têm uma interface para confirmação com resposta (exemplo: Go). Pode usar esta interface para verificar se o pedido de confirmação foi bem-sucedido. Se o pedido de confirmação for bem-sucedido, é garantido que os clientes não recebem uma nova entrega. Se o pedido de confirmação falhar, os clientes podem esperar uma nova entrega.
Os clientes também podem usar as bibliotecas de cliente suportadas sem a interface de confirmação. No entanto, nestes casos, as falhas de confirmação podem levar a reenvios silenciosos de mensagens.
As bibliotecas cliente suportadas têm interfaces para definir o tempo mínimo de extensão do aluguer (exemplo: Go). Tem de definir o valor da extensão mínima de concessão para um número elevado para evitar expirações de confirmação relacionadas com a rede. O valor máximo é de 600 segundos.
Se estiver a usar a biblioteca de cliente Java e inicializar o subscritor com um canal gRPC personalizado através do método
setChannelProvider()
, é recomendável que também definamaxInboundMetadataSize
para, pelo menos, 1 MB quando criar oTransportChannelProvider
. Para esta configuração, pode usar o métodoInstantiatingGrpcChannelProvider.Builder.setMaxInboundMetadataSize()
ou o métodoManagedChannelBuilder.maxInboundMetadataSize()
.
Os valores predefinidos e o intervalo das variáveis relacionadas com a entrega exatamente uma vez e os nomes das variáveis podem diferir entre as bibliotecas de cliente. Por exemplo, na biblioteca cliente Java, as seguintes variáveis controlam o fornecimento exatamente uma vez.
Variável | Descrição | Valor |
---|---|---|
setEnableExactlyOnceDelivery |
Ativa ou desativa a entrega exatamente uma vez. | true or false Default=false |
minDurationPerAckExtension |
O tempo mínimo em segundos a usar para prolongar o prazo de confirmação de modificação. | Intervalo=0 a 600 Predefinição=nenhum |
maxDurationPerAckExtension |
O tempo máximo em segundos a usar para prolongar o prazo de confirmação da modificação. | Intervalo=0 a 600 Predefinição=nenhum |
No caso da entrega exatamente uma vez, o pedido modifyAckDeadline
ou acknowledgment
para o Pub/Sub falha quando o ID de confirmação já expirou. Nestes casos, o serviço considera o ID de confirmação expirado como inválido, uma vez que pode já estar em curso uma entrega mais recente. Isto é intencional para a entrega exatamente uma vez. Em seguida, vê que os pedidos acknowledgment
e ModifyAckDeadline
devolvem uma resposta INVALID_ARGUMENT
. Quando a entrega exatamente uma vez está desativada, estes pedidos devolvem OK
nos casos de IDs de confirmação expirados.
Para garantir que os pedidos acknowledgment
e ModifyAckDeadline
têm IDs de confirmação válidos, considere definir o valor de minDurationPerAckExtension
para um número elevado.
Considerações regionais
A garantia de entrega exatamente uma vez só se aplica quando os subscritores se ligam ao serviço na mesma região. Se a sua aplicação de subscrição estiver distribuída por várias regiões, pode levar à entrega de mensagens duplicadas, mesmo quando a entrega exatamente uma vez está ativada. Os publicadores podem enviar mensagens para qualquer região e a garantia de exatamente uma vez é mantida.
Quando executa a sua aplicação no Google Cloud, por predefinição, esta liga-se ao ponto final do Pub/Sub na mesma região. Por conseguinte, a execução da sua aplicação numa única região dentro do Google Cloud geralmente garante que está a interagir com uma única região.
Quando executa a sua aplicação subscritora fora de Google Cloud ou em várias regiões, pode garantir que está a estabelecer ligação a uma única região usando um ponto final de localização ao configurar o cliente do Pub/Sub. Todos os pontos finais de localização do Pub/Sub apontam para regiões únicas. Para saber mais acerca dos pontos finais de localização, consulte o artigo Pontos finais do Pub/Sub. Para ver uma lista de todos os pontos finais de localização do Pub/Sub, consulte a Lista de pontos finais de localização.
Crie subscrições com entrega exatamente uma vez
Pode criar uma subscrição com entrega exatamente uma vez através da Google Cloud consola, da Google Cloud CLI, da biblioteca cliente ou da API Pub/Sub.
Subscrição de obtenção
Consola
Para criar uma subscrição de obtenção com entrega exatamente uma vez, siga estes passos:
Na Google Cloud consola, aceda à página Subscrições.
Clique em Criar subscrição.
Introduza o ID da subscrição.
Escolha ou crie um tópico no menu pendente.
A subscrição recebe mensagens do tópico.
Na secção Fornecimento exatamente uma vez, selecione Ativar fornecimento exatamente uma vez.
Clique em Criar.
gcloud
Para criar uma subscrição de obtenção com entrega exatamente uma vez, use o comando
gcloud pubsub subscriptions create
com a flag --enable-exactly-once-delivery
:
gcloud pubsub subscriptions create SUBSCRIPTION_ID \ --topic=TOPIC_ID \ --enable-exactly-once-delivery
Substitua o seguinte:
- SUBSCRIPTION_ID: o ID da subscrição a criar
- TOPIC_ID: o ID do tópico a anexar à subscrição
REST
Para criar uma subscrição com entrega exatamente uma vez, use o método
projects.subscriptions.create
.
PUT https://pubsub.googleapis.com/v1/projects/PROJECT_ID/subscriptions/SUBSCRIPTION_ID Authorization: Bearer $(gcloud auth print-access-token)
Substitua o seguinte:
- PROJECT_ID: o ID do projeto no qual criar a subscrição
- SUBSCRIPTION_ID: o ID da subscrição a criar
Para criar uma subscrição de obtenção com entrega exatamente uma vez, especifique o seguinte no corpo do pedido:
{ "topic": "projects/PROJECT_ID/topics/TOPIC_ID", "enableExactlyOnceDelivery": true, }
Substitua o seguinte:
- PROJECT_ID: o ID do projeto com o tópico
- TOPIC_ID: o ID do tópico a anexar à subscrição
C++
Antes de experimentar este exemplo, siga as instruções de configuração do C++ no artigo Início rápido: usar bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API C++ do Pub/Sub.
C#
Antes de experimentar este exemplo, siga as instruções de configuração do C# em Início rápido: usar bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API C# do Pub/Sub.
Ir
O exemplo seguinte usa a versão principal da biblioteca de cliente Go Pub/Sub (v2). Se ainda estiver a usar a biblioteca v1, consulte o guia de migração para a v2. Para ver uma lista de exemplos de código da v1, consulte os exemplos de código descontinuados.
Antes de experimentar este exemplo, siga as instruções de configuração do Go em Início rápido: usar bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API Go do Pub/Sub.
Java
Antes de experimentar este exemplo, siga as instruções de configuração do Java no artigo Início rápido: usar bibliotecas cliente. Para mais informações, consulte a documentação de referência da API Java do Pub/Sub.
Python
Antes de experimentar este exemplo, siga as instruções de configuração do Python em Início rápido: usar bibliotecas cliente. Para mais informações, consulte a documentação de referência da API Python Pub/Sub.
Node.js
Antes de experimentar este exemplo, siga as instruções de configuração do Node.js em Início rápido: usar bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API Node.js do Pub/Sub.
Node.js
Antes de experimentar este exemplo, siga as instruções de configuração do Node.js em Início rápido: usar bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API Node.js do Pub/Sub.
Ruby
O exemplo seguinte usa a biblioteca cliente Ruby Pub/Sub v3. Se ainda estiver a usar a biblioteca v2, consulte o guia de migração para a v3. Para ver uma lista de exemplos de código do Ruby v2, consulte os exemplos de código descontinuados.
Antes de experimentar este exemplo, siga as instruções de configuração do Ruby em Início rápido: usar bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API Ruby Pub/Sub.
PHP
Antes de experimentar este exemplo, siga as instruções de configuração do PHP no artigo Início rápido: usar bibliotecas cliente. Para mais informações, consulte a documentação de referência da API PHP Pub/Sub.
Monitorize as subscrições de fornecimento exatamente uma vez
A métrica
subscription/exactly_once_warning_count
regista o número de eventos que
podem levar a possíveis reentregas (válidas ou duplicadas). Esta métrica contabiliza o número de vezes que o Pub/Sub não processa pedidos associados a IDs de confirmação (pedido ModifyAckDeadline
ou acknowledgment
). Os motivos
da falha podem ser baseados no servidor ou no cliente. Por exemplo, se a camada de persistência usada para manter as informações de entrega exatamente uma vez não estiver disponível, seria um evento baseado no servidor. Se o cliente tentar acusar a receção de uma mensagem com um ID de acusação de receção inválido, trata-se de um evento baseado no cliente.
Compreenda a métrica
subscription/exactly_once_warning_count
capta eventos que podem ou não
resultar em reenvios reais e podem ser ruidosos com base no comportamento do cliente. Por exemplo: os pedidos acknowledgment
ou ModifyAckDeadline
repetidos com IDs de confirmação inválidos incrementam a métrica repetidamente.
As seguintes métricas também são úteis para compreender o comportamento do cliente:
subscription/expired_ack_deadlines_count
A métrica mostra o número de expirações do ID de confirmação. O ID de confirmação expira e pode levar a falhas nos pedidosModifyAckDeadline
eacknowledgment
.service.serviceruntime.googleapis.com/api/request_count
A métrica pode ser usada para captar falhas de pedidosModifyAckDeadline
ouacknowledgment
nos casos em que os pedidos chegam ao Google Cloud , mas não chegam ao Pub/Sub. Existem falhas que esta métrica não captura, por exemplo, quando os clientes estão desligados do Google Cloud.
Na maioria dos casos de eventos de falha que podem ser repetidos, as bibliotecas de cliente suportadas repetem o pedido automaticamente.
Quotas
As subscrições de entrega única estão sujeitas a requisitos de quota adicionais. Estas quotas são aplicadas:
- Número de mensagens consumidas de subscrições com entrega exatamente uma vez ativada por região.
- Número de mensagens reconhecidas ou cujo prazo é prolongado quando usa subscrições com a entrega exatamente uma vez ativada por região.
Para mais informações acerca destas quotas, consulte a tabela no tópico Quotas.
Entrega exatamente uma vez e subscrições ordenadas
O Pub/Sub suporta a entrega exatamente uma vez com a entrega ordenada.
Quando usar a ordenação com a entrega exatamente uma vez, o Pub/Sub espera que as confirmações estejam em ordem. Se as confirmações estiverem desordenadas, o serviço falha os pedidos com erros temporários. Se o prazo de confirmação expirar antes de uma confirmação em ordem para a entrega, o cliente recebe uma nova entrega da mensagem. Devido a isto, quando usa a ordenação com o fornecimento exatamente uma vez, o débito do cliente é limitado a uma ordem de mil mensagens por segundo.
Subscrições push e entrega exatamente uma vez
O Pub/Sub suporta a entrega exatamente uma vez apenas com subscrições de obtenção.
Os clientes que consomem mensagens das subscrições push confirmam as mensagens respondendo aos pedidos push com uma resposta bem-sucedida. No entanto, os clientes não sabem se a subscrição do Pub/Sub recebeu a resposta e a processou. Isto é diferente das subscrições de obtenção, em que os pedidos de confirmação são iniciados pelos clientes e a subscrição do Pub/Sub responde se o pedido foi processado com êxito. Por este motivo, a semântica de entrega exatamente uma vez não se alinha bem com as subscrições push.
Factos importantes
Se o prazo de confirmação não for especificado no momento de criação da subscrição, as subscrições com entrega única têm um prazo de confirmação predefinido de 60 segundos.
Os prazos de confirmação predefinidos mais longos são benéficos para evitar o reenvio causado por eventos de rede. As bibliotecas cliente suportadas não usam o prazo de confirmação da subscrição predefinido.
As subscrições de entrega única têm uma latência de publicação para subscrição significativamente mais elevada em comparação com as subscrições normais.
Se precisar de um débito elevado, os seus clientes de entrega exatamente uma vez também têm de usar a obtenção de streaming.
Uma subscrição pode receber várias cópias da mesma mensagem devido a duplicados do lado da publicação, mesmo com a entrega exatamente uma vez ativada. Os duplicados do lado da publicação podem dever-se a várias novas tentativas de publicação únicas por parte do cliente de publicação ou do serviço Pub/Sub. Várias publicações únicas pelo cliente de publicação, em várias tentativas, resultam em reenvios com diferentes IDs de mensagens. As várias publicações únicas do serviço Pub/Sub, para responder a um pedido de publicação do cliente, resultam em reenvios com os mesmos IDs das mensagens.
Pode tentar novamente as falhas em
subscription/exactly_once_warning_count
, e as bibliotecas de cliente suportadas tentam novamente estas falhas automaticamente. No entanto, não é possível tentar novamente as falhas relacionadas com IDs de confirmação inválidos.