Partilhar via


Processamento confiável de eventos com o Azure Functions e Hubs de Eventos

Saiba como criar soluções sem servidor robustas e confiáveis usando o Azure Functions com gatilhos de 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 orientados a eventos permaneçam estáveis e resilientes.

Desafios dos 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 recebidos a cada segundo.

No entanto, considere estes 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 não tratada.
  • Um sistema a jusante fica offline e bloqueia o processamento de eventos.

Ao contrário de um gatilho de armazenamento de Fila do Azure, que bloqueia mensagens durante o processamento, os Hubs de Eventos do Azure leem, por partição, a partir 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 alto rendimento, vários grupos de consumidores e capacidade de reprodução. Os eventos são lidos, para frente ou para trás, a partir de um ponto de verificação, mas você deve mover o ponteiro para processar novos eventos. Para obter mais informações, consulte Ponto de verificação 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 ao processar um único evento, os eventos não processados começarão a se acumular.

As funções evitam bloqueios ao avançar sempre o ponteiro do fluxo de dados, independentemente do sucesso ou falha. Como o ponteiro continua avançando, suas funções precisam lidar com falhas adequadamente.

Como o gatilho dos Hubs de Eventos consome eventos

As Azure Functions consome eventos de um hub de eventos do Azure seguindo as etapas descritas a seguir:

  1. Um ponteiro é criado e persistido 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 acionar a função fornecendo um lote de eventos para processamento.
  3. Quando a função conclui a execução, com ou sem exceções, o ponteiro avança e um ponto de verificação é salvo na conta de armazenamento do anfitrião padrão.
  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.

Este comportamento revela alguns pontos importantes:

  • Exceções não tratadas podem fazer com que você perca eventos:

    As 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.

  • Funções garantem a entrega pelo menos uma vez:

    Seu código e sistemas dependentes podem precisar levar em conta o fato de que o mesmo evento pode ser processado duas vezes. Para obter mais informações, consulte Projetando o 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 de código, é ainda mais importante ter um bloco catch para funções que consomem eventos de Hubs de Eventos. Dessa forma, quando uma exceção é gerada, o bloco catch trata o erro antes que o ponteiro progrida.

Mecanismos e políticas de reenquadramento

Como muitas exceções na nuvem são transitórias, o primeiro passo 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 Reintentar

Functions fornece políticas de repetição integradas 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 Event Hubs. Para obter mais informações, consulte Repetir políticas.

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 siga um fluxo de trabalho ilustrado pelas seguintes regras:

  • Tente processar um evento três vezes (potencialmente com um atraso entre as tentativas).
  • Se o resultado final de todas as novas tentativas for uma falha, adicione um evento a uma fila para que o processamento possa continuar no fluxo.
  • 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 levantada. Por exemplo, considere um caso em que uma solicitação expira ou a instância que executa a função falha. Quando uma função não é concluída sem 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. Esta situação oferece uma garantia 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ção precisam estar cientes dessa possibilidade e devem ser construídos em torno dos princípios da idempotência.

Gerir estados de falha

Seu aplicativo pode ser capaz de lidar de forma aceitável 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 armazenamento de dados downstream estar offline, a sua função deve parar de ser acionada por eventos até que o sistema atinja um estado saudável.

Padrão do disjuntor

Quando implementa o padrão circuit breaker, a sua aplicação pode efetivamente pausar o processamento de eventos e retomá-lo após a resolução dos problemas.

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

  • Estado partilhado em todas as instâncias para rastrear e monitorizar a saúde do circuito.
  • Um processo primário que pode gerir o estado do circuito, como open ou closed.

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

As Funções Duráveis 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ções, 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 eventos em um período de 30 segundos em todas as instâncias, quebre o circuito para parar de acionar novos eventos.

Os detalhes de implementação para essa lógica de monitoramento variam dependendo das necessidades específicas do seu 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 forem registradas para determinar se o limite de falha de evento foi atingido.
  3. Quando esse limite for atingido, emita um evento informando o sistema para interromper o circuito.

Gerir o estado do circuito com as Aplicações Lógicas do Azure

Os Azure Logic Apps vêm com conectores internos para diferentes serviços, funcionalidades e orquestrações com estado, sendo uma escolha natural para gerir o estado do circuito. Depois de detetar quando um circuito deve quebrar, você pode criar um aplicativo lógico para implementar este fluxo de trabalho:

  1. Acione um fluxo de trabalho de Grade de Eventos que interrompa o processamento da função.
  2. Envie um e-mail de notificação que inclua uma opção para reiniciar o fluxo de trabalho.

Para saber como desabilitar e reativar funções específicas usando as configurações do aplicativo, consulte Como desabilitar funções no Azure Functions.

O destinatário do e-mail pode investigar a saúde do circuito e, quando apropriado, reiniciar o circuito através de um link no e-mail de notificação. À medida que o fluxo de trabalho reinicia a função, os eventos são processados a partir do último ponto de verificação do hub de eventos.

Quando se utiliza esta abordagem, isto garante que nenhum evento é perdido, os eventos são processados em ordem, e pode interromper a ligação pelo tempo necessário.

Estratégias de migração para gatilhos do Event Grid

Ao migrar um aplicativo de função 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 de forma independente durante a validação.

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

  4. Pare o aplicativo original ou remova seu grupo de assinatura/consumidor.