Serverlös händelsebearbetning

Azure Cosmos DB
Azure Functions
Azure Monitor
Azure Pipelines
Azure Storage

Den här referensarkitekturen visar en serverlös, händelsedriven arkitektur som matar in en dataström, bearbetar data och skriver resultatet till en serverdelsdatabas.

Arkitektur

Diagram som visar en referensarkitektur för serverlös händelsebearbetning med Hjälp av Azure Functions.

Arbetsflöde

  • Händelser kommer till Azure Event Hubs.
  • En funktionsapp utlöses för att hantera händelsen.
  • Händelsen lagras i en Azure Cosmos DB-databas.
  • Om funktionsappen inte kan lagra händelsen sparas händelsen i en lagringskö som ska bearbetas senare.

Komponenter

  • Event Hubs matar in dataströmmen. Event Hubs är utformat för dataströmningsscenarier med högt dataflöde.

    Kommentar

    För IoT-scenarier (Internet of Things) rekommenderar vi Azure IoT Hub. IoT Hub har en inbyggd slutpunkt som är kompatibel med Azure Event Hubs-API:et, så du kan använda någon av tjänsterna i den här arkitekturen utan större ändringar i serverdelsbearbetningen. Mer information finns i Anslut ing IoT-enheter till Azure: IoT Hub och Event Hubs.

  • Funktionsapp. Azure Functions är ett serverlöst beräkningsalternativ. Den använder en händelsedriven modell, där en koddel (en funktion) anropas av en utlösare. När händelser kommer till Event Hubs i den här arkitekturen utlöser de en funktion som bearbetar händelserna och skriver resultatet till lagringen.

    Funktionsappar är lämpliga för bearbetning av enskilda poster från Event Hubs. För mer komplexa scenarier för dataströmbearbetning kan du överväga Apache Spark med Hjälp av Azure Databricks eller Azure Stream Analytics.

  • Azure Cosmos DB. Azure Cosmos DB är en databastjänst med flera modeller som är tillgänglig i ett serverlöst, förbrukningsbaserat läge. I det här scenariot lagrar händelsebearbetningsfunktionen JSON-poster med hjälp av Azure Cosmos DB för NoSQL.

  • Kölagring. Kölagring används för meddelanden med obeställbara meddelanden. Om ett fel inträffar när en händelse bearbetas lagrar funktionen händelsedata i en kö med obeställbara meddelanden för senare bearbetning. Mer information finns i avsnittet Återhämtning senare i den här artikeln.

  • Azure Monitor. Monitor samlar in prestandamått om de Azure-tjänster som distribueras i lösningen. Genom att visualisera dessa på en instrumentpanel kan du få insyn i lösningens hälsotillstånd.

  • Azure Pipelines. Pipelines är en tjänst för kontinuerlig integrering (CI) och kontinuerlig leverans (CD) som skapar, testar och distribuerar programmet.

Att tänka på

Dessa överväganden implementerar grundpelarna i Azure Well-Architected Framework, som är en uppsättning vägledande grundsatser som kan användas för att förbättra kvaliteten på en arbetsbelastning. Mer information finns i Microsoft Azure Well-Architected Framework.

Tillgänglighet

Distributionen som visas här finns i en enda Azure-region. Om du vill ha en mer flexibel metod för haveriberedskap kan du dra nytta av geo-distributionsfunktioner i de olika tjänsterna:

  • Event Hubs. Skapa två Event Hubs-namnområden, ett primärt (aktivt) namnområde och ett sekundärt (passivt) namnområde. Meddelanden dirigeras automatiskt till det aktiva namnområdet om du inte redundansväxlar till det sekundära namnområdet. Mer information finns i Geo-haveriberedskap för Azure Event Hubs.
  • Funktionsapp. Distribuera en andra funktionsapp som väntar på att läsa från det sekundära Event Hubs-namnområdet. Den här funktionen skriver till ett sekundärt lagringskonto för en kö med obeställbara meddelanden.
  • Azure Cosmos DB. Azure Cosmos DB stöder flera skrivregioner, vilket gör det möjligt att skriva till alla regioner som du lägger till i ditt Azure Cosmos DB-konto. Om du inte aktiverar flera skrivningar kan du fortfarande redundansväxla den primära skrivregionen. Azure Cosmos DB-klient-SDK:er och Azure-funktionsbindningar hanterar automatiskt redundansen, så du behöver inte uppdatera några inställningar för programkonfiguration.
  • Azure Storage. Använd RA-GRS-lagring för kön med obeställbara meddelanden. Detta skapar en skrivskyddad replik i en annan region. Om den primära regionen blir otillgänglig kan du läsa de objekt som för närvarande finns i kön. Dessutom etablerar du ett annat lagringskonto i den sekundära regionen som funktionen kan skriva till efter en redundansväxling.

Skalbarhet

Event Hubs

Dataflödeskapaciteten för Event Hubs mäts i dataflödesenheter. Du kan autoskala en händelsehubb genom att aktivera automatisk blåsning, vilket automatiskt skalar dataflödesenheterna baserat på trafik, upp till ett konfigurerat maxvärde.

Event Hubs-utlösaren i funktionsappen skalas enligt antalet partitioner i händelsehubben. Varje partition tilldelas en funktionsinstans i taget. För att maximera dataflödet tar du emot händelserna i en batch i stället för en i taget.

Azure Cosmos DB

Azure Cosmos DB är tillgängligt i två olika kapacitetslägen:

  • Serverlös, för arbetsbelastningar med tillfällig eller oförutsägbar trafik och lågt genomsnittligt till högsta trafikförhållande.
  • Etablerat dataflöde för arbetsbelastningar med varaktig trafik som kräver förutsägbara prestanda.

För att se till att din arbetsbelastning är skalbar är det viktigt att välja en lämplig partitionsnyckel när du skapar dina Azure Cosmos DB-containrar. Här följer några egenskaper hos en bra partitionsnyckel:

  • Nyckelvärdeutrymmet är stort.
  • Det kommer att finnas en jämn fördelning av läsningar/skrivningar per nyckelvärde, vilket undviker snabbnycklar.
  • Maximalt antal data som lagras för ett enskilt nyckelvärde överskrider inte den maximala fysiska partitionsstorleken (20 GB).
  • Partitionsnyckeln för ett dokument ändras inte. Du kan inte uppdatera partitionsnyckeln i ett befintligt dokument.

I scenariot för den här referensarkitekturen lagrar funktionen exakt ett dokument per enhet som skickar data. Funktionen uppdaterar kontinuerligt dokumenten med den senaste enhetsstatusen med hjälp av en upsert-åtgärd. Enhets-ID är en bra partitionsnyckel för det här scenariot eftersom skrivningar fördelas jämnt över nycklarna och storleken på varje partition begränsas strikt eftersom det finns ett enda dokument för varje nyckelvärde. Mer information om partitionsnycklar finns i Partition och skalning i Azure Cosmos DB.

Motståndskraft

När du använder Event Hubs-utlösaren med Functions fångar du undantag i bearbetningsloopen. Om ett ohanterat undantag inträffar försöker inte Functions-körningen meddelandena igen. Om ett meddelande inte kan bearbetas placerar du meddelandet i en kö med obeställbara meddelanden. Använd en out-of-band-process för att undersöka meddelandena och fastställa korrigerande åtgärder.

Följande kod visar hur inmatningsfunktionen fångar undantag och placerar obearbetade meddelanden i en kö med obearbetade meddelanden.

 [Function(nameof(RawTelemetryFunction))]
 public async Task RunAsync([EventHubTrigger("%EventHubName%", Connection = "EventHubConnection")] EventData[] messages,
     FunctionContext context)
 {
     _telemetryClient.GetMetric("EventHubMessageBatchSize").TrackValue(messages.Length);
     DeviceState? deviceState = null;
     // Create a new CosmosClient
     var cosmosClient = new CosmosClient(Environment.GetEnvironmentVariable("COSMOSDB_CONNECTION_STRING"));

     // Get a reference to the database and the container
     var database = cosmosClient.GetDatabase(Environment.GetEnvironmentVariable("COSMOSDB_DATABASE_NAME"));
     var container = database.GetContainer(Environment.GetEnvironmentVariable("COSMOSDB_DATABASE_COL"));

     // Create a new QueueClient
     var queueClient = new QueueClient(Environment.GetEnvironmentVariable("DeadLetterStorage"), "deadletterqueue");
     await queueClient.CreateIfNotExistsAsync();

     foreach (var message in messages)
     {
         try
         {
             deviceState = _telemetryProcessor.Deserialize(message.Body.ToArray(), _logger);
             try
             {
                 // Add the device state to Cosmos DB
                 await container.UpsertItemAsync(deviceState, new PartitionKey(deviceState.DeviceId));
             }
             catch (Exception ex)
             {
                  _logger.LogError(ex, "Error saving on database", message.PartitionKey, message.SequenceNumber);
                 var deadLetterMessage = new DeadLetterMessage { Issue = ex.Message, MessageBody = message.Body.ToArray(), DeviceState = deviceState };
                 // Convert the dead letter message to a string
                 var deadLetterMessageString = JsonConvert.SerializeObject(deadLetterMessage);

                 // Send the message to the queue
                 await queueClient.SendMessageAsync(deadLetterMessageString);
             }

         }
         catch (Exception ex)
         {
             _logger.LogError(ex, "Error deserializing message", message.PartitionKey, message.SequenceNumber);
             var deadLetterMessage = new DeadLetterMessage { Issue = ex.Message, MessageBody = message.Body.ToArray(), DeviceState = deviceState };
             // Convert the dead letter message to a string
             var deadLetterMessageString = JsonConvert.SerializeObject(deadLetterMessage);

             // Send the message to the queue
             await queueClient.SendMessageAsync(deadLetterMessageString);
         }
     }
 }

Koden som visas loggar även undantag till Application Insights. Du kan använda partitionsnyckeln och sekvensnumret för att korrelera meddelanden med obeställbara meddelanden med undantagen i loggarna.

Meddelanden i kön med obeställbara meddelanden bör ha tillräckligt med information så att du kan förstå kontexten för felet. I det här exemplet DeadLetterMessage innehåller klassen undantagsmeddelandet, de ursprungliga händelsetextdata och det deserialiserade händelsemeddelandet (om tillgängligt).

    public class DeadLetterMessage
    {
        public string? Issue { get; set; }
        public byte[]? MessageBody { get; set; }
        public DeviceState? DeviceState { get; set; }
    }

Använd Azure Monitor för att övervaka händelsehubben. Om du ser att det finns indata men inga utdata innebär det att meddelanden inte bearbetas. I så fall går du till Log Analytics och letar efter undantag eller andra fel.

DevOps

Använd infrastruktur som kod (IaC) när det är möjligt. IaC hanterar infrastruktur-, program- och lagringsresurserna med en deklarativ metod som Azure Resource Manager. Det hjälper dig att automatisera distributionen med DevOps som en lösning för kontinuerlig integrering och kontinuerlig leverans (CI/CD). Mallar ska vara versionshanterade och inkluderade som en del av versionspipelinen.

När du skapar mallar grupperar du resurser som ett sätt att organisera och isolera dem per arbetsbelastning. Ett vanligt sätt att tänka på arbetsbelastning är ett enda serverlöst program eller ett virtuellt nätverk. Målet med arbetsbelastningsisolering är att associera resurserna till ett team, så att DevOps-teamet självständigt kan hantera alla aspekter av dessa resurser och utföra CI/CD.

När du distribuerar dina tjänster måste du övervaka dem. Överväg att använda Application Insights för att göra det möjligt för utvecklarna att övervaka prestanda och identifiera problem.

Mer information finns i DevOps-checklistan.

Haveriberedskap

Distributionen som visas här finns i en enda Azure-region. Om du vill ha en mer flexibel metod för haveriberedskap kan du dra nytta av geo-distributionsfunktioner i de olika tjänsterna:

  • Event Hubs. Skapa två Event Hubs-namnområden, ett primärt (aktivt) namnområde och ett sekundärt (passivt) namnområde. Meddelanden dirigeras automatiskt till det aktiva namnområdet om du inte redundansväxlar till det sekundära namnområdet. Mer information finns i Geo-haveriberedskap för Azure Event Hubs.

  • Funktionsapp. Distribuera en andra funktionsapp som väntar på att läsa från det sekundära Event Hubs-namnområdet. Den här funktionen skriver till ett sekundärt lagringskonto för kö med obeställbara meddelanden.

  • Azure Cosmos DB. Azure Cosmos DB stöder flera skrivregioner, vilket gör det möjligt att skriva till alla regioner som du lägger till i ditt Azure Cosmos DB-konto. Om du inte aktiverar flera skrivningar kan du fortfarande redundansväxla den primära skrivregionen. Azure Cosmos DB-klient-SDK:er och Azure-funktionsbindningar hanterar automatiskt redundansen, så du behöver inte uppdatera några inställningar för programkonfiguration.

  • Azure Storage. Använd RA-GRS-lagring för kön med obeställbara meddelanden. Detta skapar en skrivskyddad replik i en annan region. Om den primära regionen blir otillgänglig kan du läsa de objekt som för närvarande finns i kön. Dessutom etablerar du ett annat lagringskonto i den sekundära regionen som funktionen kan skriva till efter en redundansväxling.

Kostnadsoptimering

Kostnadsoptimering handlar om att titta på sätt att minska onödiga utgifter och förbättra drifteffektiviteten. Mer information finns i Översikt över kostnadsoptimeringspelare.

Använd Priskalkylatorn för Azure för att beräkna kostnaderna. Här följer några andra överväganden för Azure Functions och Azure Cosmos DB.

Azure Functions

Azure Functions har stöd för två värdmodeller:

  • Förbrukningsplan. Beräkningskraft allokeras automatiskt när koden körs.
  • App Service-plan. En uppsättning virtuella datorer allokeras för din kod. App Service-planen definierar antalet virtuella datorer och storleken på den virtuella datorn.

I den här arkitekturen utlöser varje händelse som kommer till Event Hubs en funktion som bearbetar händelsen. Från ett kostnadsperspektiv är rekommendationen att använda förbrukningsplanen eftersom du endast betalar för de beräkningsresurser som du använder.

Azure Cosmos DB

Med Azure Cosmos DB betalar du för de åtgärder som du utför mot databasen och för den lagring som förbrukas av dina data.

  • Databasåtgärder. Hur du debiteras för dina databasåtgärder beror på vilken typ av Azure Cosmos DB-konto du använder.
    • I serverlöst läge behöver du inte etablera något dataflöde när du skapar resurser i ditt Azure Cosmos DB-konto. I slutet av faktureringsperioden debiteras du för mängden enheter för begäranden som förbrukas av databasåtgärderna.
    • I etablerat dataflödesläge anger du det dataflöde som du behöver i enheter för begäran per sekund (RU/s) och debiteras per timme för det maximala etablerade dataflödet under en viss timme. Obs! Eftersom den etablerade dataflödesmodellen ägnar resurser åt din container eller databas debiteras du för det dataflöde som du har etablerat även om du inte kör några arbetsbelastningar.
  • Lagring. Du debiteras en fast avgift för den totala mängden lagringsutrymme (i GBs) som förbrukas av dina data och index under en viss timme.

I den här referensarkitekturen lagrar funktionen exakt ett dokument per enhet som skickar data. Funktionen uppdaterar kontinuerligt dokumenten med den senaste enhetsstatusen med hjälp av en upsert-åtgärd, vilket är kostnadseffektivt när det gäller förbrukad lagring. Mer information finns i Prismodellen för Azure Cosmos DB.

Använd Kapacitetskalkylatorn för Azure Cosmos DB för att få en snabb uppskattning av arbetsbelastningskostnaden.

Distribuera det här scenariot

GitHub-logotyp En referensimplementering för den här arkitekturen finns på GitHub.

Nästa steg