Stefan Sørensen

Cloud Architekt

Software Architekt

Stefan Sørensen

Cloud Architekt

Software Architekt

Blog Beitrag

Event Driven Architecture mit Azure Event Grid

7. November 2024 Cloud-Architektur

Ausgangssituation

Sarah möchte eine skalierbare und eventgesteuerte Architektur für ein E-Commerce-System aufbauen, das mehrere Services integriert. Das Ziel ist es, sicherzustellen, dass das System flexibel, wartbar und skalierbar ist. Das System soll auch auf verschiedene Ereignisse wie Bestellungen, Zahlungen und Lagerbestände in Echtzeit reagieren. Eine Einleitung zu dem Thema haben wir in meinem Blog Artikel zu Grundlagen der Event Driven Architecture bereits kennengelernt, jetzt geht es mit Azure Event Grid und Azure Fuctions statt Python weiter.

Schritt 1: Definition der Events und Microservices

Zuerst definiert Sarah die wichtigsten Ereignisse und die zugehörigen Microservices. Die EDA verfolgt das Prinzip, dass jeder Service sich auf ein Ereignis (Event) konzentriert und dieses verarbeitet, ohne direkt mit anderen Services verbunden zu sein.

Beispiele für Events:

  1. OrderPlaced: Wenn ein Kunde eine Bestellung aufgibt.
  2. PaymentProcessed: Wenn die Zahlung für eine Bestellung erfolgreich war.
  3. InventoryUpdated: Wenn der Lagerbestand angepasst werden muss.
  4. OrderShipped: Wenn die Bestellung versandt wurde.

Zu diesen Events werden Microservices zugeordnet:

  • Order Service: Verarbeitet Bestellungen und erstellt neue Bestellaufträge.
  • Payment Service: Bearbeitet die Zahlungen für Bestellungen.
  • Inventory Service: Verwaltet den Lagerbestand der Produkte.
  • Shipping Service: Koordiniert den Versand und den Tracking-Status von Bestellungen.

Schritt 2: Architektur-Setup mit Azure Services

Sarah entscheidet sich für Azure-Dienste, die das Event-Driven Pattern unterstützen. Die folgende Architektur stellt das Kern-EDA-Setup dar:

  1. Azure Event Grid: Als zentrale Eventing-Plattform für das E-Commerce-System. Alle Events werden über Event Grid verteilt, wodurch Microservices auf die für sie relevanten Events reagieren können.
  2. Azure Functions: Sarah nutzt Azure Functions, um die einzelnen Microservices leicht und serverlos zu implementieren. Jede Funktion wird dabei für ein spezifisches Event getriggert (z.B. die OrderPlaced-Function für neue Bestellungen).
  3. Azure Service Bus: Für die Kommunikation zwischen Services, die zusätzliche Verlässlichkeit und Warteschlangen benötigen (z.B. für das Payment- und Shipping-System).
  4. Azure Cosmos DB: Sarah entscheidet sich für Cosmos DB als Datenbank, um global verteilte Daten und Zustandsinformationen über Bestellungen, Zahlungen und Lagerbestände zu speichern.
  5. Azure Logic Apps: Logic Apps helfen dabei, komplexere Workflows zu orchestrieren, z.B. für die Abwicklung eines Bestellvorgangs (Zahlung und Versand), wenn mehrere Events und Services beteiligt sind.

Schritt 3: EDA Workflow

Hier ist ein Überblick, wie der Workflow in der EDA-Umgebung abläuft:

  1. Order Placement:
  • Wenn eine Bestellung im System aufgegeben wird, erstellt der Order Service ein OrderPlaced-Event und sendet es an Azure Event Grid.
  • Das OrderPlaced-Event triggert den Inventory Service, der den Lagerbestand aktualisiert und das InventoryUpdated-Event veröffentlicht.
  1. Payment Processing:
  • Nach dem Lagerbestandstrigger wird der Payment Service über Event Grid über das OrderPlaced-Event informiert.
  • Der Payment Service führt die Zahlung durch und veröffentlicht ein PaymentProcessed-Event. Wenn die Zahlung fehlschlägt, wird ein PaymentFailed-Event erzeugt und an den Order Service weitergeleitet, um die Bestellung abzubrechen.
  1. Order Shipping:
  • Nach erfolgreicher Zahlung sendet der Shipping Service ein OrderShipped-Event und benachrichtigt den Kunden.
  • Alle Events werden in Cosmos DB protokolliert, sodass der Status der Bestellung jederzeit nachvollzogen werden kann.

Schritt 4: Überwachung und Skalierung

Sarah nutzt Azure Monitor und Application Insights, um die EDA-Komponenten in Echtzeit zu überwachen. Eventuelle Fehler oder Verzögerungen in den Prozessen werden damit sichtbar. Zusätzlich skaliert Azure Functions automatisch basierend auf der Ereignislast, was bei Verkaufsspitzen besonders nützlich ist.

Vorteile dieser Architektur

  • Flexibilität: Die Services sind entkoppelt und können unabhängig voneinander entwickelt und bereitgestellt werden.
  • Skalierbarkeit: Durch die Nutzung von Azure Functions und Event Grid ist das System hoch skalierbar und flexibel.
  • Echtzeitreaktion: Ereignisse können in Echtzeit verarbeitet werden, was besonders bei wichtigen Geschäftsvorgängen wie Bestellungen und Zahlungen von Vorteil ist.

Fazit

Sarah hat mit Azure und einer Event-Driven Architecture ein skalierbares und wartbares System für den E-Commerce-Bereich geschaffen. Die Implementierung ermöglicht eine schnelle Reaktion auf Ereignisse und bietet eine hohe Flexibilität bei der Weiterentwicklung des Systems.

Beispiel in Azure Event Grid und Azure Functions

Für dieses Beispiel erstellen wir drei Events: OrderPlaced, PaymentProcessed und OrderShipped. Wir verwenden ausschließlich Azure Event Grid und Azure Functions, weitere Services setzen wir nicht ein um das Beispiel einfach zu halten.

Vorbereitung

Voraussetzungen:

  1. Ein Azure-Konto.
  2. Azure CLI installiert.
  3. Visual Studio Code mit der Azure Functions-Erweiterung oder Azure Functions Core Tools installiert.

Hinweis: Stellen Sie sicher, dass Sie die CLI-Befehle in der Azure Cloud Shell oder im lokalen Terminal ausführen können.

Schritt 1: Azure Event Grid Topic Erstellen

Erstellen Sie ein Event Grid Topic, um Ihre Ereignisse zu veröffentlichen und an die jeweiligen Azure Functions zu verteilen.

# Setzen Sie die Variablen
$RESOURCE_GROUP="sarah-ecommerce-rg"
$LOCATION="westeurope"
$EVENT_GRID_TOPIC_NAME="sarahOrderEventsTopic"

# Erstellen Sie eine Ressourcengruppe
az group create --name $RESOURCE_GROUP --location $LOCATION

# Erstellen Sie ein Event Grid Topic
az eventgrid topic create --name $EVENT_GRID_TOPIC_NAME --resource-group $RESOURCE_GROUP --location $LOCATION

Notieren Sie sich die ID des Event Grid Topics, da Sie diese für die Konfiguration der Functions benötigen.

Schritt 2: Azure Functions für jedes Event Erstellen

Erstellen Sie drei Azure Functions: OrderPlacedFunction, PaymentProcessedFunction und OrderShippedFunction.

Funktion OrderPlacedFunction

  1. Erstellen Sie eine neue Funktion:
   func init OrderPlacedFunction --dotnet
   cd OrderPlacedFunction
   func new --template "EventGridTrigger" --name OrderPlacedFunction
  1. Code für OrderPlacedFunction (Datei: OrderPlacedFunction.cs):
   using System;
   using Microsoft.Azure.WebJobs;
   using Microsoft.Azure.WebJobs.Extensions.EventGrid;
   using Microsoft.Extensions.Logging;
   using Newtonsoft.Json.Linq;

   public static class OrderPlacedFunction
   {
       [FunctionName("OrderPlacedFunction")]
       public static void Run([EventGridTrigger] JObject eventGridEvent, ILogger log)
       {
           log.LogInformation($"OrderPlaced event received: {eventGridEvent}");
           // Logik zum Verarbeiten des OrderPlaced-Events
           // Zum Beispiel: Sende das Event "PaymentProcessed" an Event Grid
           var paymentProcessedEvent = new { EventType = "PaymentProcessed", Data = new { OrderId = eventGridEvent["data"]["OrderId"] } };
           // Hier wäre die Integration des Event Grid SDK zum Publizieren des Events erforderlich
       }
   }

Hinweis: Diese Funktion empfängt das OrderPlaced-Event und erzeugt das PaymentProcessed-Event (dieses senden Sie später über das Event Grid SDK).

Funktion PaymentProcessedFunction

  1. Neue Funktion erstellen:
   cd ..
   func init PaymentProcessedFunction --dotnet
   cd PaymentProcessedFunction
   func new --template "EventGridTrigger" --name PaymentProcessedFunction
  1. Code für PaymentProcessedFunction (Datei: PaymentProcessedFunction.cs):
   using System;
   using Microsoft.Azure.WebJobs;
   using Microsoft.Azure.WebJobs.Extensions.EventGrid;
   using Microsoft.Extensions.Logging;
   using Newtonsoft.Json.Linq;

   public static class PaymentProcessedFunction
   {
       [FunctionName("PaymentProcessedFunction")]
       public static void Run([EventGridTrigger] JObject eventGridEvent, ILogger log)
       {
           log.LogInformation($"PaymentProcessed event received: {eventGridEvent}");
           // Logik zum Verarbeiten des PaymentProcessed-Events
           // Zum Beispiel: Sende das Event "OrderShipped" an Event Grid
           var orderShippedEvent = new { EventType = "OrderShipped", Data = new { OrderId = eventGridEvent["data"]["OrderId"] } };
           // Hier wäre die Integration des Event Grid SDK zum Publizieren des Events erforderlich
       }
   }

Funktion OrderShippedFunction

  1. Neue Funktion erstellen:
   cd ..
   func init OrderShippedFunction --dotnet
   cd OrderShippedFunction
   func new --template "EventGridTrigger" --name OrderShippedFunction
  1. Code für OrderShippedFunction (Datei: OrderShippedFunction.cs):
   using System;
   using Microsoft.Azure.WebJobs;
   using Microsoft.Azure.WebJobs.Extensions.EventGrid;
   using Microsoft.Extensions.Logging;
   using Newtonsoft.Json.Linq;

   public static class OrderShippedFunction
   {
       [FunctionName("OrderShippedFunction")]
       public static void Run([EventGridTrigger] JObject eventGridEvent, ILogger log)
       {
           log.LogInformation($"OrderShipped event received: {eventGridEvent}");
           // Logik zur Benachrichtigung des Kunden, dass die Bestellung versandt wurde
       }
   }

Schritt 3: Deployment und Konfiguration der Functions

  1. Deployen Sie jede Funktion auf Azure:
   # Deploy OrderPlacedFunction
   cd OrderPlacedFunction
   az storage account create --name orderplacestorage --location westeurope --resource-group sarah-ecommerce-rg --sku Standard_LRS
   az functionapp create --resource-group sarah-ecommerce-rg --consumption-plan-location westeurope --runtime dotnet --functions-version 4 --name OrderPlacedFunction --storage-account orderplacestorage
   func azure functionapp publish OrderPlacedFunction

   # Deploy PaymentProcessedFunction
   cd PaymentProcessedFunction
   az storage account create --name paymentprocessedstorage --location westeurope --resource-group sarah-ecommerce-rg --sku Standard_LRS
   az functionapp create --resource-group sarah-ecommerce-rg --consumption-plan-location westeurope --runtime dotnet --functions-version 4 --name PaymentProcessedFunction --storage-account paymentprocessedstorage
   func azure functionapp publish PaymentProcessedFunction

   # Deploy OrderShippedFunction
   cd OrderShippedFunction
   az storage account create --name ordershippedstorage --location westeurope --resource-group sarah-ecommerce-rg --sku Standard_LRS
   az functionapp create --resource-group sarah-ecommerce-rg --consumption-plan-location westeurope --runtime dotnet --functions-version 4 --name OrderShippedFunction --storage-account ordershippedstorage
   func azure functionapp publish OrderShippedFunction
  1. Event Grid Subscriptions einrichten: Verbinden Sie die Azure Functions mit dem Event Grid Topic, damit die Events korrekt weitergeleitet werden.
   # OrderPlaced -> PaymentProcessed
   az eventgrid event-subscription create \
       --source-resource-id /subscriptions/{subscription-id}/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.EventGrid/topics/$EVENT_GRID_TOPIC_NAME \
       --name PaymentProcessedSubscription \
       --endpoint https://<OrderPlacedFunction-URL>.azurewebsites.net/runtime/webhooks/eventgrid

   # PaymentProcessed -> OrderShipped
   az eventgrid event-subscription create \
       --source-resource-id /subscriptions/{subscription-id}/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.EventGrid/topics/$EVENT_GRID_TOPIC_NAME \
       --name OrderShippedSubscription \
       --endpoint https://<PaymentProcessedFunction-URL>.azurewebsites.net/runtime/webhooks/eventgrid

Schritt 4: Testen

Um die Event Chain zu testen, können Sie mit einem Testevent (OrderPlaced) starten, indem Sie es an das Event Grid Topic senden:

az eventgrid event create --resource-id /subscriptions/{subscription-id}/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.EventGrid/topics/$EVENT_GRID_TOPIC_NAME --subject "OrderPlaced" --event-type "OrderPlaced" --data "{ 'OrderId': '1234' }" --data-version 1.0

Prüfen Sie die Logs jeder Funktion in Azure, um sicherzustellen, dass die Events ordnungsgemäß empfangen und verarbeitet werden.

Alternativ lässt sich über CURL testen:

Alternative: Verwenden von curl oder Invoke-RestMethod (PowerShell)

Da die Azure CLI keinen Befehl zum Erstellen eines Ereignisses unterstützt, können Sie ein Ereignis mit einem HTTP-POST senden. Die Endpunkt-URL für ein Event Grid Topic hat das folgende Format:

https://<EVENT_GRID_TOPIC_NAME>.<region>-1.eventgrid.azure.net/api/events

Schritt-für-Schritt-Anleitung

  1. Erhalten Sie den Zugriffsschlüssel des Event Grid Topics Sie benötigen den Zugriffsschlüssel, um das Ereignis an das Event Grid Topic zu senden.
   az eventgrid topic key list --name $EVENT_GRID_TOPIC_NAME --resource-group $RESOURCE_GROUP

Kopieren Sie den angezeigten Schlüssel.

  1. Senden Sie das Ereignis mit curl Ersetzen Sie <EVENT_GRID_TOPIC_KEY> und <EVENT_GRID_TOPIC_ENDPOINT> durch den oben erstellten Schlüssel und den entsprechenden Endpunkt.
   curl -X POST -H "aeg-sas-key: <EVENT_GRID_TOPIC_KEY>" -H "Content-Type: application/json" -d '[{
     "id": "1234",
     "subject": "OrderPlaced",
     "data": { "OrderId": "1234" },
     "eventType": "OrderPlaced",
     "eventTime": "'"$(date -u +"%Y-%m-%dT%H:%M:%SZ")"'",
     "dataVersion": "1.0"
   }]' <EVENT_GRID_TOPIC_ENDPOINT>
  • id: Eine eindeutige ID für das Ereignis.
  • subject: Ein Betreff für das Ereignis.
  • data: Der Datenteil des Ereignisses. Sie können hier JSON-Daten einfügen.
  • eventType: Der Ereignistyp (z.B., OrderPlaced).
  • eventTime: Der Zeitpunkt des Ereignisses.
  • dataVersion: Die Version der Daten, z.B., "1.0".
  1. PowerShell-Alternative: Invoke-RestMethod Falls Sie PowerShell verwenden, können Sie Invoke-RestMethod nutzen:
   $eventGridTopicKey = "<EVENT_GRID_TOPIC_KEY>"
   $eventGridTopicEndpoint = "<EVENT_GRID_TOPIC_ENDPOINT>"

   $headers = @{
       "aeg-sas-key" = $eventGridTopicKey
       "Content-Type" = "application/json"
   }

   $event = @(
       @{
           id = "1234"
           subject = "OrderPlaced"
           data = @{
               OrderId = "1234"
           }
           eventType = "OrderPlaced"
           eventTime = (Get-Date).ToUniversalTime().ToString("o")
           dataVersion = "1.0"
       }
   ) | ConvertTo-Json

   Invoke-RestMethod -Uri $eventGridTopicEndpoint -Method Post -Headers $headers -Body $event

Diese Anfragen senden das Ereignis an Ihr Event Grid Topic und sollten die Funktion auslösen, die auf OrderPlaced-Ereignisse wartet.

Das Setup ist abgeschlossen. Diese Architektur ermöglicht es Sarah, Events nur über Azure Event Grid und Azure Functions zu verwalten.

Tags:
Related Posts
Event-Driven Architecture: Die Architektur, die auf Ereignisse reagiert und Systeme transformiert

Wie Sarahs Unternehmen mit Event-Driven Architecture (EDA) effizienter, schneller und anpassungsfähiger wurde Sarah saß in ihrem Büro und starrte auf…