Compartilhar via


Processamento de eventos confiáveis com o Azure Functions e hubs de eventos

Saiba como criar soluções robustas e confiáveis sem servidor usando o Azure Functions com gatilhos dos Hubs de Eventos do Azure. Este artigo aborda as práticas recomendadas para pontos de verificação, tratamento de erros e implementação de padrões de disjuntor para garantir que nenhum evento seja perdido e que seus aplicativos controlados por eventos permaneçam estáveis e resilientes.

Desafios de fluxos de eventos em sistemas distribuídos

Considere um sistema que envia eventos a uma taxa constante de 100 eventos por segundo. Nesse ritmo, em poucos minutos várias instâncias paralelas podem consumir os 100 eventos de entrada a cada segundo.

No entanto, considere esses desafios para consumir um fluxo de eventos:

  • Um editor de eventos envia um evento corrompido.
  • Seu código de função encontra uma exceção sem tratamento.
  • Um sistema downstream fica offline e bloqueia o processamento de eventos.

Ao contrário de um disparador de Armazenamento de Filas do Azure, que bloqueia mensagens durante o processamento, os Hubs de Eventos do Azure leem, por partição, de um único ponto no fluxo. Esse comportamento de leitura, que é mais parecido com um player de vídeo, fornece os benefícios desejados de alta taxa de transferência, vários grupos de consumidores e capacidade de reprodução. Os eventos são lidos, para frente ou para trás, de um ponto de verificação, mas você deve mover o ponteiro para processar novos eventos. Para obter mais informações, consulte Checkpoint na documentação dos Hubs de Eventos.

Quando ocorrem erros em um fluxo e você opta por não avançar o ponteiro, o processamento de eventos adicionais é bloqueado. Em outras palavras, se você parar o ponteiro para lidar com um problema de processamento de um único evento, os eventos não processados começarão a se acumular.

As funções evitam deadlocks sempre avançando o ponteiro da stream, independentemente de êxito ou falha. Como o ponteiro continua avançando, suas funções precisam lidar com falhas adequadamente.

Como o ativador dos Hubs de Eventos consome eventos

O Azure Functions consome eventos de um hub de eventos percorrendo as seguintes etapas:

  1. Um ponteiro é criado e mantido no Armazenamento do Azure para cada partição do hub de eventos.
  2. Novos eventos são recebidos em um lote (por padrão) e o host tenta disparar a função que fornece um lote de eventos para processamento.
  3. Quando a função conclui a execução, com ou sem exceções, o ponteiro é avançado e um ponto de verificação é salvo na conta de armazenamento padrão do host.
  4. Se as condições impedirem a conclusão da execução da função, o host não poderá avançar o ponteiro. Quando o ponteiro não pode avançar, as execuções subsequentes reprocessam os mesmos eventos.

Esse comportamento revela alguns pontos importantes:

  • Exceções não tratadas podem levar à perda de eventos:

    Execuções de função que geram uma exceção continuam a avançar o ponteiro. Definir uma política de repetição ou outra lógica de repetição atrasa o avanço do ponteiro até que toda a repetição seja concluída.

  • As funções garantem uma entrega pelo menos uma vez :

    Seu código e sistemas dependentes podem precisar considerar o fato de que o mesmo evento pode ser processado duas vezes. Para obter mais informações, consulte Projetando Azure Functions para entrada idêntica.

Tratamento de exceções

Embora todo o código de função deva incluir um bloco try/catch no nível mais alto do código, ter um catch bloco é ainda mais importante para funções que consomem eventos dos Hubs de Eventos. Dessa forma, quando uma exceção é gerada, o bloco captura trata o erro antes de o ponteiro progredir.

Mecanismos e políticas de nova tentativa

Como muitas exceções na nuvem são transitórias, a primeira etapa no tratamento de erros é sempre repetir a operação. Você pode aplicar políticas de repetição internas ou definir sua própria lógica de repetição.

Políticas de repetição

O Azure Functions fornece políticas de repetição embutidas para Hubs de Eventos. Ao usar políticas de repetição, basta gerar uma nova exceção e o host tentar processar o evento novamente com base na política definida. Esse comportamento de repetição requer a versão 5.x ou posterior da extensão dos Hubs de Eventos. Para mais informações, consulte Políticas de repetição.

Lógica de repetição personalizada

Você também pode definir sua própria lógica de repetição na própria função. Por exemplo, você pode implementar uma política que segue um fluxo de trabalho ilustrado pelas seguintes regras:

  • Tente processar um evento três vezes (potencialmente com um atraso entre novas tentativas).
  • Se o resultado eventual de todas as tentativas for uma falha, adicione um evento a uma fila para que o processamento possa continuar no stream.
  • Eventos corrompidos ou não processados são tratados posteriormente.

Observação

Polly é um exemplo de uma biblioteca de resiliência e tratamento de falhas transitórias para aplicativos C#.

Erros de não-exceção

Alguns problemas podem ocorrer sem que uma exceção seja gerada. Por exemplo, considere um caso em que uma solicitação atinge o tempo limite ou a instância que executa a função falha. Se uma função falha em concluir sem gerar uma exceção, o ponteiro de deslocamento nunca é avançado. Se o ponteiro não avançar, qualquer instância executada após uma execução com falha continuará a ler os mesmos eventos. Essa situação proporciona uma garantia de pelo menos uma vez.

A garantia de que cada evento é processado pelo menos uma vez implica que alguns eventos podem ser processados mais de uma vez. Seus aplicativos de funções precisam estar cientes dessa possibilidade e devem ser criados em torno dos princípios de idempotência.

Gerenciamento de estados de falha

Seu aplicativo pode ser capaz de lidar aceitamente com alguns erros no processamento de eventos. No entanto, você também deve estar preparado para lidar com o estado de falha persistente, que pode ocorrer como resultado de falhas no processamento downstream. Nesse estado de falha, como um repositório de dados a jusante ficando offline, sua função deve parar de disparar em eventos até que o sistema atinja um estado saudável.

Padrão de disjuntor

Ao implementar o padrão de projeto Circuit Breaker, seu aplicativo consegue efetivamente pausar o processamento de eventos e retomá-lo mais tarde, assim que os problemas forem resolvidos.

Há dois componentes necessários para implementar um disjuntor em um processo de fluxo de eventos:

  • Estado compartilhado em todas as instâncias para acompanhar e monitorar a integridade do circuito.
  • Um processo primário que pode gerenciar o estado do circuito, como open ou closed.

Os detalhes da implementação podem variar, mas para compartilhar o estado entre instâncias, você precisa de um mecanismo de armazenamento. Você pode armazenar o estado no Armazenamento do Azure, em um cache Redis ou em qualquer outro serviço persistente que possa ser acessado pelas instâncias do aplicativo de funções.

As Durable Functions e os Aplicativos Lógicos do Azure fornecem infraestrutura para gerenciar fluxos de trabalho e estados de circuito. Este artigo descreve o uso de Aplicativos Lógicos para pausar e reiniciar execuções de função, fornecendo o controle necessário para implementar o padrão de disjuntor.

Definir um limite de falha entre instâncias

O estado externo compartilhado persistente é necessário para monitorar a integridade do circuito quando várias instâncias estão processando eventos simultaneamente. Em seguida, você pode monitorar esse estado persistente com base em regras que indicam um estado de falha, como:

Quando houver mais de 100 falhas de evento em um período de 30 segundos em todas as instâncias, abra o circuito para evitar novos disparos de eventos.

Os detalhes de implementação dessa lógica de monitoramento variam dependendo das necessidades específicas do aplicativo, mas, em geral, você deve criar um sistema que:

  1. Registra falhas no armazenamento persistente.
  2. Inspecione a contagem contínua quando novas falhas são registradas para determinar se o limite de falhas para o evento é atingido.
  3. Quando esse limite for atingido, emita um evento informando ao sistema para interromper o circuito.

Gerenciando o estado do circuito com os Aplicativos Lógicos do Azure

Os Aplicativos Lógicos do Azure vêm com conectores internos para diferentes serviços, recursos e orquestrações com estado, e é uma opção natural gerenciar o estado do circuito. Depois de detectar quando um circuito deve ser interrompido, você pode criar um aplicativo lógico para implementar esse fluxo de trabalho:

  1. Acione um fluxo de trabalho do Event Grid que interrompa o processamento da função.
  2. Envie um email de notificação que inclua uma opção para reiniciar o fluxo de trabalho.

Para saber como desabilitar e reabilitar funções específicas usando configurações de aplicativo, confira Como desabilitar funções no Azure Functions.

O destinatário de email pode investigar a integridade do circuito e, quando apropriado, reiniciar o circuito por meio de um link no email de notificação. À medida que o fluxo de trabalho reinicia a função, os eventos são processados do último ponto de verificação do hub de eventos.

Quando você usa essa abordagem, nenhum evento é perdido, os eventos são processados em ordem e você pode interromper o circuito o tempo necessário.

Estratégias de migração para gatilhos da Grade de Eventos

Ao migrar um aplicativo de funções existente entre regiões ou entre alguns planos, você deve recriar o aplicativo durante o processo de migração. Nesse caso, durante o processo de migração, você pode ter dois aplicativos que podem consumir do mesmo fluxo de eventos e gravar no mesmo destino de saída.

Você deve considerar o uso de grupos de consumidores para evitar perda ou duplicação de dados de eventos durante o processo de migração:

  1. Crie um novo grupo de consumidores para o novo aplicativo de destino.

  2. Configure o gatilho no novo aplicativo para usar esse novo grupo de consumidores.

    Isso permite que ambos os aplicativos processem eventos independentemente durante a validação.

  3. Valide se o novo aplicativo está processando eventos corretamente.

  4. Interrompa o aplicativo original ou remova sua assinatura/grupo de consumidores.