Ordenar mensagens

A ordenação de mensagens é um recurso do Pub/Sub que permite receber mensagens nos seus clientes assinantes na ordem em que foram publicados pelo clientes editores.

Por exemplo, suponha que um cliente editor em uma região publique as mensagens 1, 2, e 3 em ordem. Com a ordenação de mensagens, o cliente assinante recebe as mensagens publicadas na mesma ordem. Para que sejam entregues em ordem, o editor o cliente precisa publicar as mensagens no mesmo region.

A ordenação de mensagens é um recurso útil em cenários como mudança de banco de dados captura, rastreamento de sessão de usuário e aplicativos de streaming em que a preservação cronologia dos eventos é importante.

Esta página explica o conceito de ordenação de mensagens e como configurar sua que os clientes assinantes recebam as mensagens em ordem. Para configurar seu editor clientes para ordenação de mensagens, consulte Usar chaves de ordem para publicar um mensagem.

Visão geral da ordenação de mensagens

A ordem no Pub/Sub é determinada por:

  • Chave de ordem: é uma string usada na Metadados de mensagem do Pub/Sub e representa a entidade para a qual as mensagens precisam ser ordenadas. A chave de ordenação pode ter até 1 KB. Para para receber um conjunto de mensagens ordenadas em uma região, é preciso publicar todas elas com a mesma chave de ordem na mesma região. Alguns exemplos de ordenação são IDs de clientes e a chave primária de uma linha em um banco de dados.

    A capacidade de publicação em cada chave de ordem é limitada a 1 MBps. O a capacidade de processamento em todas as chaves de ordem em um tópico é limitada à cota disponíveis em uma região de publicação. É possível aumentar esse limite pode chegar a muitas unidades de GBps.

    Uma chave de ordem não é equivalente a uma partição em um ambiente do sistema de mensagens, pois as chaves de ordem devem ter uma capacidade uma cardinalidade maior do que as partições.

  • Ativar a ordem das mensagens: essa é uma configuração de assinatura. Quando uma assinatura tem a ordenação de mensagens ativada, os clientes assinantes recebem mensagens publicadas na mesma região com a mesma chave de ordenação na ordem em que foram recebidas pelo serviço. É preciso ativar essa configuração. na assinatura.

    Suponha que você tenha duas assinaturas, A e B, vinculadas ao mesmo tópico T. A assinatura A é configurada com a ordenação de mensagens ativada e a assinatura A opção B é configurada sem a ordenação de mensagens ativada. Nessa arquitetura, tanto As assinaturas A e B recebem o mesmo conjunto de mensagens do tópico T. Se você publica mensagens com chaves de ordem na mesma região, assinatura A recebe as mensagens na ordem em que foram publicadas. Já a assinatura B recebe as mensagens sem qualquer ordem esperada.

Em geral, se sua solução exige que os clientes do editor enviem pedidos e mensagens desordenadas, criar tópicos separados, um para mensagens ordenadas e o "outro" para mensagens não ordenadas.

Considerações ao usar mensagens ordenadas

A lista a seguir contém informações importantes sobre o comportamento mensagens ordenadas no Pub/Sub:

  • Ordem dentro da chave: as mensagens publicadas com a mesma chave de ordem precisam ser recebidas em ordem. Suponha que, para ordenar a chave A, você publicar as mensagens 1, 2 e 3. Com a ordenação ativada, espera-se que 1 seja entregues antes das 2 e 2 devem ser entregues antes das 3.

  • Ordem entre chaves: as mensagens publicadas com chaves de ordem diferentes não são recebidas na ordem. Suponha que você tenha as chaves de ordem A e B. Para a chave de ordenação A, as mensagens 1 e 2 são publicadas em ordem. Para pedidos com a chave B, as mensagens 3 e 4 serão publicadas em ordem. No entanto, a mensagem 1 pode chegar antes ou depois da mensagem 4.

  • Reenvio de mensagens: o Pub/Sub entrega cada mensagem. pelo menos uma vez para que O serviço do Pub/Sub pode entregar as mensagens novamente. As reenvios de uma mensagem acionam o reenvio de todas as mensagens subsequentes para essa chave, mesmo as confirmadas. Suponha que um cliente assinante receba as mensagens 1, 2, e 3 para uma chave de ordem específica. Se a mensagem 2 for reenviada (porque o o prazo de confirmação expirou ou a confirmação de melhor esforço não persistem no Pub/Sub), a mensagem 3 também é reenviada. Se a ordem das mensagens e um tópico de mensagens inativas estão ativados em uma assinatura. Esse comportamento pode não ocorrer, já que o Pub/Sub encaminha mensagens para tópicos de mensagens inativas com base no melhor esforço.

  • Atrasos no reconhecimento e tópicos de mensagens inativas: mensagens não confirmadas de uma determinada chave de ordem pode atrasar a entrega de mensagens para outras chaves de ordem, especialmente durante reinicializações do servidor ou alterações no tráfego. Para manter a ordem nesses eventos, garanta o reconhecimento oportuno de todas as mensagens. Se a confirmação oportuna não for possível, considere usar uma tópico de mensagens inativas para evitar a retenção de mensagens indefinidas. Esteja ciente de que o pedido podem não ser preservadas quando as mensagens forem gravadas em um tópico de mensagens inativas.

  • Afinidade de mensagens (clientes streamingPull): as mensagens para a mesma chave são e geralmente são entregues ao mesmo cliente assinante de streamingPull. A afinidade é esperada quando as mensagens estão pendentes para uma chave de ordenação de um cliente assinante específico. Se não houver mensagens pendentes, a afinidade pode para balanceamento de carga ou desconexões do cliente.

    Para garantir um bom processamento, mesmo com possíveis alterações de afinidade, é é crucial para projetar seu aplicativo streamingPull de forma que ele possa lidar mensagens em qualquer cliente para uma determinada chave de ordem.

  • Integração com o Dataflow: não ative a ordenação de mensagens para assinaturas ao configurar o Dataflow com Pub/Sub O Dataflow tem um mecanismo próprio a ordem total das mensagens, garantindo a ordem cronológica de todas as mensagens como parte das operações de janelamento. Esse método de ordenação é diferente Abordagem baseada em chaves de ordem do Pub/Sub. Como usar chaves de ordem com o Dataflow pode reduzir o desempenho do pipeline.

  • Escalonamento automático: a entrega ordenada do Pub/Sub é escalonada para bilhões de chaves de pedidos. Um número maior de chaves de ordem permite que entrega paralela aos assinantes, já que a ordem se aplica a todas as mensagens com a mesma chave de ordem.

A entrega solicitada tem algumas desvantagens. Em comparação com itens não ordenados a entrega solicitada, pode reduzir um pouco a disponibilidade de publicação e aumentar a latência de entrega de mensagens de ponta a ponta. No caso de entrega pedida, o failover requer coordenação para garantir que as mensagens sejam gravadas e lidas na ordem correta.

Para mais informações sobre como usar a ordenação de mensagens, consulte os práticas recomendadas:

Comportamento do cliente assinante para ordenação de mensagens

Os clientes assinantes recebem mensagens na ordem em que foram publicadas em um em uma região específica. O Pub/Sub oferece suporte a diferentes maneiras de receber mensagens, como clientes assinantes conectados a pull e push assinaturas. As bibliotecas de cliente usam streamingPull (com exceção do PHP).

Para saber mais sobre esses tipos de assinatura, consulte Escolher um tipo de assinatura.

As seções a seguir discutem o que significa receber mensagens em ordem para cada tipo de cliente de assinante.

Clientes de assinantes do StreamingPull

Ao usar as bibliotecas de cliente com streamingPull, você deve especificar um usuário que é executado sempre que uma mensagem é recebida por um cliente assinante. Com bibliotecas de clientes, para qualquer chave de ordem determinada, o retorno de chamada é executado para de preenchimento das mensagens na ordem correta. Se as mensagens forem confirmados dentro desse callback, todos os cálculos em uma mensagem ocorrem em ordem. No entanto, se o callback do usuário programar outro trabalho assíncrono em mensagens, o cliente assinante precisa garantir que o trabalho assíncrono é feito em ordem. Uma opção é adicionar mensagens a uma fila de trabalho local que são processados em ordem.

Clientes de assinantes pull

Para clientes assinantes conectados a assinaturas de pull, a ordenação de mensagens do Pub/Sub oferece suporte a:

  • Todas as mensagens para uma chave de ordem no PullResponse estão na ordem correta na lista.

  • Apenas um lote de mensagens pode estar pendente para uma chave de ordenação por vez.

O requisito de que apenas um lote de mensagens possa estar pendente em um necessário para manter a entrega solicitada, já que o Pub/Sub serviço não pode garantir o sucesso ou a latência da resposta enviada para a solicitação de envio de um assinante.

Clientes de assinantes de push

As restrições ao push são ainda mais rígidas do que as de puxar. Para assinaturas de push, o Pub/Sub aceita apenas uma para cada chave de ordem por vez. Cada mensagem é enviada para um endpoint de push como uma solicitação separada. Portanto, o envio das solicitações em paralelo teria o mesmo problema que o envio de vários lotes de mensagens para a mesma chave de ordenação para extrair assinantes simultaneamente. As assinaturas de push podem não ser uma boa opção para tópicos em que as mensagens são são publicados frequentemente com a mesma chave de ordem ou em que a latência é extremamente importante.

Exportar clientes assinantes

A exportação de assinaturas é compatível com mensagens ordenadas. Para assinaturas do BigQuery, as mensagens com a mesma chave de ordenação são gravadas na tabela do BigQuery em ordem. Para assinaturas do Cloud Storage, as mensagens com a mesma chave de ordenação podem não ser gravadas no mesmo arquivo. Quando estão no mesmo arquivo, as mensagens para uma chave de ordem estão em ordem. Quando distribuídas em vários arquivos, as mensagens posteriores de uma chave de ordenação podem aparecer em um arquivo com um nome que tem um carimbo de data/hora anterior ao do nome do arquivo com as mensagens anteriores.

Ativar a ordenação de mensagens

Para receber as mensagens em ordem, defina a propriedade de ordenação das mensagens na assinatura que recebe as mensagens. O recebimento de mensagens pode aumentar a latência. Não é possível mudar a propriedade de ordenação de mensagens depois de criar uma assinatura.

Você pode definir a propriedade de ordem das mensagens ao criar uma assinatura usando o o console do Google Cloud, a Google Cloud CLI ou a API Pub/Sub.

Console

Para criar uma assinatura com a propriedade de ordenação de mensagens, siga estas etapas:

  1. No console do Google Cloud, acesse a página Assinaturas.

Acessar "Assinaturas"

  1. Clique em Criar assinatura.

  2. Insira um ID de assinatura.

  3. Escolha um tópico para receber mensagens.

  4. Na seção Ordem das mensagens, selecione Ordenar mensagens com uma chave de ordem.

  5. Clique em Criar.

gcloud

Para criar uma assinatura com a propriedade de ordenação de mensagens, use o O comando gcloud pubsub subscriptions create e o Sinalização --enable-message-ordering:

gcloud pubsub subscriptions create SUBSCRIPTION_ID \
  --enable-message-ordering

Substitua SUBSCRIPTION_ID pelo ID da assinatura.

Se a solicitação for bem-sucedida, a linha de comando exibirá uma confirmação:

Created subscription [SUBSCRIPTION_ID].

REST

Para criar uma assinatura com a propriedade de ordenação de mensagens, envie uma solicitação PUT como esta:

PUT https://pubsub.googleapis.com/v1/projects/PROJECT_ID/subscriptions/SUBSCRIPTION_ID
Authorization: Bearer $(gcloud auth application-default print-access-token)

Substitua:

  • PROJECT_ID: o ID do projeto com o tópico.
  • SUBSCRIPTION_ID: o ID da assinatura.

No corpo da solicitação, especifique o seguinte:

{
  "topic": TOPIC_ID,
  "enableMessageOrdering": true,
}

Substitua TOPIC_ID pelo ID do tópico a ser anexado à assinatura.

Se a solicitação for bem-sucedida, a resposta será a assinatura no formato JSON:

{
  "name": projects/PROJECT_ID/subscriptions/SUBSCRIPTION_ID,
  "topic": projects/PROJECT_ID/topics/TOPIC_ID,
  "enableMessageOrdering": true,
}

C++

Antes de tentar esse exemplo, siga as instruções de configuração do C++ em Guia de início rápido: como usar bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API Pub/Sub C++.

namespace pubsub = ::google::cloud::pubsub;
namespace pubsub_admin = ::google::cloud::pubsub_admin;
[](pubsub_admin::SubscriptionAdminClient client,
   std::string const& project_id, std::string const& topic_id,
   std::string const& subscription_id) {
  google::pubsub::v1::Subscription request;
  request.set_name(
      pubsub::Subscription(project_id, subscription_id).FullName());
  request.set_topic(pubsub::Topic(project_id, topic_id).FullName());
  request.set_enable_message_ordering(true);
  auto sub = client.CreateSubscription(request);
  if (sub.status().code() == google::cloud::StatusCode::kAlreadyExists) {
    std::cout << "The subscription already exists\n";
    return;
  }
  if (!sub) throw std::move(sub).status();

  std::cout << "The subscription was successfully created: "
            << sub->DebugString() << "\n";
}

C#

Antes de tentar esse exemplo, siga as instruções de configuração do C# em Guia de início rápido: como usar bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API Pub/Sub C#.


using Google.Cloud.PubSub.V1;
using Grpc.Core;

public class CreateSubscriptionWithOrderingSample
{
    public Subscription CreateSubscriptionWithOrdering(string projectId, string topicId, string subscriptionId)
    {
        SubscriberServiceApiClient subscriber = SubscriberServiceApiClient.Create();
        var topicName = TopicName.FromProjectTopic(projectId, topicId);
        var subscriptionName = SubscriptionName.FromProjectSubscription(projectId, subscriptionId);

        var subscriptionRequest = new Subscription
        {
            SubscriptionName = subscriptionName,
            TopicAsTopicName = topicName,
            EnableMessageOrdering = true
        };

        Subscription subscription = null;
        try
        {
            subscription = subscriber.CreateSubscription(subscriptionRequest);
        }
        catch (RpcException e) when (e.Status.StatusCode == StatusCode.AlreadyExists)
        {
            // Already exists.  That's fine.
        }
        return subscription;
    }
}

Go

Antes de tentar esse exemplo, siga as instruções de configuração do Go em Guia de início rápido: como usar bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API Pub/Sub Go.

import (
	"context"
	"fmt"
	"io"
	"time"

	"cloud.google.com/go/pubsub"
)

func createWithOrdering(w io.Writer, projectID, subID string, topic *pubsub.Topic) error {
	// projectID := "my-project-id"
	// subID := "my-sub"
	// topic of type https://godoc.org/cloud.google.com/go/pubsub#Topic
	ctx := context.Background()
	client, err := pubsub.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("pubsub.NewClient: %w", err)
	}
	defer client.Close()

	// Message ordering can only be set when creating a subscription.
	sub, err := client.CreateSubscription(ctx, subID, pubsub.SubscriptionConfig{
		Topic:                 topic,
		AckDeadline:           20 * time.Second,
		EnableMessageOrdering: true,
	})
	if err != nil {
		return fmt.Errorf("CreateSubscription: %w", err)
	}
	fmt.Fprintf(w, "Created subscription: %v\n", sub)
	return nil
}

Java

Antes de tentar essa amostra, siga as instruções de configuração do Java em Guia de início rápido: como usar bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API Pub/Sub Java.

import com.google.cloud.pubsub.v1.SubscriptionAdminClient;
import com.google.pubsub.v1.ProjectSubscriptionName;
import com.google.pubsub.v1.ProjectTopicName;
import com.google.pubsub.v1.Subscription;
import java.io.IOException;

public class CreateSubscriptionWithOrdering {
  public static void main(String... args) throws Exception {
    // TODO(developer): Replace these variables before running the sample.
    String projectId = "your-project-id";
    String topicId = "your-topic-id";
    String subscriptionId = "your-subscription-id";

    createSubscriptionWithOrderingExample(projectId, topicId, subscriptionId);
  }

  public static void createSubscriptionWithOrderingExample(
      String projectId, String topicId, String subscriptionId) throws IOException {
    try (SubscriptionAdminClient subscriptionAdminClient = SubscriptionAdminClient.create()) {

      ProjectTopicName topicName = ProjectTopicName.of(projectId, topicId);
      ProjectSubscriptionName subscriptionName =
          ProjectSubscriptionName.of(projectId, subscriptionId);

      Subscription subscription =
          subscriptionAdminClient.createSubscription(
              Subscription.newBuilder()
                  .setName(subscriptionName.toString())
                  .setTopic(topicName.toString())
                  // Set message ordering to true for ordered messages in the subscription.
                  .setEnableMessageOrdering(true)
                  .build());

      System.out.println("Created a subscription with ordering: " + subscription.getAllFields());
    }
  }
}

Node.js

Antes de tentar essa amostra, siga as instruções de configuração do Node.js em Guia de início rápido: como usar bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API Pub/Sub Node.js.

/**
 * TODO(developer): Uncomment these variables before running the sample.
 */
// const topicNameOrId = 'YOUR_TOPIC_NAME_OR_ID';
// const subscriptionNameOrId = 'YOUR_SUBSCRIPTION_NAME_OR_ID';

// Imports the Google Cloud client library
const {PubSub} = require('@google-cloud/pubsub');

// Creates a client; cache this for further use
const pubSubClient = new PubSub();

async function createSubscriptionWithOrdering(
  topicNameOrId,
  subscriptionNameOrId
) {
  // Creates a new subscription
  await pubSubClient
    .topic(topicNameOrId)
    .createSubscription(subscriptionNameOrId, {
      enableMessageOrdering: true,
    });
  console.log(
    `Created subscription ${subscriptionNameOrId} with ordering enabled.`
  );
  console.log(
    'To process messages in order, remember to add an ordering key to your messages.'
  );
}

Node.js

Antes de tentar essa amostra, siga as instruções de configuração do Node.js em Guia de início rápido: como usar bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API Pub/Sub Node.js.

/**
 * TODO(developer): Uncomment these variables before running the sample.
 */
// const topicNameOrId = 'YOUR_TOPIC_NAME_OR_ID';
// const subscriptionNameOrId = 'YOUR_SUBSCRIPTION_NAME_OR_ID';

// Imports the Google Cloud client library
import {PubSub} from '@google-cloud/pubsub';

// Creates a client; cache this for further use
const pubSubClient = new PubSub();

async function createSubscriptionWithOrdering(
  topicNameOrId: string,
  subscriptionNameOrId: string
) {
  // Creates a new subscription
  await pubSubClient
    .topic(topicNameOrId)
    .createSubscription(subscriptionNameOrId, {
      enableMessageOrdering: true,
    });
  console.log(
    `Created subscription ${subscriptionNameOrId} with ordering enabled.`
  );
  console.log(
    'To process messages in order, remember to add an ordering key to your messages.'
  );
}

Python

Antes de tentar esse exemplo, siga as instruções de configuração do Python em Guia de início rápido: como usar bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API Pub/Sub Python.

from google.cloud import pubsub_v1

# TODO(developer): Choose an existing topic.
# project_id = "your-project-id"
# topic_id = "your-topic-id"
# subscription_id = "your-subscription-id"

publisher = pubsub_v1.PublisherClient()
subscriber = pubsub_v1.SubscriberClient()
topic_path = publisher.topic_path(project_id, topic_id)
subscription_path = subscriber.subscription_path(project_id, subscription_id)

with subscriber:
    subscription = subscriber.create_subscription(
        request={
            "name": subscription_path,
            "topic": topic_path,
            "enable_message_ordering": True,
        }
    )
    print(f"Created subscription with ordering: {subscription}")

Ruby

Antes de tentar esse exemplo, siga as instruções de configuração do Ruby em Guia de início rápido: como usar bibliotecas de cliente. Para mais informações, consulte a documentação de referência da API Pub/Sub Ruby.

# topic_id        = "your-topic-id"
# subscription_id = "your-subscription-id"

pubsub = Google::Cloud::Pubsub.new

topic        = pubsub.topic topic_id
subscription = topic.subscribe subscription_id,
                               message_ordering: true

puts "Pull subscription #{subscription_id} created with message ordering."

A seguir