Padrões de tarefas de replicação de eventos
A visão geral da federação e a visão geral das funções do replicador explicam a lógica e os elementos básicos das tarefas de replicação, e é recomendável que você se familiarize com eles antes de continuar com este artigo.
Neste artigo, detalhamos as diretrizes de implementação para vários dos padrões destacados na seção de visão geral.
Replicação
O padrão de replicação copia eventos de um Hub de Eventos para o próximo ou de um Hub de Eventos para algum outro destino, como uma fila do Service Bus. Os eventos são encaminhados sem fazer modificações na carga útil do evento.
A implementação desse padrão é coberta pelos exemplos de replicação de eventos entre Hubs de Eventos e Replicação de eventos entre Hubs de Eventos e Service Bus e pelo tutorial Usar Apache Kafka MirrorMaker com Hubs de Eventos para o caso específico de replicação de dados de um broker Apache Kafka em Hubs de Eventos.
Córregos e preservação da ordem
A replicação, seja por meio do Azure Functions ou do Azure Stream Analytics, não visa garantir a criação de clones 1:1 exatos de um Hub de Eventos de origem em um Hub de Eventos de destino, mas se concentra em preservar a ordem relativa dos eventos onde o aplicativo o exige. O aplicativo comunica isso agrupando eventos relacionados com a mesma chave de partição e os Hubs de Eventos organizam mensagens com a mesma chave de partição sequencialmente na mesma partição.
Importante
As informações de "deslocamento" são exclusivas para cada Hub de Eventos e as compensações para os mesmos eventos serão diferentes entre as instâncias do Hub de Eventos. Para localizar uma posição em um fluxo de eventos copiado, use deslocamentos baseados em tempo e consulte os metadados atribuídos ao serviço propagado.
As compensações baseadas no tempo iniciam o recetor num determinado momento:
- EventPosition.FromStart() - Leia todos os dados retidos novamente.
- EventPosition.FromEnd() - Leia todos os novos dados do momento da conexão.
- EventPosition.FromEnqueuedTime(dateTime) - Todos os dados a partir de uma determinada data e hora.
No EventProcessor, você define a posição por meio do InitialOffsetProvider no EventProcessorOptions. Com as outras APIs do recetor, a posição é passada através do construtor.
Os auxiliares de função de replicação pré-criados fornecidos como exemplos usados na orientação baseada no Azure Functions garantem que fluxos de eventos com a mesma chave de partição recuperada de uma partição de origem sejam enviados para o Hub de Eventos de destino como um lote no fluxo original e com a mesma chave de partição.
Se a contagem de partições do Hub de Eventos de origem e de destino for idêntica, todos os fluxos no destino serão mapeados para as mesmas partições que fizeram na origem. Se a contagem de partições for diferente, o que importa em alguns dos padrões adicionais descritos a seguir, o mapeamento será diferente, mas os fluxos são sempre mantidos juntos e em ordem.
A ordem relativa de eventos pertencentes a fluxos diferentes ou de eventos independentes sem uma chave de partição em uma partição de destino pode sempre diferir da partição de origem.
Metadados atribuídos ao serviço
Os metadados atribuídos ao serviço de um evento obtido do Hub de Eventos de origem, o tempo de fila original, o número de sequência e o deslocamento, são substituídos por novos valores atribuídos ao serviço no Hub de Eventos de destino, mas com as funções auxiliares, tarefas de replicação fornecidas em nossos exemplos, os valores originais são preservados nas propriedades do usuário: repl-enqueue-time
(ISO8601 string), repl-sequence
, repl-offset
.
Essas propriedades são do tipo string e contêm o valor stringified das respetivas propriedades originais. Se o evento for encaminhado 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.
Ativação pós-falha
Se você estiver usando a replicação para fins de recuperação de desastres, para proteção contra eventos de disponibilidade regional no serviço Hubs de Eventos ou contra interrupções de rede, qualquer cenário de falha exigirá a execução de um failover de um Hub de Eventos para o próximo, dizendo aos produtores e/ou consumidores para usar 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 Hubs de Eventos e Grupos de Consumidores têm nomes idênticos e que as regras de assinatura de acesso compartilhado e/ou regras de controle de acesso baseadas em função são configuradas da mesma maneira. Você pode criar (e atualizar) um namespace secundário seguindo as orientações para mover namespaces e omitir a etapa de limpeza.
Para forçar produtores e consumidores a mudar, você precisa disponibilizar as informações sobre qual namespace usar para pesquisa em um local fácil de acessar e atualizar. Se os produtores ou consumidores se depararem com erros frequentes ou persistentes, devem consultar esse local e ajustar a sua configuração. Existem várias maneiras de compartilhar essa configuração, mas destacamos duas a seguir: DNS e compartilhamentos de arquivos.
Configuração de failover baseada em DNS
Uma abordagem candidata é manter as informações nos registros SRV DNS em um DNS que você controla e apontar para os respetivos pontos de extremidade do Hub de Eventos.
Importante
Lembre-se de que os Hubs de Eventos não permitem que seus pontos de extremidade sejam diretamente aliados com registros CNAME, o que significa que você usará 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ê é o proprietário do domínio example.com
e, para seu aplicativo, de uma zona test.example.com
. Para dois Hubs de Eventos alternativos, você criará mais duas zonas aninhadas e um registro SRV em cada uma.
Os registros SRV são, seguindo convenção comum, prefixados e _azure_eventhubs._amqp
contêm dois registros de ponto final: um para AMQP-over-TLS na porta 5671 e outro para AMQP-over-WebSockets na porta 443, ambos apontando para o ponto de extremidade de Hubs de Eventos do namespace correspondente à zona.
Zona | Registo SRV |
---|---|
eh1.test.example.com |
_azure_servicebus._amqp.eh1.test.example.com 1 1 5671 eh1-test-example-com.servicebus.windows.net 2 2 443 eh1-test-example-com.servicebus.windows.net |
eh2.test.example.com |
_azure_servicebus._amqp.eh2.test.example.com 1 1 5671 eh2-test-example-com.servicebus.windows.net 2 2 443 eh2-test-example-com.servicebus.windows.net |
Na zona do seu aplicativo, você criará uma entrada CNAME que aponta para a zona subordinada correspondente ao seu Hub de Eventos principal:
Registo CNAME | Alias |
---|---|
eventhub.test.example.com |
eh1.test.example.com |
Usando um cliente DNS que permite consultar registros CNAME e SRV explicitamente (os clientes internos de Java e .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 de pesquisa é:
static string GetEventHubName(string aliasName)
{
const string SrvRecordPrefix = "_azure_eventhub._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 atualmente aliased com o CNAME, como mostrado acima.
Executar um failover requer editar o registro CNAME e apontá-lo 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, resilientes contra interrupções de uma única região.
Este procedimento é semelhante ao funcionamento do Geo-DR dos Hubs de Eventos, mas totalmente sob seu próprio controle e também funciona com cenários ativos/ativos.
Configuração de failover baseada em compartilhamento de arquivos
A alternativa mais simples ao uso do 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 servir o arquivo a partir de uma infraestrutura robusta contra interrupções e que ainda permita atualizações.
Se você já executa uma infraestrutura de site altamente disponível com disponibilidade global e replicação de conteúdo, adicione esse arquivo lá e publique novamente o arquivo se uma opção for necessária.
Atenção
Você só deve publicar o nome do ponto de extremidade dessa maneira, não uma cadeia de conexão completa, incluindo segredos.
Considerações adicionais para o fracasso dos consumidores
Para os consumidores do Hub de Eventos, outras considerações para a estratégia de failover dependem das necessidades do processador de eventos.
Se houver um desastre que exija a reconstrução de um sistema, incluindo bancos de dados, a partir de dados de backup, e os bancos de dados forem alimentados diretamente ou por meio de processamento intermediário dos eventos realizados no Hub de Eventos, você restaurará o backup e, em seguida, desejará começar a reproduzir eventos no sistema a partir do momento em que o backup do banco de dados foi criado e não a partir do momento em que o sistema original foi destruído.
Se uma falha afetar apenas uma fatia de um sistema ou apenas um único Hub de Eventos, que se tornou inacessível, você provavelmente desejará continuar processando eventos aproximadamente da mesma posição em que o processamento foi interrompido.
Para realizar qualquer cenário e usar o processador de eventos do seu respetivo SDK do Azure, você criará um novo armazenamento de ponto de verificação e fornecerá uma posição de partição inicial, com base no carimbo de data/hora do qual deseja retomar o processamento.
Se você ainda tiver acesso ao armazenamento de pontos de verificação do Hub de Eventos do qual está se afastando, os metadados propagados discutidos acima ajudarão você a ignorar eventos que já foram manipulados e retomar exatamente de onde você parou pela última vez.
Unir
O padrão de mesclagem tem uma ou mais tarefas de replicação apontando para um destino, possivelmente simultaneamente com produtores regulares também enviando eventos para o mesmo destino.
As variações destes padrões são:
- Duas ou mais funções de replicação simultaneamente adquirindo eventos de fontes separadas e enviando-os para o mesmo destino.
- Mais uma função de replicação adquirindo eventos de uma origem, enquanto o destino também é usado diretamente pelos produtores.
- O padrão anterior, mas espelhado entre dois ou mais Hubs de Eventos, resultando nesses Hubs de Eventos contendo os mesmos fluxos, não importa onde os eventos sejam produzidos.
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 eventos já replicados de serem replicados novamente. A técnica é demonstrada e explicada no exemplo EventHubToEventHubMerge .
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 de tais modificações são:
- Transcodificação - Se o conteúdo do evento (também referido como "corpo" ou "carga útil") chegar do código-fonte codificado usando o formato Apache Avro ou algum formato de serialização proprietário, mas a expectativa do sistema proprietário do destino é que o conteúdo seja codificado JSON, uma tarefa de replicação de transcodificação primeiro desserializará a carga do Apache Avro em um gráfico de objeto na memória e, em seguida, serializará esse gráfico no JSON para o evento que está sendo encaminhado. A transcodificação também inclui tarefas de compressão e descompressão de conteúdo.
- Transformação - Eventos que contêm dados estruturados podem exigir a reformulação desses dados para facilitar o consumo pelos consumidores a jusante. Isso pode envolver trabalhos como o nivelamento de estruturas aninhadas, a remoção de elementos de dados estranhos ou a reformulação da carga útil para se ajustar exatamente a um determinado esquema.
- Processamento em lote - Os eventos podem ser recebidos em lotes (vários eventos em uma única transferência) de uma fonte, mas precisam ser encaminhados individualmente para um destino ou vice-versa. Uma tarefa pode, portanto, encaminhar vários eventos com base em uma única transferência de evento de entrada ou agregar um conjunto de eventos que são transferidos juntos.
- Validação - Os dados de eventos de fontes externas geralmente precisam ser verificados para verificar se estão em conformidade com um conjunto de regras antes de serem encaminhados. As regras podem ser expressas usando esquemas ou código. Os eventos que não estiverem em conformidade podem ser descartados, com o problema anotado nos logs, ou podem ser encaminhados para um destino de destino especial para lidar com eles ainda mais.
- Enriquecimento - Os dados de eventos provenientes de algumas fontes podem exigir enriquecimento com contexto adicional para que possam ser utilizados em sistemas de destino. Isso pode envolver a pesquisa de dados de referência e a incorporação desses dados com o evento ou a adição de informações sobre a fonte conhecida para a tarefa de replicação, mas não contida nos eventos.
- Filtragem - Alguns eventos que chegam de uma fonte podem ter que ser retidos do destino com base em alguma regra. Um filtro testa o evento em relação a uma regra e descarta-o se o evento não corresponder à regra. Filtrar eventos duplicados observando certos critérios e descartando eventos subsequentes com os mesmos valores é uma forma de filtragem.
- Criptografia - Uma tarefa de replicação pode ter que descriptografar o conteúdo que chega da fonte e/ou criptografar o conteúdo encaminhado para um alvo e/ou pode ter que verificar a integridade do conteúdo e dos metadados relativos a uma assinatura transportada no evento, ou anexar tal assinatura.
- Atestado - Uma tarefa de replicação pode anexar metadados, potencialmente protegidos por uma assinatura digital, a um evento que ateste que o evento foi recebido por meio de um canal específico ou em um momento específico.
- Encadeamento - Uma tarefa de replicação pode aplicar assinaturas a fluxos de eventos de modo que a integridade do fluxo seja protegida e eventos ausentes possam ser detetados.
Os padrões de transformação, processamento em lote e enriquecimento geralmente são melhor implementados com trabalhos do Azure Stream Analytics .
Todos esses padrões podem ser implementados usando o Azure Functions, usando o Gatilho de Hubs de Eventos para adquirir eventos e a vinculação de saída do Hub de Eventos para entregá-los.
Encaminhamento
O padrão de roteamento se baseia 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("EH2EH")]
public static async Task Run(
[EventHubTrigger("source", Connection = "EventHubConnectionAppSetting")] EventData[] events,
[EventHub("dest1", Connection = "EventHubConnectionAppSetting")] EventHubClient output1,
[EventHub("dest2", Connection = "EventHubConnectionAppSetting")] EventHubClient output2,
ILogger log)
{
foreach (EventData eventData in events)
{
// send to output1 and/or output2 based on criteria
EventHubReplicationTasks.ConditionalForwardToEventHub(input, output1, log, (eventData) => {
return ( inputEvent.SystemProperties.SequenceNumber%2==0 ) ? inputEvent : null;
});
EventHubReplicationTasks.ConditionalForwardToEventHub(input, output2, log, (eventData) => {
return ( inputEvent.SystemProperties.SequenceNumber%2!=0 ) ? inputEvent : null;
});
}
}
A função de roteamento considerará os metadados da mensagem e/ou a carga útil da mensagem e, em seguida, escolherá um dos destinos disponíveis para enviar.
No Azure Stream Analytics, você pode obter o mesmo com a definição de várias saídas e, em seguida, a execução de uma consulta por saída.
select * into dest1Output from inputSource where Info = 1
select * into dest2Output from inputSource where Info = 2
Projeção de log
O padrão de projeção de log nivela o fluxo de eventos em um banco de dados indexado, com eventos se tornando registros no banco de dados. Normalmente, os eventos são adicionados à mesma coleção ou tabela, e a chave de partição do Hub de Eventos torna-se parte da chave primária procurando tornar o registro exclusivo.
A projeção de log pode produzir um historiador de séries temporais dos dados do evento ou uma exibição compactada, na qual apenas o evento mais recente é retido para cada chave de partição. A forma do banco de dados de destino depende, em última análise, de você e das necessidades do seu aplicativo. Esse padrão também é conhecido como "fornecimento de eventos".
Gorjeta
Você pode criar facilmente projeções de log no Banco de Dados SQL do Azure e no Azure Cosmos DB no Azure Stream Analytics e deve preferir essa opção.
O Azure Function a seguir projeta o conteúdo de um Hub de Eventos compactado em uma coleção do Azure Cosmos DB.
[FunctionName("Eh1ToCosmosDb1Json")]
[ExponentialBackoffRetry(-1, "00:00:05", "00:05:00")]
public static async Task Eh1ToCosmosDb1Json(
[EventHubTrigger("eh1", ConsumerGroup = "Eh1ToCosmosDb1", Connection = "Eh1ToCosmosDb1-source-connection")] EventData[] input,
[CosmosDB(databaseName: "SampleDb", collectionName: "foo", ConnectionStringSetting = "CosmosDBConnection")] IAsyncCollector<object> output,
ILogger log)
{
foreach (var ev in input)
{
if (!string.IsNullOrEmpty(ev.SystemProperties.PartitionKey))
{
var record = new
{
id = ev.SystemProperties.PartitionKey,
data = JsonDocument.Parse(ev.Body),
properties = ev.Properties
};
await output.AddAsync(record);
}
}
}