Bearbeiten

Share via


Gridwich-Vorgänge für Azure Storage

Azure Storage

Der Gridwich-Azure-Speicherdienst, Gridwich.SagaParticipants.Storage.AzureStorage, stellt Blob- und Containervorgänge für Azure-Speicherkonten bereit, die für Gridwich konfiguriert sind. Beispiele für Speichervorgänge sind Blob erstellen, Container löschen, Blob kopieren oder Speicherebene ändern.

In Gridwich müssen die Speichermechanismen sowohl für Azure Storage-Blockblobs als auch für Container funktionieren. Dank unterschiedlicher Klassen und Speicherdienstvorgänge für Blobs und Container steht stets eindeutig fest, ob sich ein bestimmter Speichervorgang auf ein Blob oder auf einen Container bezieht. Sofern nicht anders angegeben, bezieht sich dieser Artikel sowohl auf Blobs als auch auf Container.

Gridwich macht die meisten Speichervorgänge für externe Systeme innerhalb des Storage.AzureStorageSagateilnehmers verfügbar. Andere Sagateilnehmer verwenden den Speicherdienst für Aufgaben wie das Kopieren von Blobs zwischen verschiedenen Containern oder Konten, wenn sie Codierungsworkflows einrichten.

In diesem Artikel wird beschrieben, wie der Gridwich-Azure-Speicherdienst die Lösungsanforderungen erfüllt und in Mechanismen wie Ereignishandler integriert ist. Links verweisen auf den entsprechenden Quellcode, der ausführlichere Kommentare zu den Containern, Klassen und Mechanismen enthält.

Azure Storage SDK

Gridwich erstellt keine eigenständigen REST-Anforderungen, sondern verwendet für die Interaktion mit Azure Storage Klassen aus dem Azure Storage SDK. Innerhalb des Speicheranbieters werden Speicheranforderungen von den SDK-Klassen BlobBaseClient und BlobContainerClient verwaltet.

Diese SDK-Clientklassen erlauben derzeit nur den indirekten Zugriff auf die beiden HTTP-Header, die von Gridwich bearbeitet werden müssen, x-ms-client-request-id für den Vorgangskontext und ETag für die Objektversion.

In Gridwich gibt ein Anbieterklassenpaar die Funktionen BlobBaseClientProvider und BlobContainerClientProvider in Einheiten aus, die als Sleeves bezeichnet werden. Ausführliche Informationen zu Sleeves finden Sie unter Speicher-Sleeves.

Das folgende Diagramm zeigt die Struktur der SDK- und Gridwich-Klassen sowie die Beziehung zwischen Instanzen. Die Pfeile bedeuten dabei „verfügt über einen Verweis auf“.

Diagram showing client object instance relationships between the Storage SDK classes.

Pipelinerichtlinie

Beim Erstellen der Clientinstanz legen Sie den Hook so fest, dass die HTTP-Header als Pipelinerichtlinieninstanz bearbeitet werden. Sie können diese Richtlinie nur zum Zeitpunkt der Erstellung der Clientinstanz festlegen und sie später nicht mehr ändern. Der Speicheranbietercode, der den Client verwendet, muss die Headerwerte während der Ausführung bearbeiten können. Die Herausforderung besteht darin sicherzustellen, dass der Speicheranbieter und die Pipeline ordnungsgemäß miteinander interagieren.

Beachten Sie für Informationen zur Gridwich-Pipelinerichtlinie die BlobClientPipelinePolicy-Klasse.

Zwischenspeichern von Speicherdiensten

TCP-Verbindungsaufbau und -Authentifizierung generieren einen Mehraufwand, wenn eine SDK-Clientobjektinstanz ihre erste Anforderung an Azure Storage sendet. Mehrere Aufrufe desselben Blobs in einer externen Systemanforderung, wie z. B. Metadaten abrufen und anschließend Blob löschen, verstärken den Mehraufwand.

Um den Mehraufwand zu verringern, verwaltet Gridwich für jeden Speicherblob oder Container einen Cache einer Clientinstanz, je nach den SDK-Klassen, die der Vorgangskontext verwendet. Gridwich behält diese Clientinstanz bei und kann sie für die Dauer einer externen Systemanforderung für mehrere Azure-Speichervorgänge mit demselben Blob oder Container verwenden.

Die vom Azure SDK bereitgestellten Clientklassen verlangen, dass SDK-Clientobjektinstanzen zum Zeitpunkt der Erstellung für ein einzelnes Blob bzw. einen einzelnen Container spezifisch sind. Die Sicherheit der Instanzen für die gleichzeitige Verwendung in verschiedenen Threads ist ferner nicht garantiert. Da ein Vorgangskontext eine einzelne Anforderung darstellt, basiert Gridwich die Zwischenspeicherung auf der Kombination aus Blob- bzw. Containername und Vorgangskontext.

Diese Wiederverwendung von Instanzen erfordert in Verbindung mit der Clientstruktur des Azure Storage SDK zusätzlichen Unterstützungscode, um für eine Balance zwischen Effizienz und Übersichtlichkeit des Codes zu sorgen.

Kontextargument

Fast alle Gridwich-Speicherdienstvorgänge erfordern ein spezielles Kontextargument vom Typ StorageClientProviderContext. Dieses Kontextargument erfüllt die folgenden Anforderungen:

  • Es liefert dem externen System Antworten, die den eindeutigen JSON-basierten Vorgangskontext-Wert der einzelnen Anforderung enthalten, den das externe System in der Gridwich-Anforderung angegeben hat. Weitere Informationen finden Sie unter Vorgangskontext.

  • Es ermöglicht es aufrufenden Funktionen des Speicherdiensts (wie beispielsweise Gridwich-Ereignishandlern) zu steuern, welche Antworten für das externe System sichtbar sind. Dieses Steuerelement hindert den Dienst daran, das externe System mit irrelevanten Benachrichtigungsereignissen zu überfluten. Weitere Informationen finden Sie unter Kontextstummschaltung.

  • Es entspricht den Azure-Speicherkonventionen, um kohärente Anforderungen und Antworten in einer Umgebung zu gewährleisten, die eine Mischung paralleler Leser und Autoren zulässt. Es unterstützt beispielsweise die ETag-Nachverfolgung. Weitere Informationen finden Sie unter ETags.

Speicherkontext

Der Kontext sowohl für die Blob- als auch für die Container-Speichertypen ist der StorageClientProviderContext, der wie folgt aussieht:

    string  ClientRequestID { get; }
    JObject ClientRequestIdAsJObject { get; }
    bool    IsMuted { get; set; }
    string  ETag { get; set; }
    bool    TrackingETag { get; set; }

Die beiden ersten Eigenschaften sind unterschiedliche Darstellungen des Vorgangskontexts, der verwendet wurde, um die StorageClientProviderContext-Instanz zu initialisieren. Die Klasse verfügt über verschiedene Konstruktoren, einschließlich eines Kopierkonstruktors. Zu den zusätzlichen Methoden zählen ResetTo für eine direkte Zustandsduplizierung sowie eine statische CreateSafe-Methode, um sicherzustellen, dass problematische Initialisierungen keine Ausnahmen auslösen.

Die Klasse umfasst auch eine besondere Behandlung für das Erstellen von Kontexten auf der Grundlage von eindeutigen Bezeichnern und leeren Zeichenfolgen. Die Azure Storage-Benachrichtigungshandler für Blob Erstellt und Gelöscht, die auch Benachrichtigungen aus externen Agents verarbeiten, erfordern das GUID-Format.

Kontextstummschaltung

Mit der Eigenschaft IsMuted wird gesteuert, ob die Anwendung erwartet, dass der Dienst resultierende Benachrichtigungen an die aufrufende Funktion, z. B. das externe System, zurückgibt (d. h. veröffentlicht). Bei einem stumm geschalteten Vorgang werden resultierende Ereignisse nicht vom Dienst veröffentlicht.

Ein Beispiel hierfür sind Blobkopien, die von einem Encoder ausgeführt werden, um Blobs in Azure Storage als Eingabe für eine Codierungsaufgabe anzuordnen. Das externe System interessiert sich nicht für diese Details, sondern nur für den Status des Codierungsauftrags und den Ort, an dem es die codierten Ausgaben abrufen kann. Um dies widerzuspiegeln, führt der Encoder Folgendes durch:

  1. Er erstellt einen nicht stumm geschalteten Speicherkontext, der auf dem Anforderungsvorgangskontext basiert, z. B. ctxNotMuted.

  2. Er erstellt einen stumm geschalteten Speicherkontext, z. B. ctxMuted, indem entweder der Kontextklassen-Kopierkonstruktor verwendet oder eine neue Instanz erstellt wird. Beide Optionen haben denselben Vorgangskontextwert.

  3. Er gibt ctxMuted für Speichervorgänge an, die an der Einrichtung für die Codierung beteiligt sind. Das externe System sieht nicht, dass diese Vorgänge ausgeführt werden.

  4. Er gibt den ctxNotMuted-Kontext für Speichervorgänge an, die den Codierungsabschluss widerspiegeln, z. B. das Kopieren einer Ausgabedatei in einen Zielcontainer. Gridwich-Handler veröffentlichen die resultierenden Azure Storage-Benachrichtigungsereignisse im externen System.

Die aufrufende Funktion steuert die letztendliche Sichtbarkeit von Vorgängen. Sowohl stumm geschaltete als auch nicht stumm geschaltete Vorgänge basieren auf einem gleichwertigen operationContext-Wert. Die Kontextstummschaltung soll die Problemdiagnose mit Ereignisablaufverfolgungsprotokollen vereinfachen, da es möglich ist, die sich auf eine Anforderung beziehenden Speichervorgänge unabhängig vom Stummschaltungsstatus des Vorgangs zu sehen.

ResponseBaseDTO verfügt über eine boolesche Eigenschaft DoNotPublish, die von der Ereignisverteilung verwendet wird, um die endgültige Entscheidung zu treffen, ob eine Veröffentlichung erfolgen soll. Die Ereignisverteilung legt die DoNotPublish-Eigenschaft wiederum anhand der IsMuted-Eigenschaft des Kontexts fest.

Der Dienst überträgt die Stummschaltungseinstellung an Azure Storage, das dann die clientRequestId in den Speicherbenachrichtigungsereignissen festlegt, die es den beiden Gridwich-Handlern Erstellt und Gelöscht bereitstellt. Diese beiden Handler legen DoNotPublish fest, um die von der aufrufenden Funktion angeforderte Stummschaltung widerzuspiegeln.

ETags für Zielkonsistenz

Azure Storage verwendet den HTTP-ETag-Header für Anforderungssequenzen, die eine Zielkonsistenz aufweisen sollen. Ein Anwendungsbeispiel besteht darin sicherzustellen, dass sich ein Blob zwischen den Speichervorgängen Metadaten abrufen und Metadaten aktualisieren nicht geändert hat.

Zur Anpassung an die Standard-HTTP-Verwendung hat dieser Header einen nicht transparenten Wert, dessen Interpretation besagt, dass sich bei einer Änderung des Headerwerts auch das zugrunde liegende Objekt geändert hat. Wenn eine Anforderung ihren aktuellen ETag-Wert für das Objekt sendet und dieser nicht mit dem aktuellen ETag-Wert des Speicherdiensts übereinstimmt, schlägt die Anforderung unverzüglich fehl. Wenn die Anforderung keinen ETag-Wert enthält, wird diese Überprüfung von Azure Storage übersprungen, und die Anforderung wird nicht gesperrt.

ETags im Speicherdienst

Bei Gridwich ist das ETag ein internes Detail, das vom Gridwich-Speicherdienst und von Azure Storage verwendet wird. Anderer Code muss das ETag nicht beachten. Der Speicherdienst verwendet das ETag für Sequenzen wie die Vorgänge Blob-Metadaten abrufen und Blob löschen, um eine BlobDelete Event-Anforderung zu verarbeiten. Durch die ETag-Verwendung wird sichergestellt, dass sich der Vorgang Blob löschen auf die exakt gleiche Version des Blobs bezieht wie der Vorgang Metadaten abrufen.

So verwenden Sie das ETag für das vorherige Beispiel:

  1. Senden Sie die Anforderung Metadaten abrufen mit einem leeren ETag.
  2. Speichern Sie den ETag-Wert aus der Antwort.
  3. Fügen Sie den gespeicherten ETag-Wert zu der Anforderung Blob löschen hinzu.

Wenn sich die beiden ETag-Werte unterscheiden, schlägt der Löschvorgang fehl. Der Fehler impliziert, dass ein anderer Vorgang das Blob zwischen den Schritten 2 und 3 geändert hat. Wiederholen Sie den Vorgang aus Schritt 1.

ETag ist ein Parameter von Konstruktoren und eine Zeichenfolgeneigenschaft der StorageClientProviderContext-Klasse. Der ETag-Wert wird nur durch die Gridwich-spezifische Richtlinie BlobClientPipelinePolicy geändert.

Steuern der ETag-Verwendung

Die TrackingETag-Eigenschaft steuert, ob der ETag-Wert bei der nächsten Anforderung gesendet wird. Der Wert true bedeutet, dass der Dienst ein ETag sendet, wenn dieses verfügbar ist.

Eine Azure Storage-Anforderung mit einem ETag-Wert, der nicht mit dem Antragsteller-Blob oder -Container identisch ist, führt zum Fehlschlagen des Vorgangs. Dieser Fehler ist beabsichtigt, da ETag die HTTP-Standardmethode darstellt, um „die genaue Version, auf die sich die Anforderung bezieht“ auszudrücken. Anforderungen können die Eigenschaft TrackingETag einschließen, um anzugeben, dass die ETags übereinstimmen müssen. Oder sie können die Eigenschaft TrackingETag nicht einschließen, um anzugeben, dass die ETag-Werte nicht von Bedeutung sind.

Die Pipeline ruft stets einen ETag-Wert aus einem Azure-Speichervorgang ab, wenn in dieser REST-Antwort ein solcher Wert vorhanden ist. Die Pipeline aktualisiert nach Möglichkeit stets die Kontext-ETag-Eigenschaft für den letzten Vorgang. Mit dem TrackingETag-Flag wird nur gesteuert, ob die nächste Anforderung von derselben Clientinstanz den Wert der ETag-Eigenschaft sendet. Wenn der ETag-Wert NULL oder leer ist, legt die aktuelle Anforderung unabhängig vom Wert von TrackingETag keinen HTTP-ETag-Wert fest.

Speicher-Sleeves

In Gridwich müssen die Speichermechanismen sowohl für Azure Storage-Blockblobs als auch für Container funktionieren. Es gibt unterschiedliche Klassen und Speicherdienstvorgänge für Blobs und Container. Daher steht eindeutig fest, ob sich ein bestimmter Speichervorgang auf ein Blob oder einen Container bezieht.

Ein Anbieterklassenpaar, eines für Blobs und eines für Container, gibt die beiden Funktionssätze in Einheiten aus, die als Sleeves bezeichnet werden. Die Sleeves enthalten Instanzen von Speicherhilfsprogrammklassen, die Teil des Azure SDK sind. Durch die Initialisierung des Speicherdiensts werden die Anbieter erstellt und den Speicherdienstmethoden direkt zur Verfügung gestellt.

Sleeve-Struktur

Der Sleeve ist ein Container für die SDK-Clientobjektinstanz und einen Speicherkontext. Speicheranbieterfunktionen verweisen über die beiden Eigenschaften Client und Context auf den Sleeve. Es gibt einen Sleeve-Typ für Blobs und einen anderen für Container, die über Client-Eigenschaften des Typs BlobBaseClient bzw. BlobContainerClient verfügen.

Die allgemeine Sleeve-Struktur für Blobs sieht wie folgt aus:

    BlobBaseClient Client { get; }
    BlobServiceClient Service { get; }
    StorageClientProviderContext Context { get; }

Die Service-Eigenschaft im Sleeve ist eine Komfortfunktion. Einige der abschließenden encoder-bezogenen Vorgänge, die die SDK BlobServiceClient-Klasse verwenden, benötigen Speicherkontoschlüssel. Diese Anforderung führte dazu, dass eine Dienstclientinstanz zu den beiden vorhandenen Sleeve-Typen hinzugefügt wurde, anstatt einen separaten Anbieter zu generieren.

Verwenden von Sleeves

Die Clientspeicheranbieter stellen Sleeve-Instanzen bereit. Der Speicherdienstcode sieht in etwa wie die folgende mit Anmerkungen versehene Codesequenz aus, wobei die Typen zur besseren Übersichtlichkeit ausgeschrieben sind:

    public bool DeleteBlob(Uri sourceUri, StorageClientProviderContext context)
    {
        . . .
        StorageBlobClientSleeve sleeve = _blobBaseClientProvider.GetBlobBaseClientForUri(sourceUri, context); // Line A
        BlobProperties propsIncludingMetadata = sleeve.Client.GetProperties(); // Line B
        sleeve.Context.TrackingETag = true;   // Send ETag from GetProperties()
        var wasDeleted = sleeve.Client.DeleteBlob(); // Line C
        sleeve.Context.TrackingETag = false;
        var someResult = sleeve.Client.AnotherOperation(); // Line D
        . . .
    }
  1. Gridwich trägt automatisch den Vorgangskontext in den Sleeve-Kontext in Zeile A ein. Für TrackingETag wird standardmäßig „false“ verwendet.
  2. Nach Zeile B enthält sleeve.Context das ETag aus Zeile A und behält denselben ClientRequestID-Wert bei.
  3. Zeile C sendet den ETag-Wert aus Zeile B und die ClientRequestId.
  4. Nach Zeile C verfügt der Kontext über einen neuen ETag-Wert, wie er in der Delete()-Antwort zurückgegeben wurde.
  5. Zeile D sendet keinen ETag-Wert in der Anforderung für AnotherOperation().
  6. Nach Zeile D hat der Kontext einen neuen ETag-Wert, wie er in der AnotherOperation()-Antwort zurückgegeben wurde.

Der Speicherdienst ist aktuell in der Konfiguration der Abhängigkeitsinjektion als Transient festgelegt, was bedeutet, dass die sleeve-basierte Zwischenspeicherung auf Anforderungsbasis erfolgt. Weitere Informationen finden Sie unter Speicherdienst und Abhängigkeitsinjektion.

Speicherdienst-Alternativen

In den folgenden Abschnitten werden alternative Ansätze beschrieben, die nicht Teil der aktuellen Gridwich-Speicherlösung sind.

Klasse „Gridwich AzureStorageManagement“

In Verbindung mit dem Sleeve-Service-Element, bei dem es sich um eine Instanz der Azure SDK BlobServiceClient-Klasse handelt, verfügt Gridwich auch über die Klasse AzureStorageManagement. Die Speicherdienstmethode GetConnectionStringForAccount und die GetStoreByNameAsync-Methode der Telerek-Codierung verwenden diese Klasse, um Speicherkontoschlüssel abzurufen. Die Klasse basiert gegenwärtig auf dem Fluent-Framework. Ergänzungen für die SDK-BlobServiceClient-Klasse dürften diese Klasse irgendwann ablösen und so einen fokussierteren Informationsabruf erlauben, als dies angesichts der großen Vielfalt der Fluent IAzure-Schnittstelle möglich ist.

Ausblenden der Pipelinerichtlinie durch Erstellen von Unterklassen

Durch Erstellen von Unterklassen der SDK-Clienttypen werden dem Client zwei einfache Eigenschaften hinzugefügt: eine für jeden HTTP-Headerwert, um die Interaktion mit der Pipelinerichtlinie vollständig auszublenden. Aufgrund eines tiefgreifenden Moq-Fehlers ist es jedoch nicht möglich, Komponententests über mock für diese abgeleiteten Typen zu erstellen. Gridwich verwendet Moq, weshalb dieser Ansatz der Unterklassenerstellung nicht verwendet wurde.

Der Moq-Fehler betrifft die fehlerhafte Handhabung der assemblyübergreifenden Unterklassifizierung in Gegenwart von virtuellen Funktionen im internen Bereich. Die SDK-Clientklassen verwenden virtuelle Funktionen im internen Bereich, welche Typen des internen Bereichs umfassen, die für normale externe Benutzer nicht sichtbar sind. Wenn Moq versucht, ein mock der Unterklasse zu erstellen, die sich in einer der Gridwich-Assemblys befindet, schlägt dieser Vorgang bei der Testausführung fehl, da es die virtuellen Aufrufe nicht im internen Bereich in den SDK-Clientklassen finden kann, von denen die Gridwich-Klassen abgeleitet sind. Es ist keine Problemumgehung ohne Änderungen an der Moq Castle-Proxygenerierung möglich.

Speicherdienst und Abhängigkeitsinjektion

Gridwich registriert den Speicherdienst derzeit als einen Transient-Abhängigkeitsinjektionsdienst. Jedes Mal, wenn die Abhängigkeitsinjektion für den Dienst angefordert wird, wird somit eine neue Instanz erstellt. Der aktuelle Code sollte auch ordnungsgemäß funktionieren, wenn die Registrierung in Scoped geändert wird, was eine Instanz pro Anforderung impliziert, z. B. die Anforderung des externen Systems.

Es kommt jedoch zu Problemen, wenn sich die Registrierung in Singleton ändert, d. h. eine Instanz über die Gridwich-Funktions-App. Der Zwischenspeicherungsmechanismus von Gridwich für Sleeves und Datenbytebereiche unterscheidet dann nicht zwischen verschiedenen Anforderungen. Außerdem ist das Cachemodell kein Auscheckmodell, weshalb Gridwich die Instanz nicht aus dem Cache entfernt, während sie verwendet wird. Da die Threadsicherheit der SDK-Clientklassen nicht garantiert ist, wären für die Koordination viele Änderungen erforderlich.

Ändern Sie aus diesen Gründen den bestehenden Gridwich-Speicherdienst nicht in eine Singleton-Abhängigkeitsinjektionsregistrierung. Gridwich befolgt diese Regel bei der Abhängigkeitsinjektionsregistrierung und enthält den Komponententest CheckThatStorageServiceIsNotASingleton, um sie zu erzwingen.

Nächste Schritte

Produktdokumentation:

Microsoft Learn-Module: