Compartilhar via


Padrões de tarefa de replicação de mensagem

A visão geral da federação e das funções do replicador explicam a lógica para os elementos básicos das tarefas de replicação. Recomenda-se que você conheça essas visões gerais antes de prosseguir neste artigo.

Neste artigo detalhamos as diretrizes de implementação para vários padrões destacados na seção visão geral.

Replicação

O padrão de replicação copia mensagens de uma fila ou de um tópico para o próximo, ou de uma fila ou um tópico para outro destino, como um Hub de Eventos. As mensagens são encaminhadas sem fazer modificações no conteúdo do evento.

A implementação desse padrão é abordada pelo exemplo de replicação de mensagem entre o Barramento de Serviço do Azure.

Sequências e preservação da ordem

O modelo de replicação não tem como objetivo preservar a ordem absoluta de mensagens de uma fila ou tópico de origem em uma fila ou tópico de destino, mas se concentra, sempre que necessário, em preservar a ordem relativa de mensagens em que o aplicativo exige isso. O aplicativo habilita isso habilitando o suporte de sessão para a entidade de origem e agrupando mensagens relacionadas com a mesma chave da sessão.

As funções de replicação predefinidas com reconhecimento de sessão garantem que as sequências de mensagens com a mesma ID de sessão recuperadas de uma entidade de origem sejam enviadas para a fila ou o tópico de destino como um lote na sequência original e com a mesma ID de sessão.

Metadados atribuídos ao serviço

Os metadados atribuídos ao serviço de uma mensagem obtida da fila ou do tópico de origem, a hora de enfileiramento original e o número de sequência são substituídos por novos valores atribuídos ao novo serviço na fila ou no tópico de destino, mas com as tarefas de replicação padrão fornecidas em nossos exemplos, os valores originais são preservados nas propriedades do usuário: repl-enqueue-time(cadeia de caracteres ISO8601) e repl-sequence.

Essas propriedades são do tipo string (cadeia de caracteres) e contêm o valor em cadeias de caracteres das respectivas propriedades originais. Se a mensagem for encaminhada várias vezes, os metadados atribuídos ao serviço da origem imediata serão anexados às propriedades já existentes, com valores separados por ponto e vírgula.

Failover

Se você estiver usando a replicação com o objetivo de usar na recuperação de desastres, como mensagens regionais de disponibilidade no Barramento de Serviço ou contra interrupções na rede, qualquer cenário de falha desses tipos exigirá a execução de um failover de um tópico ou uma fila para o próximo hub, informando produtores e/ou consumidores para usarem o ponto de extremidade secundário.

Para todos os cenários de failover, supõe-se que os elementos necessários dos namespaces sejam estruturalmente idênticos, o que significa que os tópicos e as filas são nomeados de maneira idêntica, e que as regras de assinatura de acesso compartilhado e/ou as regras de controle de acesso baseado em função estão configuradas da mesma maneira. Para criar (e atualizar) um namespace secundário, siga as diretrizes para mover namespaces e omita a etapa de limpeza.

Para forçar produtores e consumidores a mudarem, você precisa disponibilizar as informações sobre qual namespace usar, em um local que seja fácil de pesquisar, acessar e atualizar. Se produtores ou consumidores encontrarem erros frequentes ou persistentes, eles devem consultar esse local e ajustar sua configuração. Há várias maneiras de compartilhar essa configuração, mas indicamos dois: DNS e compartilhamentos de arquivos.

Configuração de failover com base em DNS

Uma abordagem possível é manter as informações em Registros SRV de DNS em um DNS que você controla e apontar para os respectivos pontos de extremidade do tópico ou da fila. Lembre-se de que os hubs de mensagem não permitem que seus pontos de extremidade tenham um alias direto com registros CNAME, o que significa que você usa o DNS como um mecanismo de pesquisa resiliente para endereços de ponto de extremidade e não para resolver diretamente as informações de endereço IP.

Suponha que você tenha o domínio example.com e, para seu aplicativo, uma zona test.example.com. Para dois Barramentos de Serviço alternativos, você criará duas zonas aninhadas adicionais e um Registro SRV em cada um.

Os Registros SRV são, seguindo a convenção comum, prefixados com _azure_servicebus._amqp e retêm dois registros de ponto de extremidade: um para AMQP-over-TLS na porta 5671 e outro para AMQP-over-WebSockets na porta 443, ambos apontando para o ponto de extremidade dos Barramentos de Serviço do namespace correspondente à zona.

Zona Registros SRV
sb1.test.example.com _azure_servicebus._amqp.sb1.test.example.com
1 1 5671 sb1-test-example-com.servicebus.windows.net
2 2 443 sb1-test-example-com.servicebus.windows.net
sb2.test.example.com _azure_servicebus._amqp.sb1.test.example.com
1 1 5671 sb2-test-example-com.servicebus.windows.net
2 2 443 sb2-test-example-com.servicebus.windows.net

Na zona do aplicativo, crie uma entrada CNAME que aponta para a zona subordinada correspondente à sua fila ou ao seu tópico primário:

Registro CNAME Alias
servicebus.test.example.com sb1.test.example.com

Usando um cliente DNS que permite a consulta de registros CNAME e SRV de forma explícita (os clientes internos do Java e do .NET só permitem a resolução simples de nomes para endereços IP), você pode resolver o ponto de extremidade desejado. Com DnsClient.net, por exemplo, a função pesquisa é:

static string GetServiceBusName(string aliasName)
{
    const string SrvRecordPrefix = "_azure_servicebus._amqp.";
    LookupClient lookup = new LookupClient();

    return (from CNameRecord alias in (lookup.Query(aliasName, QueryType.CNAME).Answers)
            from SrvRecord srv in lookup.Query(SrvRecordPrefix + alias.CanonicalName, QueryType.SRV).Answers
            where srv.Port == 5671
            select srv.Target).FirstOrDefault()?.Value.TrimEnd('.');
}

A função retorna o nome do host de destino registrado para a porta 5671 da zona que é o alias atual do CNAME, conforme mostrado acima.

A execução do failover requer que o registro CNAME seja alterado, apontando-o para a zona alternativa.

A vantagem de usar o DNS e, especificamente, o DNS do Azure, é que as informações do DNS do Azure são replicadas globalmente e, portanto, são resilientes contra interrupções de uma única região.

Esse procedimento é semelhante ao funcionamento do Geo-DR do Barramento de Serviço, mas você tem o controle total. Ele também funciona com cenários ativos/inativos.

Configuração de failover com base em compartilhamento de arquivo

A alternativa mais simples ao uso de DNS para compartilhar informações de ponto de extremidade, é colocar o nome do ponto de extremidade primário em um arquivo de texto sem formatação e disponibilizar o arquivo de uma infraestrutura robusta contra interrupções que permita atualizações.

Se você já tiver uma infraestrutura de site com alta disponibilidade, com disponibilidade global e replicação de conteúdo, adicione e republique o arquivo se uma troca for necessária.

Mesclar

O padrão de mesclagem tem uma ou mais tarefas de replicação que apontam para um destino, possivelmente ao mesmo tempo com produtores regulares, que também enviam mensagens para o mesmo destino.

As variações desse padrão são:

  • Duas ou mais funções de replicação obtendo simultaneamente mensagens de origens separadas e enviando-as para o mesmo destino.
  • Mais uma função de replicação obtendo mensagens de uma fonte enquanto o destino também é usado diretamente por produtores.
  • O padrão anterior, mas mensagens espelhadas entre dois ou mais tópicos, resultando nesses tópicos que contêm as mesmas mensagens, independentemente de onde as mensagens são produzidas.

As duas primeiras variações de padrão são triviais e não diferem das tarefas de replicação simples.

O último cenário requer a exclusão de mensagens já replicadas para que não sejam replicadas novamente. A técnica é demonstrada e explicada no exemplo ativo/ativo.

Editor

O padrão do editor se baseia no padrão de replicação, mas as mensagens são modificadas antes de serem encaminhadas. Exemplos destas modificações:

  • Transcodificação – se o conteúdo da mensagem (também conhecido como "corpo" ou "carga") chega da origem codificada usando o formato Apache Avro ou outro formato de serialização proprietário, mas a expectativa do sistema destino é que o conteúdo esteja codificado em JSON, uma tarefa de replicação de transcodificação primeiro desserializa o conteúdo do Apache Avro em um grafo de objetos na memória interna e, em seguida, serializa esse grafo no formato JSON para a mensagem que está sendo encaminhada. A transcodificação também inclui as tarefas de compactação e de descompactação do conteúdo.
  • Transformação – as mensagens que contêm dados estruturados podem exigir a reformatação desses dados para facilitar o processamento por consumidores de downstream. Este escopo pode envolver trabalhos como por exemplo, nivelar estruturas aninhadas, remover elementos de dados estranhos ou reformatar o conteúdo para ajustá-lo exatamente a um determinado esquema.
  • Envio em lote – as mensagens podem ser recebidas em lotes (várias mensagens em uma única transferência) de uma origem, mas precisam ser encaminhadas individualmente para um destino ou vice-versa. Portanto, uma tarefa pode encaminhar várias mensagens com base em uma única transferência de mensagem de entrada ou agregar um conjunto de mensagens que são transferidas juntos.
  • Validação – os dados de mensagem de origens externas geralmente precisam ser verificados se estão em conformidade com um conjunto de regras, antes que possam ser encaminhados. As regras podem ser expressas usando esquemas ou código. Mensagens que não estão em conformidade podem ser removidas, com o problema registrado em logs, ou podem ser encaminhadas a um destino especial para que sejam posteriormente tratadas.
  • Enriquecimento – os dados de mensagens provenientes de algumas origens podem exigir enriquecimento com contexto adicional para que sejam utilizáveis nos sistemas de destino. Esse enriquecimento pode envolver a pesquisa de dados de referência e a incorporação desses dados com a mensagem ou a adição de informações sobre a origem que é conhecida pela tarefa de replicação, mas não estão contidas nas mensagens.
  • Filtragem – algumas mensagens que chegam de uma origem podem precisar ser retidos com base em alguma regra. Um filtro testará a mensagem em relação a uma regra e descartará a mensagem se ela não corresponder à regra. Uma forma de filtragem é remover mensagens duplicadas observando determinados critérios e descartar mensagens subsequentes com os mesmos valores.
  • Roteamento e particionamento – algumas tarefas de replicação podem permitir dois ou mais destinos alternativos e definir regras para as quais o destino de replicação é escolhido para qualquer mensagem específica com base nos metadados ou no conteúdo da mensagem. Uma forma especial de roteamento é o particionamento, em que a tarefa atribui explicitamente partições em um destino de replicação com base em regras.
  • Criptografia – uma tarefa de replicação pode precisar descriptografar o conteúdo que chega da origem e/ou criptografar o conteúdo encaminhado a um destino e/ou pode precisar verificar a integridade do conteúdo e dos metadados em relação a uma assinatura executada na mensagem, ou anexar a assinatura.
  • Atestado – uma tarefa de replicação pode anexar metadados, possivelmente protegidos por uma assinatura digital, a uma mensagem que atesta que a mensagem foi recebida por meio de um canal específico ou em um momento específico.
  • Encadeamento – uma tarefa de replicação pode aplicar assinaturas a sequências de mensagens, de modo que a integridade da sequência seja protegida e as mensagens ausentes possam ser detectadas.

Todos esses padrões podem ser implementados usando o Azure Functions, com o gatilho dos Hubs de Mensagens para adquirir as mensagens e a associação de saída do tópico ou da fila para entregá-las.

Roteamento

O padrão de roteamento baseia-se no padrão de replicação, mas em vez de ter uma origem e um destino, a tarefa de replicação tem vários destinos, ilustrados aqui em C#:

[FunctionName("SBRouter")]
public static async Task Run(
    [ServiceBusTrigger("source", Connection = "serviceBusConnectionAppSetting")] ServiceBusReceivedMessage[] messages,
    [ServiceBusOutput("dest1", Connection = "serviceBusConnectionAppSetting")] IAsyncCollector<dynamic> output1,
    [ServiceBusOutput("dest2", Connection = "serviceBusConnectionAppSetting")] IAsyncCollector<dynamic> output2,
    ILogger log)
{
    foreach (Message messageData in messages)
    {
        // send to output1 or output2 based on criteria 
    }
}

A função de roteamento considera os metadados da mensagem e/ou o conteúdo da mensagem e, em seguida, seleciona um dos destinos disponíveis para enviar.

Próximas etapas