Replicação de mensagens e federação entre regiões
Dentro de namespaces, o Barramento de Serviço do Azure dá suporte à criação de topologias de filas encadeadas e assinaturas de tópicos usando o encaminhamento automático para permitir a implementação de vários padrões de roteamento. Por exemplo, você pode fornecer aos parceiros filas dedicadas para as quais eles têm permissões de envio ou recebimento e que podem ser temporariamente suspensas, se necessário, e conectá-los de forma flexível a outras entidades privadas do aplicativo. Você também pode criar topologias complexas de roteamento de vários estágios ou filas no estilo de caixa de correio, que drenam as assinaturas de tópicos semelhantes a filas e permitem mais capacidade de armazenamento por assinante.
Muitas soluções sofisticadas também exigem que as mensagens sejam replicadas entre os limites do namespace para implementar esses e outros padrões. As mensagens podem ter que fluir entre namespaces associados a vários locatários de aplicativos diferentes ou em várias regiões diferentes do Azure.
Sua solução manterá vários namespaces do Service Bus em diferentes regiões e replicará mensagens entre Filas e Tópicos e/ou trocará mensagens com fontes e destinos como Hubs de Eventos do Azure, Hub IoT do Azure ou Apache Kafka.
Esses cenários são o foco deste artigo.
Padrões de federação
Há várias motivações potenciais para mover mensagens entre entidades do Service Bus, como Filas ou Tópicos, ou entre o Service Bus e outras fontes e destinos.
Em comparação com o conjunto semelhante de padrões para Hubs de Eventos, a federação para entidades semelhantes a filas é mais complexa porque as filas de mensagens prometem aos seus consumidores propriedade exclusiva sobre qualquer mensagem única, espera-se que preservem a ordem de chegada na entrega de mensagens e que o corretor coordene a distribuição justa de mensagens entre consumidores concorrentes.
Existem impedimentos práticos, incluindo as restrições do teorema da PAC, que tornam difícil fornecer uma visão unificada de uma fila que está simultaneamente disponível em várias regiões e que permite que consumidores concorrentes distribuídos regionalmente assumam a propriedade exclusiva das mensagens. Essa fila distribuída geograficamente exigiria uma replicação totalmente consistente não apenas das mensagens, mas também do estado de entrega de cada mensagem antes que as mensagens possam ser disponibilizadas aos consumidores. Um objetivo de consistência total para uma fila hipotética distribuída regionalmente está em conflito direto com o objetivo principal que praticamente todos os clientes do Barramento de Serviço do Azure têm ao considerar cenários de federação: Máxima disponibilidade e confiabilidade para suas soluções.
Por conseguinte, os padrões aqui apresentados centram-se na disponibilidade e na fiabilidade, ao mesmo tempo que visam evitar da melhor forma a perda de informação e o tratamento duplicado das mensagens.
Resiliência contra eventos de disponibilidade regional
Embora a disponibilidade máxima e a confiabilidade sejam as principais prioridades operacionais do Service Bus, há, no entanto, muitas maneiras pelas quais um produtor ou consumidor pode ser impedido de falar com o Service Bus "primário" atribuído devido a problemas de rede ou resolução de nomes, ou onde a entidade do Service Bus pode, de fato, não responder temporariamente ou retornar erros. O processador de mensagens designado também pode ficar indisponível.
Essas condições não são "desastrosas", de modo que você desejará abandonar completamente a implantação regional, como faria em uma situação de recuperação de desastre, mas o cenário de negócios de alguns aplicativos já pode ser afetado por eventos de disponibilidade que não duram mais do que alguns minutos ou até segundos. O Barramento de Serviço do Azure é frequentemente usado em ambientes de nuvem híbrida e com clientes que residem na borda da rede, por exemplo, em lojas de varejo, restaurantes, agências bancárias, locais de fabricação, instalações logísticas e aeroportos. É possível que um problema de roteamento ou congestionamento de rede afete a capacidade de qualquer site de alcançar seu ponto de extremidade do Service Bus atribuído, enquanto um ponto de extremidade secundário em uma região diferente pode estar acessível. Ao mesmo tempo, os sistemas que processam mensagens que chegam desses sites ainda podem ter acesso desimpedido aos pontos de extremidade primários e secundários do Service Bus.
Há muitos exemplos práticos desses aplicativos de nuvem híbrida e borda com baixa tolerância comercial ao impacto de problemas de roteamento de rede ou de problemas transitórios de disponibilidade de uma entidade do Service Bus. Isso inclui o processamento de pagamentos em locais de varejo, embarque nos portões dos aeroportos e pedidos de telefone celular em restaurantes, que chegam a um instante, e paralisação completa sempre que o caminho de comunicação confiável não estiver disponível.
Nesta categoria, discutimos três padrões distribuídos distintos: replicação "totalmente ativa", replicação "ativa-passiva" e replicação "spillover".
Replicação totalmente ativa
O padrão de replicação "totalmente ativo" permite que uma réplica ativa do mesmo tópico lógico (ou fila) esteja disponível em vários namespaces (e regiões) e que todas as mensagens fiquem disponíveis em todas as réplicas, independentemente de onde foram enfileiradas. O padrão geralmente preserva a ordem das mensagens em relação a qualquer editor.
Como mostrado na ilustração, o padrão geralmente se apoia em Tópicos do Service Bus. Um tópico para cada namespace que deve participar do esquema de replicação. Cada um desses tópicos tem uma "assinatura de replicação" para qualquer um dos outros tópicos para os quais as mensagens devem ser replicadas. Na ilustração acima, temos simplesmente um par de tópicos e, portanto, uma única assinatura de replicação para o respetivo outro tópico. Em um cenário com três namespaces {n1, n2, n3}, um tópico no namespace n1 teria duas assinaturas de replicação, uma para o tópico correspondente em n2 e outra para o tópico correspondente em n3.
Cada assinatura de replicação tem uma regra que combina uma expressão de filtro SQL (replicated <> 1
) e uma ação SQL (set replicated = 1
). O filtro da regra garante que apenas as mensagens em que a propriedade replication
personalizada não está definida ou não tem o valor 1
se tornem elegíveis para esta assinatura, e a ação define essa propriedade exata para o valor 1
em cada mensagem selecionada logo em seguida. O efeito é que, quando a mensagem é copiada para o tópico correspondente, ela não é mais elegível para replicação na direção oposta e, portanto, evitamos que as mensagens saltem entre réplicas.
Uma assinatura com uma respetiva regra pode ser facilmente adicionada a qualquer tópico usando a CLI do Azure desta forma.
az servicebus topic subscription rule create --resource-group myresourcegroup \
--namespace mynamespace --topic-name mytopic \
--subscription-name replication --name replication \
--action-sql-expression "set replication = 1" \
--filter-sql-expression "replication IS NULL"
Para modelar uma fila, cada tópico é restrito a apenas uma assinatura regular (diferente das assinaturas de replicação) que todos os consumidores compartilham.
O modelo de replicação totalmente ativo coloca uma cópia de cada mensagem enviada em qualquer um dos tópicos em cada um dos tópicos. Isso significa que o código do aplicativo em cada região verá e processará todas as mensagens. Esse padrão é adequado para cenários em que os dados estão sendo compartilhados em várias regiões ou se o processamento redundante é geralmente desejado. Se você precisar processar cada mensagem apenas uma vez, como em uma fila regular, precisará considerar um dos dois padrões a seguir.
Replicação Ativo-Passivo
O padrão de replicação "ativo-passivo" é uma variação do padrão anterior, onde apenas um dos tópicos (o "primário") é usado ativamente pelo aplicativo para enviar e receber mensagens e as mensagens são replicadas em um tópico secundário para o caso em que o tópico principal pode se tornar indisponível ou inacessível.
A principal diferença entre esse padrão e o padrão anterior é que a replicação é unidirecional do tópico primário para o tópico secundário. O tópico secundário nunca se torna o principal, mas é uma opção de backup para quando o tópico principal está temporariamente inutilizável.
A vantagem de usar esse padrão é que ele tenta ajudar a minimizar o processamento duplicado. Durante a replicação, a TimeToLive
propriedade message é definida como uma duração nas mensagens replicadas que reflete o tempo esperado durante o qual uma falha do primário levará a um failover. Por exemplo, se o seu cenário de caso de uso exigir uma mudança do consumidor para o secundário dentro de no máximo 1 minuto após o início da recuperação de mensagens do primário mostrando problemas, o secundário deve idealmente ter todas as mensagens disponíveis que você não pôde acessar no primário, mas um número mínimo de mensagens que você já havia processado do primário antes que os problemas aparecessem. Se definirmos o TimeToLive
para o dobro desse período, 2 minutos, durante a replicação (set sys.TimeToLive = '0:2:0'
na ação de regra), o secundário reterá apenas mensagens por 2 minutos e descartará as mais antigas. Isso significa que, quando o recetor muda para o secundário, ele pode ler e descartar rapidamente mensagens mais antigas do que a última que processou e, em seguida, processar a partir da primeira mensagem que ainda não viu. A duração real da retenção dependerá do caso de uso específico e da rapidez que você deseja e pode alternar para o secundário em seu aplicativo. O TimeToLive
cenário é honrado na faixa de alguns segundos a dias.
Enquanto o aplicativo está usando o secundário, ele também pode publicar diretamente no tópico secundário, que então age como qualquer tópico regular. Após a transição para o secundário, o consumidor verá, portanto, uma mistura de mensagens replicadas e mensagens publicadas diretamente no secundário. O aplicativo deve, portanto, primeiro mudar a publicação de volta para o primário e ainda permitir a drenagem das mensagens publicadas localmente antes de mudar o consumidor de volta para o secundário. Devido à retomada automática da replicação assim que o primário estiver novamente disponível, o consumidor também receberá novas mensagens publicadas no primário durante esse período, embora com uma latência um pouco maior.
Esse padrão é adequado para cenários em que as mensagens devem ser processadas apenas uma vez. O aplicativo precisa cooperar para manter o controle das mensagens que processou a partir do primário, porque ele encontrará duplicatas durante a janela de failover no secundário e encontrará novamente duplicatas ao voltar atrás. O critério de eliminação da duplicação deve ser melhor um aplicativo fornecido
MessageId
. OEnqueuedTimeUtc
valor também é adequado como um indicador de marca d'água, mas o aplicativo precisa permitir alguma quantidade de desvio de relógio (vários segundos) entre primário e secundário, como em qualquer sistema distribuído.
Replicação de transbordamento
O padrão de replicação "spillover" permite o uso ativo/ativo de várias entidades do Service Bus em várias regiões para lidar com o cenário em que o Service Bus está íntegro, mas o consumidor fica sobrecarregado com o número de mensagens pendentes ou está completamente indisponível. Uma razão para isso pode ser que um banco de dados que suporta o processo do consumidor pode estar lento ou indisponível. Esse padrão funciona com filas simples e com assinaturas de tópicos.
Conforme mostrado na ilustração, o padrão de replicação de spillover replica mensagens da fila de letras mortas associada a uma fila ou assinatura para uma fila ou tópico emparelhado em um namespace diferente.
Sem que haja uma situação de falha, os dois namespaces são usados em paralelo, cada um recebendo algum subconjunto do tráfego geral de mensagens e seus consumidores associados lidando com esse subconjunto. Uma vez que um dos consumidores começa a apresentar altas taxas de falha ou para completamente, as respetivas mensagens acabarão na fila de mensagens mortas, seja por exceder a contagem de entrega ou porque ela expira. As tarefas de replicação irão então buscá-los e enfileirá-los novamente na fila emparelhada, onde serão apresentados ao consumidor presumivelmente saudável.
Se o processamento tiver de ocorrer dentro de um determinado prazo, a fila TimeToLive
e/ou as mensagens devem ser definidas de modo a que o processamento ainda possa ocorrer a tempo pelo spillover secundário, por exemplo TimeToLive
, pode ser definido para metade do tempo permitido.
Assim como acontece com o padrão totalmente ativo, o aplicativo pode adicionar um indicador à mensagem se a mensagem já foi replicada uma vez, de modo que eles não saltem entre o par de filas, mas sejam postados em uma fila auxiliar que atua como a fila de letras mortas para o padrão composto.
Esse padrão é adequado para cenários em que a principal preocupação é se defender contra problemas de disponibilidade nos consumidores ou recursos dos quais os consumidores dependem, e também redistribuir picos de tráfego em uma das filas emparelhadas. Ele também fornece proteção contra que um dos namespaces fique indisponível se os consumidores lerem de ambas as filas, mas o atraso de replicação imposto pela
TimeToLive
expiração pode fazer com que as mensagens dentro dessa janela de tempo se estendam no namespace indisponível.
Otimização da latência
Os tópicos são usados para distribuir informações a vários consumidores. Em alguns casos, especialmente os consumidores com ampla distribuição geográfica, pode ser benéfico replicar mensagens de um tópico em um tópico em um namespace secundário mais próximo dos consumidores.
Por exemplo, ao compartilhar dados entre hubs regionais e continentais, é mais eficiente transferir informações apenas uma vez entre hubs e fazer com que os consumidores obtenham sua cópia dos dados desses hubs.
As transferências de replicação podem ser feitas em lotes, que os consumidores geralmente obtêm e liquidam mensagens uma a uma. Com uma latência de rede base de 100 ms entre, por exemplo, a América do Norte e a Europa, cada mensagem leva 200 ms a mais para ser processada nas duas viagens de ida e volta a uma entidade remota para adquirir e liquidar as mensagens, em comparação com uma entidade na mesma região.
Validação, redução e enriquecimento
As mensagens podem ser enviadas para uma fila ou tópico do Service Bus por clientes externos à sua própria solução.
Essas mensagens podem exigir a verificação da conformidade com um determinado esquema e que as mensagens não conformes sejam descartadas ou postas em letras mortas. Algumas mensagens podem ter de ser reduzidas em complexidade omitindo dados e outras podem ter de ser enriquecidas com a adição de dados com base em pesquisas de dados de referência. As operações podem ser executadas com funcionalidade personalizada na tarefa de replicação.
Replicação de fluxo para fila
Os Hubs de Eventos do Azure são uma solução ideal para lidar com volumes extremos de eventos de entrada. Mas nem os Hubs de Eventos nem mecanismos semelhantes como o Apache Kafka fornecem um modelo de consumidor concorrente gerenciado por serviços, onde vários consumidores podem lidar com mensagens da mesma fonte simultaneamente sem correr o risco de processamento duplicado e, finalmente, liquidar essas mensagens depois de processadas.
Um fluxo para replicação de fila transfere o conteúdo de uma única partição do Hub de Eventos ou o conteúdo de um Hub de Eventos completo para uma fila do Service Bus, a partir da qual as mensagens podem ser processadas com segurança, transação e com consumidores concorrentes. Essa replicação também permite o uso de todos os outros recursos do Service Bus para essas mensagens, incluindo roteamento com tópicos e desmultiplexação baseada em sessão.
Consolidação e normalização
As soluções globais são muitas vezes compostas por pegadas regionais que são amplamente independentes, incluindo ter suas próprias capacidades de processamento, mas as perspetivas suprarregionais e globais exigirão a integração de dados e, portanto, uma consolidação central dos mesmos dados de mensagem que são avaliados nas respetivas pegadas regionais para a perspetiva local.
A normalização é um sabor do cenário de consolidação, em que duas ou mais sequências de mensagens de entrada carregam o mesmo tipo de informação, mas com estruturas diferentes ou codificações diferentes, e as mensagens devem ser transcodificadas ou transformadas antes de poderem ser consumidas.
A normalização também pode incluir trabalho criptográfico, como descriptografar cargas criptografadas de ponta a ponta e criptografá-las novamente com chaves e algoritmos diferentes para o público consumidor a jusante.
Divisão e roteamento
Os tópicos do Barramento de Serviço e suas regras de assinatura geralmente são usados para filtrar um fluxo de mensagens para um público específico, e esse público obteve o conjunto filtrado de uma assinatura.
Em um sistema global em que o público dessas mensagens é distribuído globalmente ou pertence a aplicativos diferentes, a replicação pode ser usada para transferir mensagens de tal assinatura para uma fila ou tópico em um namespace diferente de onde elas são consumidas.
Aplicativos de replicação no Azure Functions
A implementação dos padrões acima requer um ambiente de execução escalável e confiável para as tarefas de replicação que você deseja configurar e executar. No Azure, o ambiente de tempo de execução mais adequado para tarefas sem estado é o Azure Functions.
O Azure Functions pode ser executado sob uma identidade gerenciada do Azure, de modo que as tarefas de replicação possam se integrar às regras de controle de acesso baseadas em função dos serviços de origem e de destino sem que você precise gerenciar segredos ao longo do caminho de replicação. Para origens e destinos de replicação que exigem credenciais explícitas, o Azure Functions pode manter os valores de configuração dessas credenciais em armazenamento com acesso controlado dentro do Cofre de Chaves do Azure.
Além disso, o Azure Functions permite que as tarefas de replicação se integrem diretamente com as redes virtuais do Azure e os pontos de extremidade de serviço para todos os serviços de mensagens do Azure e é prontamente integrado ao Azure Monitor.
Mais importante ainda, o Azure Functions tem gatilhos pré-criados e escalonáveis e associações de saída para Hubs de Eventos do Azure, Hub IoT do Azure, Barramento de Serviço do Azure, Grade de Eventos do Azure e Armazenamento de Filas do Azure, extensões personalizadas para RabbitMQe Apache Kafka. A maioria dos gatilhos se adaptará dinamicamente às necessidades de taxa de transferência, dimensionando o número de instâncias executadas simultaneamente para cima e para baixo com base em métricas documentadas.
Com o plano de consumo do Azure Functions, os gatilhos pré-criados podem até mesmo ser reduzidos a zero enquanto nenhuma mensagem estiver disponível para replicação, o que significa que você não incorre em custos para manter a configuração pronta para ser dimensionada. A principal desvantagem de usar o plano de consumo é que a latência para tarefas de replicação "acordando" desse estado é significativamente maior do que com os planos de hospedagem em que a infraestrutura é mantida em execução.
Em contraste com tudo isso, os mecanismos de replicação mais comuns para mensagens e eventos, como o MirrorMaker do Apache Kafka, exigem que você forneça um ambiente de hospedagem e dimensione o mecanismo de replicação por conta própria. Isso inclui configurar e integrar os recursos de segurança e rede e facilitar o fluxo de dados de monitoramento, e então você ainda não tem a oportunidade de injetar tarefas de replicação personalizadas no fluxo.
Tarefas de replicação com os Aplicativos Lógicos do Azure
Uma alternativa sem codificação para fazer replicação usando funções seria usar aplicativos lógicos em vez disso. Os Aplicativos Lógicos têm tarefas de replicação predefinidas para o Service Bus. Eles podem ajudar a configurar a replicação entre instâncias diferentes e podem ser ajustados para personalização adicional.
Passos Seguintes
Neste artigo, exploramos uma variedade de padrões de federação e explicamos a função do Azure Functions como o tempo de execução da replicação de eventos e mensagens no Azure.
Em seguida, talvez você queira ler como configurar um aplicativo replicador com o Azure Functions e, em seguida, como replicar fluxos de eventos entre Hubs de Eventos e vários outros sistemas de eventos e mensagens: