Processamento de eventos sem servidor

Cosmos DB
Funções
Monitor
Pipelines
Armazenamento

Esta arquitetura de referência mostra uma arquitetura sem servidor condicionada por eventos que ingere um fluxo de dados, processa os dados e escreve os resultados numa base de dados de back-end.

Arquitetura

Diagrama a mostrar uma arquitetura de referência para processamento de eventos sem servidor com Funções do Azure.

Fluxo de trabalho

  • Os eventos chegam às Hubs de Eventos do Azure.
  • É acionada uma Aplicação de Funções para processar o evento.
  • O evento é armazenado numa base de dados do Azure Cosmos DB.
  • Se a Aplicação de Funções não conseguir armazenar o evento com êxito, o evento será guardado numa fila de Armazenamento para ser processado mais tarde.

Componentes

  • Os Hubs de Eventos ingerem o fluxo de dados. Os Hubs de Eventos foram concebidos para cenários de transmissão em fluxo de dados de alto débito.

    Nota

    Para cenários de Internet das Coisas (IoT), recomendamos que Hub IoT do Azure. Hub IoT tem um ponto final incorporado compatível com a API Hubs de Eventos do Azure, pelo que pode utilizar qualquer um dos serviços nesta arquitetura sem grandes alterações no processamento de back-end. Para obter mais informações, veja Ligar Dispositivos IoT ao Azure: Hub IoT e Hubs de Eventos.

  • Aplicação de Funções. Funções do Azure é uma opção de computação sem servidor. Utiliza um modelo baseado em eventos, em que um fragmento de código (uma função) é invocado por um acionador. Nesta arquitetura, quando os eventos chegam aos Hubs de Eventos, acionam uma função que processa os eventos e escreve os resultados no armazenamento.

    As Aplicações de Funções são adequadas para processar registos individuais a partir dos Hubs de Eventos. Para cenários de processamento de fluxos mais complexos, considere o Apache Spark com o Azure Databricks ou o Azure Stream Analytics.

  • Azure Cosmos DB. O Azure Cosmos DB é um serviço de base de dados com vários modelos que está disponível num modo sem servidor e baseado no consumo. Neste cenário, a função de processamento de eventos armazena registos JSON com o Azure Cosmos DB para NoSQL.

  • Armazenamento de filas. O armazenamento de filas é utilizado para mensagens não entregues. Se ocorrer um erro ao processar um evento, a função armazena os dados do evento numa fila de mensagens não entregues para processamento posterior. Para obter mais informações, veja a secção Resiliência mais à frente neste artigo.

  • Azure Monitor. O Monitor recolhe métricas de desempenho sobre os serviços do Azure implementados na solução. Ao visualizá-los num dashboard, pode obter visibilidade sobre o estado de funcionamento da solução.

  • Pipelines do Azure. Os pipelines são um serviço de integração contínua (CI) e entrega contínua (CD) que cria, testa e implementa a aplicação.

Considerações

Estas considerações implementam os pilares do Azure Well-Architected Framework, que é um conjunto de princípios orientadores que podem ser utilizados para melhorar a qualidade de uma carga de trabalho. Para obter mais informações, veja Microsoft Azure Well-Architected Framework.

Disponibilidade

A implementação aqui apresentada reside numa única região do Azure. Para uma abordagem mais resiliente à recuperação após desastre, tire partido das funcionalidades de distribuição geográfica nos vários serviços:

  • os Hubs de Eventos. Crie dois espaços de nomes dos Hubs de Eventos, um espaço de nomes primário (ativo) e um espaço de nomes secundário (passivo). As mensagens são automaticamente encaminhadas para o espaço de nomes ativo, a menos que efetue a ativação pós-falha para o espaço de nomes secundário. Para obter mais informações, veja Hubs de Eventos do Azure Recuperação após desastre geográfico.
  • Aplicação de Funções. Implemente uma segunda aplicação de funções que está à espera de ler a partir do espaço de nomes secundário dos Hubs de Eventos. Esta função escreve numa conta de armazenamento secundária para uma fila de mensagens não entregues.
  • Azure Cosmos DB. O Azure Cosmos DB suporta várias regiões de escrita, o que permite escrever em qualquer região que adicione à sua conta do Azure Cosmos DB. Se não ativar várias escritas, pode continuar a efetuar a ativação pós-falha na região de escrita primária. Os SDKs de cliente do Azure Cosmos DB e os enlaces da Função do Azure processam automaticamente a ativação pós-falha, pelo que não precisa de atualizar as definições de configuração da aplicação.
  • Armazenamento do Azure. Utilize o armazenamento RA-GRS para a fila de mensagens não entregues. Esta ação cria uma réplica só de leitura noutra região. Se a região primária ficar indisponível, pode ler os itens atualmente na fila. Além disso, aprovisione outra conta de armazenamento na região secundária na qual a função pode escrever após uma ativação pós-falha.

Escalabilidade

Hubs de Eventos

A capacidade de débito dos Hubs de Eventos é medida em unidades de débito. Pode dimensionar automaticamente um hub de eventos ao ativar a inflação automática, que dimensiona automaticamente as unidades de débito com base no tráfego, até um máximo configurado.

O acionador dos Hubs de Eventos na aplicação de funções é dimensionado de acordo com o número de partições no hub de eventos. É atribuída uma instância de função de cada vez a cada partição. Para maximizar o débito, receba os eventos num lote, em vez de um de cada vez.

Azure Cosmos DB

O Azure Cosmos DB está disponível em dois modos de capacidade diferentes:

  • Sem servidor, para cargas de trabalho com tráfego intermitente ou imprevisível e taxa de tráfego média/pico baixa.
  • Débito aprovisionado para cargas de trabalho com tráfego sustentado que requer um desempenho previsível.

Para garantir que a carga de trabalho é dimensionável, é importante escolher uma chave de partição adequada quando criar os contentores do Azure Cosmos DB. Seguem-se algumas características de uma boa chave de partição:

  • O espaço de valor da chave é grande.
  • Haverá uma distribuição uniforme de leituras/escritas por valor de chave, evitando teclas de atalho.
  • Os dados máximos armazenados para qualquer valor de chave única não excederão o tamanho máximo da partição física (20 GB).
  • A chave de partição de um documento não será alterada. Não pode atualizar a chave de partição num documento existente.

No cenário desta arquitetura de referência, a função armazena exatamente um documento por dispositivo que está a enviar dados. A função atualiza continuamente os documentos com o estado mais recente do dispositivo através de uma operação upsert. O ID do Dispositivo é uma boa chave de partição para este cenário, porque as escritas serão distribuídas uniformemente pelas chaves e o tamanho de cada partição será estritamente vinculado porque existe um único documento para cada valor de chave. Para obter mais informações sobre chaves de partição, veja Partição e dimensionamento no Azure Cosmos DB.

Resiliência

Ao utilizar o acionador dos Hubs de Eventos com As Funções, detete exceções no ciclo de processamento. Se ocorrer uma exceção não processada, o runtime das Funções não repetirá as mensagens. Se não for possível processar uma mensagem, coloque a mensagem numa fila de mensagens não entregues. Utilize um processo fora de banda para examinar as mensagens e determinar a ação corretiva.

O código seguinte mostra como a função de ingestão deteta exceções e coloca mensagens não processadas numa fila de mensagens não entregues.

[FunctionName("RawTelemetryFunction")]
[StorageAccount("DeadLetterStorage")]
public static async Task RunAsync(
    [EventHubTrigger("%EventHubName%", Connection = "EventHubConnection", ConsumerGroup ="%EventHubConsumerGroup%")]EventData[] messages,
    [Queue("deadletterqueue")] IAsyncCollector<DeadLetterMessage> deadLetterMessages,
    ILogger logger)
{
    foreach (var message in messages)
    {
        DeviceState deviceState = null;

        try
        {
            deviceState = telemetryProcessor.Deserialize(message.Body.Array, logger);
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Error deserializing message", message.SystemProperties.PartitionKey, message.SystemProperties.SequenceNumber);
            await deadLetterMessages.AddAsync(new DeadLetterMessage { Issue = ex.Message, EventData = message });
        }

        try
        {
            await stateChangeProcessor.UpdateState(deviceState, logger);
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "Error updating status document", deviceState);
            await deadLetterMessages.AddAsync(new DeadLetterMessage { Issue = ex.Message, EventData = message, DeviceState = deviceState });
        }
    }
}

Repare que a função utiliza o enlace de saída do Armazenamento de filas para colocar itens na fila.

O código mostrado também regista exceções no Application Insights. Pode utilizar a chave de partição e o número de sequência para correlacionar as mensagens não entregues com as exceções nos registos.

As mensagens na fila de mensagens não entregues devem ter informações suficientes para que possa compreender o contexto do erro. Neste exemplo, a DeadLetterMessage classe contém a mensagem de exceção, os dados de evento originais e a mensagem de evento serializado sem serialização (se disponível).

public class DeadLetterMessage
{
    public string Issue { get; set; }
    public EventData EventData { get; set; }
    public DeviceState DeviceState { get; set; }
}

Utilize o Azure Monitor para monitorizar o hub de eventos. Se vir que existem entradas, mas não existem saídas, significa que as mensagens não estão a ser processadas. Nesse caso, aceda ao Log Analytics e procure exceções ou outros erros.

DevOps

Utilize a infraestrutura como código (IaC) sempre que possível. A IaC gere a infraestrutura, a aplicação e os recursos de armazenamento com uma abordagem declarativa, como o Azure Resource Manager. Isto ajudará a automatizar a implementação com o DevOps como uma solução de integração contínua e entrega contínua (CI/CD). Os modelos devem ser versões e incluídos como parte do pipeline de versão.

Ao criar modelos, agrupe recursos como forma de os organizar e isolar por carga de trabalho. Uma forma comum de pensar na carga de trabalho é uma única aplicação sem servidor ou uma rede virtual. O objetivo do isolamento da carga de trabalho é associar os recursos a uma equipa, para que a equipa do DevOps possa gerir de forma independente todos os aspetos desses recursos e executar CI/CD.

Esta arquitetura inclui passos para configurar a Aplicação de Funções de Estado do Drone com pipelines do Azure com YAML e blocos de Funções do Azure.

À medida que implementa os seus serviços, terá de monitorizá-los. Considere utilizar o Application Insights para permitir que os programadores monitorizem o desempenho e detetem problemas.

Para obter mais informações, veja a lista de verificação de DevOps.

Recuperação após desastre

A implementação aqui apresentada reside numa única região do Azure. Para uma abordagem mais resiliente à recuperação após desastre, tire partido das funcionalidades de distribuição geográfica nos vários serviços:

  • Hubs de Eventos. Crie dois espaços de nomes dos Hubs de Eventos, um espaço de nomes primário (ativo) e um espaço de nomes secundário (passivo). As mensagens são automaticamente encaminhadas para o espaço de nomes ativo, a menos que faça a ativação pós-falha para o espaço de nomes secundário. Para obter mais informações, veja Hubs de Eventos do Azure Recuperação após desastre geográfico.

  • Aplicação de Funções. Implemente uma segunda aplicação de funções que esteja à espera de ler a partir do espaço de nomes dos Hubs de Eventos secundários. Esta função escreve numa conta de armazenamento secundária para a fila de letras não entregues.

  • Azure Cosmos DB. O Azure Cosmos DB suporta várias regiões de escrita, o que permite escritas em qualquer região que adicione à sua conta do Azure Cosmos DB. Se não ativar várias escritas, pode continuar a efetuar a ativação pós-falha da região de escrita primária. Os SDKs de cliente do Azure Cosmos DB e os enlaces da Função do Azure processam automaticamente a ativação pós-falha, pelo que não precisa de atualizar as definições de configuração da aplicação.

  • Armazenamento do Azure. Utilize o armazenamento RA-GRS para a fila de letras não entregues. Esta ação cria uma réplica só de leitura noutra região. Se a região primária ficar indisponível, pode ler os itens atualmente na fila. Além disso, aprovisione outra conta de armazenamento na região secundária na qual a função pode escrever após uma ativação pós-falha.

Otimização de custos

A otimização de custos consiste em analisar formas de reduzir as despesas desnecessárias e melhorar a eficiência operacional. Para obter mais informações, veja Descrição geral do pilar de otimização de custos.

Utilize a calculadora de preços do Azure para estimar os custos. Seguem-se outras considerações sobre Funções do Azure e o Azure Cosmos DB.

Funções do Azure

Funções do Azure suporta dois modelos de alojamento:

  • Plano de consumo. O poder de computação é alocado automaticamente quando o código está em execução.
  • Serviço de Aplicações plano. É atribuído um conjunto de máquinas virtuais (VMs) ao seu código. O plano Serviço de Aplicações define o número de VMs e o tamanho da VM.

Nesta arquitetura, cada evento que chega aos Hubs de Eventos aciona uma função que processa esse evento. Do ponto de vista dos custos, a recomendação é utilizar o plano de consumo porque paga apenas pelos recursos de computação que utiliza.

Azure Cosmos DB

Com o Azure Cosmos DB, paga pelas operações que realiza na base de dados e pelo armazenamento consumido pelos seus dados.

  • Operações de base de dados. A forma como é cobrado pelas operações da base de dados depende do tipo de conta do Azure Cosmos DB que está a utilizar.
    • No modo sem servidor, não tem de aprovisionar qualquer débito ao criar recursos na sua conta do Azure Cosmos DB. No final do período de faturação, é faturado a quantidade de Unidades de Pedido consumidas pelas operações da base de dados.
    • No modo de débito aprovisionado , especifica o débito de que precisa em Unidades de Pedido por segundo (RU/s) e é faturado por hora para o débito máximo aprovisionado durante uma determinada hora. Nota: Uma vez que o modelo de débito aprovisionado dedica recursos ao contentor ou à base de dados, ser-lhe-á cobrado o débito que aprovisionou, mesmo que não execute cargas de trabalho.
  • Armazenamento. É-lhe cobrada uma taxa fixa para a quantidade total de armazenamento (em GBs) consumida pelos seus dados e índices durante uma determinada hora.

Nesta arquitetura de referência, a função armazena exatamente um documento por dispositivo que está a enviar dados. A função atualiza continuamente os documentos com o estado mais recente do dispositivo, utilizando uma operação upsert, que é rentável em termos de armazenamento consumido. Para obter mais informações, veja Modelo de preços do Azure Cosmos DB.

Utilize a calculadora de capacidade do Azure Cosmos DB para obter uma estimativa rápida do custo da carga de trabalho.

Implementar este cenário

Logótipo do GitHub Está disponível uma implementação de referência para esta arquitetura no GitHub.

Passos seguintes