Editar

Compartilhar via


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

Hubs de eventos do Azure
Funções do Azure

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.

Função grouping

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 em uma nova estrutura de dados ou enriquecer dados para aplicativos downstream.

No Functions, um aplicativo de funções fornece o contexto de execução para funções. Os comportamentos do aplicativo de funções se aplicam a todas as funções que o aplicativo de função hospeda. As funções em um aplicativo de funções são implantadas e escaladas juntas. Todas as funções de um aplicativo de funções precisam ser da mesma linguagem.

A forma como você agrupa funções em aplicativos de função pode afetar o desempenho e os recursos de dimensionamento de seus aplicativos de função. 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 aspectos, consulte Práticas recomendadas para uso confiável do Azure Functions e Melhore o desempenho e a confiabilidade do Azure Functions.

A lista a seguir é uma orientação para agrupar funções. A orientação considera aspectos de armazenamento e grupo de consumidores:

  • Hospede 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 seu próprio volume 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 acionadas pelos Hubs de Eventos, pois 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 variar. Os grupos de consumidores possibilitam que vários aplicativos de consumo tenham suas próprias exibiçõ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 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 clientes dedicados para cada aplicativo de função

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

Planos de hospedagem de função

Existem várias opções de hospedagem para aplicativos de funções e é importante revisar seus recursos. Para obter informações sobre essas opções de hosting, consulte Opções de hosting do Azure Functions. Observe 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 duração.

Os planos Premium e Dedicado são frequentemente usados para hospedar aplicativos e funções de várias funções que consomem mais 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 observar 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ções em contêineres no Azure Functions. Isso permite que você execute suas funções controladas por eventos em um ambiente totalmente gerenciado baseado em Kubernetes com suporte interno para monitoramento de software livre, 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 devem ser definidas corretamente para garantir o desempenho e o dimensionamento máximos. 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 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, consulte O que é o Hubs de Eventos do Azure para Apache Kafka.

Noções básicas sobre unidades de produtividade (TUs)

Na camada Standard dos Hubs de Eventos, a taxa de transferência é classificada como a quantidade de dados que entra e é lida do namespace por unidade de tempo. As TUs são unidades pré-adquiridas de capacidade de produtividade.

As TUs são cobradas 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 TUs está no ponto de entrada. No entanto, o agregado para os aplicativos de consumo, incluindo a taxa na qual 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 dos Hubs de Eventos, consulte Unidades de produtividade.

Escale verticalmente com a ampliação automática

A ampliaçã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 ampliação automática evita a limitação do 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 ampliação automática ajuda a resolver preocupações sobre o superprovisionamento.

A ampliação automática é um recurso dos Hubs de Eventos que muitas vezes é confundida com o dimensionamento automático, especialmente no contexto de soluções sem servidor. No entanto, a ampliação automática, ao contrário do dimensionamento automático, não reduz verticalmente 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 as camadas Premium ou 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 nas camadas Premium e Dedicada. 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 hosting Consumo e Premium, as instâncias do aplicativo de função são escaladas horizontalmente de forma dinâmica para atender ao número de partições, se necessário. O plano de hospedagem Dedicado 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 Dedicado para o Azure Functions.

Em última análise, um relacionamento um-para-um entre o número de partições e instâncias de função, ou consumidores, é o destino ideal para a taxa de produtividade máxima em uma solução de processamento de fluxo. Para atingir o paralelismo ideal, tenha vários consumidores em um grupo de consumidores. Para o Functions, esse objetivo se traduz em muitas instâncias de uma função no plano. O resultado é referido como paralelismo em nível de partição ou o grau máximo de paralelismo, conforme 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 atingir a taxa de produtividade máxima e levar em conta a possibilidade de um volume maior 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 produtividade: como o grau de paralelismo é o número de consumidores (instâncias de função), quanto mais partições houver, maior será a taxa de produtividade simultânea. Esse fato é importante quando você compartilha um número designado de TUs para um hub de eventos com outros aplicativos de consumidor.
  • Mais funções podem exigir mais memória: à medida que o número de instâncias de função aumenta, o mesmo acontece com o volume de memória dos recursos no plano. Em algum momento, muitas partições podem deteriorar o desempenho dos consumidores.
  • Há um risco de pressão de retorno dos serviços downstream: à medida que mais produtividade é gerada, você corre o risco de sobrecarregar os serviços downstream ou receber pressão de volta deles. A distribuição ao consumidor deve ser levada 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 preenchidas esparsamente: 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 a taxa de produtividade para os consumidores.

Quando a ordenação 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 correta. 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 o Functions, a ordenação é obtida quando os eventos são publicados em uma partição específica e uma função acionada pelos Hubs de Eventos obtém uma concessão para a mesma partição. Atualmente, a capacidade de configurar uma partição com a associação de saída dos Hubs de Eventos não é suportada. Em vez disso, a melhor abordagem é usar um dos SDKs dos 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 nos Hubs de Eventos.

Gatilho dos Hubs de Eventos

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

Envio em lote para funções disparadas

Você pode configurar funções que um hub de eventos dispara 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ção. A menos que você precise processar apenas um evento único, sua função deve ser configurada para processar vários eventos quando invocada.

A habilitação do envio em lote para a associação de gatilho dos Hubs de Eventos varia entre as linguagens:

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

Para obter mais informações sobre como o envio em lote está habilitado, consulte Gatilhos de Hubs de Eventos do Azure para o Azure Functions.

Configurações do gatilho

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

  • maxEventBatchSize: essa configuração representa o número máximo de eventos que a função pode receber quando é chamada. Se o número de eventos recebidos for menor que esse valor, a função ainda será invocada com quantos eventos 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 ao otimizar 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 desse valor. Definir esse valor para um número menor que a configuração maxEventBatchSize pode prejudicar o desempenho.
  • batchCheckpointFrequency: à medida que 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 um único lote com êxito. 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 novas tentativas de eventos, consulte Função do Azure disparada pelo hub de eventos: repetições e novas tentativas (postagem de blog).

Faça vários testes de desempenho para determinar os valores a serem definidos para a associação de disparo. Recomendamos que você altere as configurações de forma incremental e meça constantemente 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.

Definindo o ponto de verificação

Os pontos de verificação marcam ou confirmam as posições do leitor em uma sequência de eventos de partição. É responsabilidade do host do Functions criar um ponto de verificação à medida que os eventos são processados e a configuração da 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 ajudar você 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 do Functions avalia batchCheckpointFrequency. Se chegar a hora de um ponto de verificação, ele criará um, independentemente de haver exceções. O fato de que as exceções não afetam o ponto de verificação não deve afetar o uso adequado da verificação e do tratamento de exceções.
  • A frequência do lote é importante: em soluções de streaming de eventos de alto volume, pode ser vantajoso 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, como consequência, o número de operações de E/S de armazenamento.
  • Podem acontecer repetições: cada vez que uma função é invocada com a associação de gatilho dos Hubs de Eventos, ela usa o ponto de verificação mais recente para determinar onde retomar o processamento. O deslocamento de 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 chamada da função e a função é invocada novamente. Para obter mais informações sobre duplicatas e técnicas de eliminação de duplicação, consulte Idempotência.

Compreender o ponto de verificação torna-se fundamental ao considerar as práticas recomendadas para tratamento de erros e novas tentativas, um tópico que será discutido mais adiante neste artigo.

Amostragem de telemetria

O Functions fornece suporte interno para o Application Insights, uma extensão do Azure Monitor que fornece recursos de monitoramento de desempenho do aplicativo. 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.

Esse poderoso recurso oferece algumas opções de configuração importantes que afetam o desempenho. Algumas das configurações e considerações importantes 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 as informações necessárias. Considere o uso do recurso de amostragem de telemetria no Application Insights para evitar a degradação do 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 junto com muitas outras opções relacionadas à amostragem e ao registro em log. 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 para 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, principalmente em cenários de streaming de eventos de alta taxa de transferência.

Aproveitar a amostragem e avaliar continuamente a quantidade adequada de telemetria necessária para o monitoramento é essencial 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, confira Configurar amostragem.

Associação de saída

Use a associação de saída dos Hubs de Eventos para o Associação de saída dos 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 associação incluem:

  • Gerenciamento de recursos: a associação lida com os ciclos de vida do cliente e da conexão para você e reduz possíveis problemas que possam 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. Ela ajuda você a escrever código que é mais fácil de escrever e manter.
  • Envio em lote: para várias linguagens, o processamento em lote é suportado para publicar com eficiência em um fluxo de eventos. O envio 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 Linguagens que o Functions oferece suporte e os guias do desenvolvedor para essas linguagens. A seção Associações de cada linguagem fornece exemplos detalhados e documentação.

Envio em lote ao publicar eventos

Se sua função publicar 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 terminar 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 envio em lote é incentivado para melhorar o desempenho ao enviar vários eventos para um fluxo. O envio em lote permite que a associação publique eventos da forma mais eficiente possível.

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

Gerar vários eventos com o modelo em processo (C#)

Use os tipos ICollector e IAsyncCollector ao enviar vários eventos de uma função em C#.

  • O método ICollector<T>.Add() pode ser usado em funções síncronas e assíncronas. Ele executa a operação de adição assim que é chamado.
  • O método IAsyncCollector<T>.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 Associação de saída dos Hubs de Eventos do Azure para o Azure Functions.

Gerar vários eventos com o modelo de trabalho isolado (C#)

Dependendo da versão do runtime do Functions, o modelo de trabalho isolado dará suporte a tipos diferentes para os parâmetros que são passados para a associação de saída. Para vários eventos, uma matriz é usada para encapsular o conjunto. É recomendável examinar os atributos de associação de saída e os detalhes de uso do modelo Isolado e anotar as diferenças entre as versões de extensão.

Limitação e pressão de retorno

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

Para lidar com erros downstream com o modelo Em processo, você pode encapsular AddAsync e FlushAsync em um manipulador de exceções para .NET Functions para capturar exceções de IAsyncCollector. Outra opção é usar os SDKs dos 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 deverá ser usado para capturar exceções de forma responsável ao retornar os valores de saída.

Código de 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 estão envolvidas chamadas de E/S.

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

  • Todos assíncronos ou todos síncronos: 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 entre assíncrono ou síncrono e mantenha a escolha até o fim.
  • Evite chamadas de bloqueio: as chamadas de bloqueio retornam 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 chamadas de bloqueio

Usar chamadas de bloqueio para operações assíncronas pode levar à privação 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á aguardando. Como resultado, ele requer o dobro de threads para concluir a operação.

Evitar essa abordagem de síncrono em vez de assíncrono é especialmente importante quando Hubs de Eventos está envolvido, porque uma falha de função não atualiza o ponto de verificação. Na 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 envio em lote, 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 principal está no próprio código e deve ser resolvido lá.

Colaboradores

Esse artigo é mantido pela Microsoft. Ele foi escrito originalmente pelos colaboradores a seguir.

Autor principal:

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

Próximas etapas

Antes de continuar, considere revisar estes artigos relacionados: