Simultaneidade no Azure Functions

Este artigo descreve os comportamentos de simultaneidade de gatilhos controlados por eventos no Azure Functions. Ele também descreve um novo modelo dinâmico para otimizar comportamentos de simultaneidade.

O modelo de hospedagem para Functions permite que várias invocações de função sejam executadas simultaneamente em uma única instância de computação. Por exemplo, considere um caso em que você tem três funções diferentes em seu aplicativo de função, que é dimensionado e executado em várias instâncias. Nesse cenário, cada função processa invocações em cada instância de VM na qual seu aplicativo de função está sendo executado. As invocações de função em uma única instância compartilham os mesmos recursos de computação da VM, como memória, CPU e conexões. Quando seu aplicativo é hospedado em um plano dinâmico (Consumo ou Premium), a plataforma dimensiona o número de instâncias de aplicativo de função para cima ou para baixo com base no número de eventos de entrada. Para saber mais, consulte Dimensionamento controlado por eventos). Ao hospedar suas funções em um plano Dedicado (Serviço de Aplicativo), você configura manualmente suas instâncias ou configura um esquema de dimensionamento automático.

Como várias invocações de função podem ser executadas em cada instância simultaneamente, cada função precisa ter uma maneira de limitar quantas invocações simultâneas está processando a qualquer momento.

Simultaneidade estática

Muitos dos gatilhos suportam um modelo de configuração estática no nível do host, que é usado para especificar a simultaneidade por instância para esse tipo de gatilho. Por exemplo, o gatilho do Service Bus fornece uma MaxConcurrentCalls e uma MaxConcurrentSessions configuração no arquivo host.json. Essas configurações juntas controlam o número máximo de mensagens que cada função processa simultaneamente em cada instância. Outros tipos de gatilho têm mecanismos internos para invocações de balanceamento de carga entre instâncias. Por exemplo, os Hubs de Eventos e o Azure Cosmos DB usam um esquema baseado em partição.

Para tipos de gatilho que suportam configuração de simultaneidade, há um comportamento padrão, que você pode optar por substituir no arquivo de host.json para seu aplicativo de função. Essas configurações, que se aplicam a todas as instâncias em execução, permitem que você controle a simultaneidade máxima para suas funções em cada instância. Por exemplo, quando sua função consome muita CPU ou recursos, você pode optar por limitar a simultaneidade para manter as instâncias íntegras. Da mesma forma, quando sua função está fazendo solicitações para um serviço downstream que está sendo limitado, você também deve considerar limitar a simultaneidade.

Embora essas configurações de simultaneidade ofereçam controle de certos comportamentos de gatilho, como limitar suas funções, pode ser difícil determinar os valores ideais para essas configurações. Geralmente, você tem que chegar a valores aceitáveis através de um processo de tentativa e erro de teste de carga. Mesmo quando você determina um conjunto de valores que estão funcionando para um perfil de carga específico, o número de eventos que chegam de seus serviços conectados pode mudar de dia para dia. Essa variabilidade significa que seu aplicativo geralmente pode ser executado com valores abaixo do ideal. Por exemplo, seu aplicativo de função pode processar cargas de mensagens particularmente exigentes no último dia da semana, o que exige que você reduza a simultaneidade. No entanto, durante o resto da semana, as cargas úteis da mensagem são mais simples, o que significa que você pode usar um nível de simultaneidade mais alto no resto da semana.

Idealmente, queremos que o sistema permita que as instâncias processem o máximo de trabalho possível, mantendo cada instância saudável e latências baixas, que é o que a simultaneidade dinâmica foi projetada para fazer.

Simultaneidade dinâmica

O Functions agora fornece um modelo de simultaneidade dinâmica que simplifica a configuração da simultaneidade para todos os aplicativos de função executados no mesmo plano.

Nota

Atualmente, a simultaneidade dinâmica só tem suporte para os gatilhos de Blob do Azure, Fila do Azure e Barramento de Serviço e exige que você use as versões listadas na seção de suporte de extensão abaixo.

Benefícios

O uso da simultaneidade dinâmica oferece os seguintes benefícios:

  • Configuração simplificada: não é mais necessário determinar manualmente as configurações de simultaneidade por gatilho. O sistema aprende os valores ideais para a sua carga de trabalho ao longo do tempo.
  • Ajustes dinâmicos: A simultaneidade é ajustada dinamicamente para cima ou para baixo em tempo real, o que permite que o sistema se adapte às mudanças nos padrões de carga ao longo do tempo.
  • Proteção da integridade da instância: o tempo de execução limita a simultaneidade aos níveis que uma instância de aplicativo de função pode lidar confortavelmente. Isso protege o aplicativo de se sobrecarregar, assumindo mais trabalho do que deveria.
  • Taxa de transferência aprimorada: a taxa de transferência geral é melhorada porque as instâncias individuais não estão recebendo mais trabalho do que podem processar rapidamente. Isso permite que o trabalho seja balanceado de forma mais eficaz entre instâncias. Para funções que podem lidar com cargas mais altas, a simultaneidade pode ser aumentada para valores além dos valores de configuração padrão, o que gera uma taxa de transferência mais alta.

Configuração de simultaneidade dinâmica

A simultaneidade dinâmica pode ser ativada no nível do host no arquivo host.json. Quando, habilitadas todas as extensões de vinculação usadas pelo seu aplicativo de função que suportam simultaneidade dinâmica, ajuste a simultaneidade dinamicamente conforme necessário. As configurações de simultaneidade dinâmica substituem quaisquer configurações de simultaneidade configuradas manualmente para gatilhos que oferecem suporte à simultaneidade dinâmica.

Por padrão, a simultaneidade dinâmica está desabilitada. Com a simultaneidade dinâmica habilitada, a simultaneidade começa em 1 para cada função e é ajustada até um valor ideal, que é determinado pelo host.

Você pode habilitar a simultaneidade dinâmica em seu aplicativo de função adicionando as seguintes configurações em seu arquivo de host.json:

    { 
        "version": "2.0", 
        "concurrency": { 
            "dynamicConcurrencyEnabled": true, 
            "snapshotPersistenceEnabled": true 
        } 
    } 

Quando SnapshotPersistenceEnabled é true, que é o padrão, os valores de simultaneidade aprendidos são periodicamente persistidos para armazenamento para que novas instâncias comecem a partir desses valores em vez de começar a partir de 1 e ter que refazer o aprendizado.

Gestor de simultaneidade

Nos bastidores, quando a simultaneidade dinâmica está ativada, há um processo de gerenciamento de simultaneidade em execução em segundo plano. Esse gerenciador monitora constantemente as métricas de integridade da instância, como a utilização da CPU e do thread, e altera as limitações conforme necessário. Quando um ou mais aceleradores são ativados, a simultaneidade da função é ajustada para baixo até que o host esteja íntegro novamente. Quando os aceleradores estão desativados, a simultaneidade pode aumentar. Várias heurísticas são usadas para ajustar inteligentemente a simultaneidade para cima ou para baixo, conforme necessário, com base nesses aceleradores. Com o tempo, a simultaneidade para cada função estabiliza a um nível específico.

Os níveis de simultaneidade são gerenciados para cada função individual. Como tal, o sistema equilibra-se entre funções com utilização intensiva de recursos que requerem um baixo nível de simultaneidade e funções mais leves que podem lidar com simultaneidade mais elevada. O saldo de simultaneidade para cada função ajuda a manter a integridade geral da instância do aplicativo de função.

Quando a simultaneidade dinâmica estiver ativada, você verá decisões de simultaneidade dinâmica em seus logs. Por exemplo, você verá logs quando vários aceleradores estiverem habilitados e sempre que a simultaneidade for ajustada para cima ou para baixo para cada função. Esses logs são gravados na categoria de log Host.Concurrency na tabela de rastreamentos.

Suporte de extensão

A simultaneidade dinâmica está habilitada para um aplicativo de função no nível do host e todas as extensões que suportam simultaneidade dinâmica são executadas nesse modo. A simultaneidade dinâmica requer colaboração entre o host e as extensões de gatilho individuais. Apenas as versões listadas das seguintes extensões suportam simultaneidade dinâmica.

Filas do Azure

O gatilho de armazenamento de fila do Azure tem seu próprio loop de sondagem de mensagens. Ao usar a configuração estática, a simultaneidade é regida pelas opções de BatchSize/NewBatchThreshold configuração. Ao usar a simultaneidade dinâmica, esses valores de configuração são ignorados. A simultaneidade dinâmica é integrada ao loop de mensagens, de modo que o número de mensagens buscadas por iteração é ajustado dinamicamente. Quando os aceleradores estiverem ativados (o host estiver sobrecarregado), o processamento de mensagens será pausado até que os aceleradores sejam desativados. Quando os aceleradores são desativados, a simultaneidade aumenta.

Para usar simultaneidade dinâmica para filas, você deve usar a versão 5.x da extensão de armazenamento.

Blobs do Azure

Internamente, o gatilho de armazenamento de Blob do Azure usa a mesma infraestrutura que o Gatilho de Fila do Azure usa. Quando blobs novos/atualizados precisam ser processados, as mensagens são gravadas em uma fila de controle gerenciada pela plataforma e essa fila é processada usando a mesma lógica usada para QueueTrigger. Quando a simultaneidade dinâmica estiver habilitada, a simultaneidade para o processamento dessa fila de controle será gerenciada dinamicamente.

Para usar simultaneidade dinâmica para Blobs, você deve usar a versão 5.x da extensão de armazenamento.

Service Bus

Atualmente, o gatilho do Service Bus oferece suporte a três modelos de execução. A simultaneidade dinâmica afeta esses modelos de execução da seguinte maneira:

  • Processamento de tópico/fila de envio único: Cada invocação da sua função processa uma única mensagem. Ao usar a configuração estática, a simultaneidade é regida MaxConcurrentCalls pela opção config. Ao usar a simultaneidade dinâmica, esse valor de configuração é ignorado e a simultaneidade é ajustada dinamicamente.
  • Processamento de tópico/fila de despacho único baseado em sessão: Cada invocação da sua função processa uma única mensagem. Dependendo do número de sessões ativas para seu tópico/fila, cada instância aluga uma ou mais sessões. As mensagens em cada sessão são processadas em série, para garantir a ordem em uma sessão. Quando não estiver usando simultaneidade dinâmica, a simultaneidade é regida MaxConcurrentSessions pela configuração. Com a simultaneidade dinâmica habilitada, MaxConcurrentSessions é ignorada e o número de sessões que cada instância está processando é ajustado dinamicamente.
  • Processamento em lote: cada invocação de sua função processa um lote de mensagens, regido pela MaxMessageCount configuração. Como as invocações em lote são seriais, a simultaneidade para sua função acionada em lote é sempre uma e a simultaneidade dinâmica não se aplica.

Para habilitar o gatilho do Service Bus para usar simultaneidade dinâmica, você deve usar a versão 5.x da extensão do Service Bus.

Próximos passos

Para obter mais informações, consulte os seguintes recursos: