Event Driven Architecture mit Azure Event Grid
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:
- OrderPlaced: Wenn ein Kunde eine Bestellung aufgibt.
- PaymentProcessed: Wenn die Zahlung für eine Bestellung erfolgreich war.
- InventoryUpdated: Wenn der Lagerbestand angepasst werden muss.
- 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:
- 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.
- 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). - 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).
- 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.
- 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:
- Order Placement:
- Wenn eine Bestellung im System aufgegeben wird, erstellt der
Order Service
einOrderPlaced
-Event und sendet es an Azure Event Grid. - Das
OrderPlaced
-Event triggert denInventory Service
, der den Lagerbestand aktualisiert und dasInventoryUpdated
-Event veröffentlicht.
- Payment Processing:
- Nach dem Lagerbestandstrigger wird der
Payment Service
über Event Grid über dasOrderPlaced
-Event informiert. - Der
Payment Service
führt die Zahlung durch und veröffentlicht einPaymentProcessed
-Event. Wenn die Zahlung fehlschlägt, wird einPaymentFailed
-Event erzeugt und an denOrder Service
weitergeleitet, um die Bestellung abzubrechen.
- Order Shipping:
- Nach erfolgreicher Zahlung sendet der
Shipping Service
einOrderShipped
-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:
- Ein Azure-Konto.
- Azure CLI installiert.
- 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
- Erstellen Sie eine neue Funktion:
func init OrderPlacedFunction --dotnet
cd OrderPlacedFunction
func new --template "EventGridTrigger" --name OrderPlacedFunction
- 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 dasPaymentProcessed
-Event (dieses senden Sie später über das Event Grid SDK).
Funktion PaymentProcessedFunction
- Neue Funktion erstellen:
cd ..
func init PaymentProcessedFunction --dotnet
cd PaymentProcessedFunction
func new --template "EventGridTrigger" --name PaymentProcessedFunction
- 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
- Neue Funktion erstellen:
cd ..
func init OrderShippedFunction --dotnet
cd OrderShippedFunction
func new --template "EventGridTrigger" --name OrderShippedFunction
- 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
- 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
- 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
- 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.
- 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"
.
- PowerShell-Alternative:
Invoke-RestMethod
Falls Sie PowerShell verwenden, können SieInvoke-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.
Wie Sarahs Unternehmen mit Event-Driven Architecture (EDA) effizienter, schneller und anpassungsfähiger wurde Sarah saß in ihrem Büro und starrte auf…