Editar

Partilhar via


Diretrizes de desempenho e dimensionamento para Hubs de Eventos e Azure Functions

Azure Event Hubs
Azure Functions

Este artigo fornece orientação para otimizar a escalabilidade e o desempenho quando você usa os Hubs de Eventos do Azure e o Azure Functions juntos em seus aplicativos.

Agrupamento de funções

Normalmente, uma função encapsula uma unidade de trabalho em um fluxo de processamento de eventos. Por exemplo, uma função pode transformar um evento numa nova estrutura de dados ou enriquecer dados para aplicações a jusante.

Em Funções, um aplicativo de função fornece o contexto de execução para funções. Os comportamentos do aplicativo de função se aplicam a todas as funções que o aplicativo de função hospeda. As funções em um aplicativo de função são implantadas juntas e dimensionadas juntas. Todas as funções em um aplicativo de função devem ser do mesmo idioma.

A forma como agrupa funções em aplicações de função pode afetar o desempenho e as capacidades de dimensionamento das suas aplicações funcionais. Você pode agrupar de acordo com os direitos de acesso, a implantação e os padrões de uso que invocam seu código.

Para obter orientação sobre as práticas recomendadas do Functions para agrupamento e outros aspetos, consulte Práticas recomendadas para funções confiáveis do Azure e Melhorar o desempenho e a confiabilidade do Azure Functions.

A lista a seguir é uma orientação para agrupar funções. As orientações consideram os aspetos relacionados com a armazenagem e o grupo de consumidores:

  • Hospedar uma única função em um aplicativo de função: se os Hubs de Eventos acionarem uma função, você poderá, para reduzir a contenção entre essa função e outras funções, isolar a função em seu próprio aplicativo de função. O isolamento é especialmente importante se as outras funções forem intensivas em CPU ou memória. Essa técnica ajuda porque cada função tem sua própria pegada de memória e padrões de uso que podem afetar diretamente o dimensionamento do aplicativo de função que a hospeda.

  • Dê a cada aplicativo de função sua própria conta de armazenamento: evite compartilhar contas de armazenamento entre aplicativos de função. Além disso, se um aplicativo de função usar uma conta de armazenamento, não use essa conta para outras operações ou necessidades de armazenamento. Pode ser especialmente importante evitar o compartilhamento de contas de armazenamento para funções que os Hubs de Eventos acionam, porque essas funções podem ter um alto volume de transações de armazenamento devido ao ponto de verificação.

  • Crie um grupo de consumidores dedicado para cada aplicativo de função: um grupo de consumidores é uma exibição de um hub de eventos. Diferentes grupos de consumidores têm visões diferentes, o que significa que os estados, posições e compensações podem diferir. Os grupos de consumidores possibilitam que vários aplicativos de consumo tenham suas próprias visualizações do fluxo de eventos e leiam o fluxo de forma independente, em seu próprio ritmo e com seus próprios deslocamentos. Para obter mais informações sobre grupos de consumidores, consulte Recursos e terminologia nos Hubs de Eventos do Azure.

    Um grupo de consumidores tem um ou mais aplicativos de consumidor associados a ele, e um aplicativo de consumidor pode usar um ou mais grupos de consumidores. Em uma solução de processamento de fluxo, cada aplicativo de consumidor equivale a um grupo de consumidores. Um aplicativo de função é um excelente exemplo de um aplicativo de consumidor. O diagrama a seguir fornece um exemplo de dois aplicativos de função que leem de um hub de eventos, onde cada aplicativo tem seu próprio grupo de consumidores dedicado:

    Grupos de consumidores dedicados para cada aplicativo de função

    Não compartilhe grupos de consumidores entre aplicativos funcionais e outros aplicativos de consumo. Cada aplicativo de função deve ser um aplicativo distinto com seu próprio grupo de consumidores atribuído para garantir a integridade do deslocamento para cada consumidor e simplificar as dependências em uma arquitetura de streaming de eventos. Essa configuração, juntamente com o fornecimento de cada função acionada pelo hub de eventos seu próprio aplicativo de função e conta de armazenamento, ajuda a definir a base para o desempenho e o dimensionamento ideais.

Planos de hospedagem de funções

Existem várias opções de hospedagem para aplicativos de função e é importante rever suas capacidades. Para obter informações sobre essas opções de hospedagem, consulte Opções de hospedagem do Azure Functions. Tome nota de como as opções são dimensionadas.

O plano de consumo é o padrão. Os aplicativos de função no Plano de consumo são dimensionados de forma independente e são mais eficazes quando evitam tarefas de longa execução.

Os planos Premium e Dedicado são frequentemente usados para hospedar vários aplicativos de função e funções que são mais intensivas em CPU e memória. Com o plano Dedicado, você executa suas funções em um plano do Serviço de Aplicativo do Azure com taxas regulares do plano do Serviço de Aplicativo. É importante notar que todos os aplicativos de função nesses planos compartilham os recursos alocados para o plano. Se as funções tiverem perfis de carga diferentes ou requisitos exclusivos, é melhor hospedá-las em planos diferentes, especialmente em aplicativos de processamento de fluxo.

Os Aplicativos de Contêiner do Azure fornecem suporte integrado para desenvolver, implantar e gerenciar aplicativos de função em contêineres no Azure Functions. Isso permite que você execute suas funções orientadas a eventos em um ambiente totalmente gerenciado baseado em Kubernetes com suporte integrado para monitoramento de código aberto, mTLS, Dapr e KEDA.

Dimensionamento de Hubs de Eventos

Quando você implanta um namespace de Hubs de Eventos, há várias configurações importantes que você precisa definir corretamente para garantir o desempenho máximo e o dimensionamento. Esta seção se concentra na camada Standard dos Hubs de Eventos e nos recursos exclusivos dessa camada que afetam o dimensionamento quando você também usa o Functions. Para obter mais informações sobre as camadas de Hubs de Eventos, consulte Camadas Básica vs. Standard vs. Premium vs. Dedicada.

Um namespace de Hubs de Eventos corresponde a um cluster Kafka. Para obter informações sobre como os Hubs de Eventos e o Kafka se relacionam entre si, consulte O que são Hubs de Eventos do Azure para Apache Kafka.

Noções básicas sobre unidades de taxa de transferência (TUs)

Na camada Padrão dos Hubs de Eventos, a taxa de transferência é classificada como a quantidade de dados que entram e são lidos do namespace por unidade de tempo. As TUs são unidades pré-compradas de capacidade de rendimento.

Os TUs são cobrados por hora.

Todos os hubs de eventos em um namespace compartilham as TUs. Para calcular corretamente as necessidades de capacidade, você deve considerar todos os aplicativos e serviços, tanto editores quanto consumidores. As funções afetam o número de bytes e eventos que são publicados e lidos em um hub de eventos.

A ênfase para determinar o número de UTs está no ponto de entrada. No entanto, o agregado relativo aos pedidos de consumo, incluindo a taxa a que esses eventos são processados, também deve ser incluído no cálculo.

Para obter mais informações sobre unidades de taxa de transferência de Hubs de Eventos, consulte Unidades de taxa de transferência.

Aumente a escala com a insuflação automática

A inflação automática pode ser habilitada em um namespace de Hubs de Eventos para acomodar situações em que a carga excede o número configurado de TUs. O uso da inflação automática evita a limitação do seu aplicativo e ajuda a garantir que o processamento, incluindo a ingestão de eventos, continue sem interrupções. Como a configuração de TU afeta os custos, o uso da inflação automática ajuda a resolver as preocupações sobre o excesso de provisionamento.

A auto-inflação é um recurso dos Hubs de Eventos que muitas vezes é confundido com o dimensionamento automático, especialmente no contexto de soluções sem servidor. No entanto, a auto-insuflação, ao contrário da escala automática, não diminui quando a capacidade adicional não é mais necessária.

Se o aplicativo precisar de capacidade que exceda o número máximo permitido de TUs, considere usar a camada Premium ou a camada Dedicada dos Hubs de Eventos.

Partições e funções simultâneas

Quando um hub de eventos é criado, o número de partições deve ser especificado. A contagem de partições permanece fixa e não pode ser alterada, exceto nos níveis Premium e Dedicado. Quando os Hubs de Eventos acionam aplicativos de funções, é possível que o número de instâncias simultâneas seja igual ao número de partições.

Nos planos de hospedagem Consumo e Premium, as instâncias do aplicativo de função são dimensionadas dinamicamente para atender ao número de partições, se necessário. O plano de hospedagem dedicada executa funções em um plano do Serviço de Aplicativo e requer que você configure manualmente suas instâncias ou configure um esquema de dimensionamento automático. Para obter mais informações, consulte Planos de hospedagem dedicados para o Azure Functions.

Em última análise, uma relação um-para-um entre o número de partições e instâncias de função, ou consumidores, é o alvo ideal para a taxa de transferência máxima em uma solução de processamento de fluxo. Para alcançar o paralelismo ideal, tenha vários consumidores em um grupo de consumidores. Para Funções, esse objetivo se traduz em muitas instâncias de uma função no plano. O resultado é referido como paralelismo de nível de partição ou o grau máximo de paralelismo, como mostrado no diagrama a seguir:

Grau máximo de paralelismo

Pode parecer fazer sentido configurar o maior número possível de partições para alcançar a taxa de transferência máxima e levar em conta a possibilidade de um maior volume de eventos. No entanto, há vários fatores importantes a serem considerados ao configurar muitas partições:

  • Mais partições podem levar a mais taxa de transferência: Como o grau de paralelismo é o número de consumidores (instâncias de função), quanto mais partições houver, maior poderá ser a taxa de transferência simultânea. Esse fato é importante quando você compartilha um número designado de TUs para um hub de eventos com outros aplicativos de consumo.
  • Mais funções podem exigir mais memória: à medida que o número de instâncias de função aumenta, aumenta também a pegada de memória dos recursos no plano. Em algum momento, muitas partições podem deteriorar o desempenho dos consumidores.
  • Há um risco de contrapressão dos serviços downstream: à medida que mais taxa de transferência é gerada, você corre o risco de sobrecarregar os serviços downstream ou receber pressão de retorno deles. O fan-out do consumidor deve ser levado em conta ao considerar as consequências para os recursos circundantes. As possíveis consequências incluíram limitação de outros serviços, saturação da rede e outras formas de contenção de recursos.
  • As partições podem ser escassamente preenchidas: a combinação de muitas partições e um baixo volume de eventos pode levar a dados que são distribuídos esparsamente entre partições. Em vez disso, um número menor de partições pode fornecer melhor desempenho e uso de recursos.

Disponibilidade e consistência

Quando uma chave de partição ou ID não é especificada, os Hubs de Eventos roteiam um evento de entrada para a próxima partição disponível. Essa prática fornece alta disponibilidade e ajuda a aumentar o rendimento para os consumidores.

Quando a ordem de um conjunto de eventos é necessária, o produtor de eventos pode especificar que uma partição específica deve ser usada para todos os eventos do conjunto. O aplicativo consumidor que lê a partir da partição recebe os eventos na ordem adequada. Essa compensação fornece consistência, mas compromete a disponibilidade. Não use essa abordagem, a menos que a ordem dos eventos deva ser preservada.

Para Funções, a ordenação é obtida quando os eventos são publicados em uma partição específica e uma função acionada por Hubs de Eventos obtém uma concessão para a mesma partição. Atualmente, a capacidade de configurar uma partição com a ligação de saída dos Hubs de Eventos não é suportada. Em vez disso, a melhor abordagem é usar um dos SDKs de Hubs de Eventos para publicar em uma partição específica.

Para obter mais informações sobre como os Hubs de Eventos oferecem suporte à disponibilidade e consistência, consulte Disponibilidade e consistência em Hubs de Eventos.

Os Hubs de Eventos disparam

Esta seção se concentra nas configurações e considerações para otimizar as funções acionadas pelos Hubs de Eventos. Os fatores incluem processamento em lote, amostragem e recursos relacionados que influenciam o comportamento de uma vinculação de gatilho de hub de eventos.

Processamento em lote para funções acionadas

Você pode configurar funções que um hub de eventos aciona para processar um lote de eventos ou um evento de cada vez. O processamento de um lote de eventos pode ser mais eficiente quando reduz parte da sobrecarga de invocações de funções. A menos que você precise processar apenas um único evento, sua função deve ser configurada para processar vários eventos quando invocada.

A habilitação do envio em lote para a vinculação de gatilho dos Hubs de Eventos varia entre os idiomas:

  • JavaScript, Python e outras linguagens habilitam o processamento em lote quando a propriedade cardinality é definida como muitos no arquivo function.json para a função.
  • Em C#, a cardinalidade é configurada automaticamente quando uma matriz é designada para o tipo no atributo EventHubTrigger .

Para obter mais informações sobre como o processamento em lote é habilitado, consulte Gatilho de Hubs de Eventos do Azure para o Azure Functions.

Definições do acionador

Várias definições de configuração no arquivo host.json desempenham um papel fundamental nas características de desempenho da vinculação de gatilho de Hubs de Eventos para Funções:

  • maxEventBatchSize: essa configuração representa o número máximo de eventos que a função pode receber quando é invocada. Se o número de eventos recebidos for menor que esse valor, a função ainda será invocada com tantos eventos quantos estiverem disponíveis. Não é possível definir um tamanho mínimo de lote.
  • prefetchCount: A contagem de pré-busca é uma das configurações mais importantes quando você otimiza o desempenho. O canal AMQP subjacente faz referência a esse valor para determinar quantas mensagens buscar e armazenar em cache para o cliente. A contagem de pré-busca deve ser maior ou igual ao valor maxEventBatchSize e geralmente é definida como um múltiplo dessa quantidade. Definir esse valor para um número menor do que a configuração maxEventBatchSize pode prejudicar o desempenho.
  • batchCheckpointFrequency: Como sua função processa lotes, esse valor determina a taxa na qual os pontos de verificação são criados. O valor padrão é 1, o que significa que há um ponto de verificação sempre que uma função processa com êxito um único lote. Um ponto de verificação é criado no nível da partição para cada leitor no grupo de consumidores. Para obter informações sobre como essa configuração influencia repetições e repetições de eventos, consulte Função do Azure acionada pelo hub de eventos: repetições e repetições (postagem de blog).

Faça vários testes de desempenho para determinar os valores a serem definidos para a associação de gatilho. Recomendamos que você altere as configurações incrementalmente e meça consistentemente para ajustar essas opções. Os valores padrão são um ponto de partida razoável para a maioria das soluções de processamento de eventos.

Pontos de verificação

Pontos de verificação marcam ou confirmam posições do leitor em uma sequência de eventos de partição. É responsabilidade do host do Functions verificar o ponto à medida que os eventos são processados e a configuração para a frequência do ponto de verificação em lote é atendida. Para obter mais informações sobre pontos de verificação, consulte Recursos e terminologia nos Hubs de Eventos do Azure.

Os conceitos a seguir podem ajudá-lo a entender a relação entre o ponto de verificação e a maneira como sua função processa eventos:

  • As exceções ainda contam para o sucesso: Se o processo da função não falhar durante o processamento de eventos, a conclusão da função será considerada bem-sucedida, mesmo que tenham ocorrido exceções. Quando a função é concluída, o host Functions avalia batchCheckpointFrequency. Se for hora de um ponto de verificação, ele criará um, independentemente de haver exceções. O fato de as exceções não afetarem o ponto de verificação não deve afetar o uso adequado da verificação e tratamento de exceções.
  • A frequência de lote é importante: em soluções de streaming de eventos de alto volume, pode ser benéfico alterar a configuração batchCheckpointFrequency para um valor maior que 1. Aumentar esse valor pode reduzir a taxa de criação de pontos de verificação e, consequentemente, o número de operações de E/S de armazenamento.
  • Repetições podem acontecer: cada vez que uma função é invocada com a vinculação de gatilho dos Hubs de Eventos, ela usa o ponto de verificação mais recente para determinar onde retomar o processamento. O deslocamento para cada consumidor é salvo no nível de partição para cada grupo de consumidores. As repetições acontecem quando um ponto de verificação não ocorre durante a última invocação da função e a função é invocada novamente. Para obter mais informações sobre duplicatas e técnicas de desduplicação, consulte Idempotência.

Compreender o ponto de verificação torna-se crítico quando você considera as práticas recomendadas para tratamento de erros e tentativas, um tópico que será discutido mais adiante neste artigo.

Amostragem por telemetria

O Functions fornece suporte interno para o Application Insights, uma extensão do Azure Monitor que fornece recursos de monitoramento de desempenho de aplicativos. Com esse recurso, você pode registrar informações sobre atividades de função, desempenho, exceções de tempo de execução e muito mais. Para obter mais informações, consulte Visão geral do Application Insights.

Esta poderosa capacidade oferece algumas opções de configuração importantes que afetam o desempenho. Algumas das configurações e considerações notáveis para monitoramento e desempenho são:

  • Habilitar amostragem de telemetria: para cenários de alta taxa de transferência, você deve avaliar a quantidade de telemetria e informações de que precisa. Considere usar o recurso de amostragem de telemetria no Application Insights para evitar degradar o desempenho de sua função com telemetria e métricas desnecessárias.
  • Definir configurações de agregação: examine e configure a frequência de agregação e envio de dados para o Application Insights. Essa definição de configuração está no arquivo host.json , juntamente com muitas outras opções relacionadas à amostragem e registro. Para obter mais informações, consulte Configurar o agregador.
  • Desabilitar AzureWebJobDashboard: para aplicativos destinados à versão 1.x do tempo de execução do Functions, essa configuração armazena a cadeia de conexão em uma conta de armazenamento que o SDK do Azure usa para reter logs para o painel WebJobs. Se o Application Insights for usado em vez do painel WebJobs, essa configuração deverá ser removida. Para obter mais informações, consulte AzureWebJobsDashboard.

Quando o Application Insights é habilitado sem amostragem, toda a telemetria é enviada. O envio de dados sobre todos os eventos pode ter um efeito prejudicial no desempenho da função, especialmente em cenários de streaming de eventos de alta taxa de transferência.

Tirar proveito da amostragem e avaliar continuamente a quantidade apropriada de telemetria necessária para o monitoramento é crucial para o desempenho ideal. A telemetria deve ser usada para avaliação geral da integridade da plataforma e para solução de problemas ocasionais, não para capturar métricas de negócios principais. Para obter mais informações, veja Configurar a amostragem.

Vinculação de saída

Use a associação de saída de Hubs de Eventos para o Azure Functions para simplificar a publicação em um fluxo de eventos de uma função. Os benefícios de usar essa vinculação incluem:

  • Gerenciamento de recursos: a associação lida com os ciclos de vida do cliente e da conexão para você e reduz o potencial de problemas que podem surgir com o esgotamento da porta e o gerenciamento do pool de conexões.
  • Menos código: a associação abstrai o SDK subjacente e reduz a quantidade de código necessária para publicar eventos. Ele ajuda você a escrever código que é mais fácil de escrever e manter.
  • Processamento em lote: para vários idiomas, há suporte para publicação em lote eficiente em um fluxo de eventos. O processamento em lote pode melhorar o desempenho e ajudar a simplificar o código que envia os eventos.

É altamente recomendável que você revise a lista de idiomas suportados pelo Functions e os guias do desenvolvedor para esses idiomas. A seção Ligações para cada idioma fornece exemplos e documentação detalhados .

Envio em lote ao publicar eventos

Se sua função publica apenas um único evento, configurar a associação para retornar um valor é uma abordagem comum que é útil se a execução da função sempre termina com uma instrução que envia o evento. Essa técnica só deve ser usada para funções síncronas que retornam apenas um evento.

O processamento em lote é incentivado para melhorar o desempenho ao enviar vários eventos para um fluxo. O processamento em lote permite que a vinculação publique eventos da maneira mais eficiente possível.

O suporte para usar a associação de saída para enviar vários eventos para Hubs de Eventos está disponível em C#, Java, Python e JavaScript.

Saída de vários eventos com o modelo em processo (C#)

Use os tipos ICollector e IAsyncCollector quando você envia vários eventos de uma função em C#.

  • O ICollector<T>. O método Add() pode ser usado em funções síncronas e assíncronas. Ele executa a operação add assim que é chamada.
  • O IAsyncCollector<T>. O método AddAsync() prepara os eventos a serem publicados no fluxo de eventos. Se você escrever uma função assíncrona, deverá usar IAsyncCollector para gerenciar melhor os eventos publicados.

Para obter exemplos de como usar C# para publicar eventos únicos e múltiplos, consulte Vinculação de saída dos Hubs de Eventos do Azure para o Azure Functions.

Saída de vários eventos com o modelo de trabalhador isolado (C#)

Dependendo da versão de tempo de execução do Functions, o modelo de trabalho isolado suportará diferentes tipos para os parâmetros que são passados para a ligação de saída. Para vários eventos, uma matriz é usada para encapsular o conjunto. Recomenda-se revisar os atributos de vinculação de saída e os detalhes de uso para o modelo Isolado e anotar as diferenças entre as versões de extensão.

Limitação e contrapressão

As considerações de limitação aplicam-se às associações de saída, não apenas para Hubs de Eventos, mas também para serviços do Azure, como o Azure Cosmos DB. É importante familiarizar-se com os limites e quotas que se aplicam a esses serviços e planear em conformidade.

Para lidar com erros downstream com o modelo em processo, você pode encapsular AddAsync e FlushAsync em um manipulador de exceção para funções .NET para capturar exceções de IAsyncCollector. Outra opção é usar os SDKs de Hubs de Eventos diretamente em vez de usar associações de saída.

Se você estiver aproveitando o modelo Isolado para funções, o tratamento estruturado de exceções deve ser usado para capturar exceções de forma responsável ao retornar os valores de saída.

Código da função

Esta seção aborda as principais áreas que devem ser consideradas ao escrever código para processar eventos em uma função acionada pelos Hubs de Eventos.

Programação assíncrona

Recomendamos que você escreva sua função para usar código assíncrono e evitar bloquear chamadas, especialmente quando chamadas de E/S estão envolvidas.

Aqui estão as diretrizes que você deve seguir ao escrever uma função para processar de forma assíncrona:

  • Todas assíncronas ou todas síncronas: se uma função estiver configurada para ser executada de forma assíncrona, todas as chamadas de E/S deverão ser assíncronas. Na maioria dos casos, o código parcialmente assíncrono é pior do que o código totalmente síncrono. Escolha assíncrono ou síncrono e mantenha a escolha até o fim.
  • Evite bloquear chamadas: o bloqueio de chamadas retorna ao chamador somente após a conclusão da chamada, em contraste com as chamadas assíncronas que retornam imediatamente. Um exemplo em C# seria chamar Task.Result ou Task.Wait em uma operação assíncrona.

Mais informações sobre o bloqueio de chamadas

O uso de chamadas de bloqueio para operações assíncronas pode levar à fome do pool de threads e fazer com que o processo de função falhe. A falha acontece porque uma chamada de bloqueio requer que outro thread seja criado para compensar a chamada original que agora está esperando. Como resultado, ele requer o dobro de threads para concluir a operação.

Evitar essa abordagem de sincronização assíncrona é especialmente importante quando Hubs de Eventos estão envolvidos, porque uma falha de função não atualiza o ponto de verificação. Da próxima vez que a função for invocada, ela pode acabar nesse ciclo e parecer estar presa ou se mover lentamente à medida que as execuções da função eventualmente expiram.

A solução de problemas desse fenômeno geralmente começa com a revisão das configurações de gatilho e a execução de experimentos que podem envolver o aumento da contagem de partições. As investigações também podem levar à alteração de várias das opções de loteamento, como o tamanho máximo do lote ou a contagem de pré-busca. A impressão é que é um problema de taxa de transferência ou definição de configuração que só precisa ser ajustada de acordo. No entanto, o problema central está no próprio código e deve ser abordado lá.

Contribuidores

Este artigo é mantido pela Microsoft. Foi originalmente escrito pelo seguinte colaborador.

Autor principal:

  • David Barkol - Brasil | Especialista Principal de Soluções GBB

Para ver perfis não públicos do LinkedIn, inicie sessão no LinkedIn.

Próximos passos

Antes de continuar, considere rever estes artigos relacionados: