Anleitung: Delta Sync - AWS AppSync

Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.

Anleitung: Delta Sync

Anmerkung

Wir unterstützen jetzt hauptsächlich die APPSYNC_JS-Laufzeit und ihre Dokumentation. Bitte erwägen Sie, die APPSYNC_JS-Laufzeit und ihre Anleitungen hier zu verwenden.

Client-Anwendungen in AWS AppSync speichern Daten, indem Sie GraphQL-Antworten lokal auf der Festplatte in einer mobilen/Webanwendung zwischenspeichern. Versionierte Datenquellen und Sync-Vorgänge bieten Kunden die Möglichkeit, den Synchronisierungsprozess mit einem einzigen Resolver durchzuführen. Auf diese Weise können Clients ihren lokalen Cache mit Ergebnissen aus einer Basis-Abfrage, die möglicherweise viele Datensätze enthalten, hydratisieren und anschließend nur die Daten empfangen, die seit der letzten Abfrage geändert wurden (die Delta-Updates). Indem Clients berechtigt werden, die Basis-Hydration des Caches mit einer Abfrage und inkrementelle Updates mit einer anderen Abfrage separat durchzuführen, können die Rechenvorgänge von der Client-Anwendung in das Backend verlagert werden. Dies ist wesentlich effizienter für Client-Anwendungen, die häufig zwischen Online- und Offline-Status wechseln.

Um Delta Sync zu implementieren, verwendet die Sync-Abfrage den Sync-Vorgang für eine versionierte Datenquelle. Wenn eine AWS AppSync -Mutation ein Element in einer versionierten Datenquelle ändert, wird auch ein Datensatz dieser Änderung in der Delta-Tabelle gespeichert. Sie können wählen, ob Sie verschiedene Delta-Tabellen (z. B. eine pro Typ, eine pro Domainbereich) für andere versionierte Datenquellen oder eine einzelne Delta-Tabelle für Ihre API verwenden möchten. AWS AppSync empfiehlt, keine einzige Delta-Tabelle für mehrere APIs zu verwenden, um die Kollision von Primärschlüsseln zu vermeiden.

Darüber hinaus können Delta Sync-Clients auch ein Abonnement als Argument erhalten. Der Client koordiniert dann das Wiederherstellen von Abonnementverbindungen und Schreibvorgänge während des Übergangs vom Offline- zum Online-Zustand. Delta Sync führt hierzu eine automatische Wiederaufnahme der Abonnements durch, einschließlich exponentiellem Backoff und Neuversuch mit Jitter in verschiedenen Netzwerkfehlerszenarien und Speichern der Ereignisse in einer Warteschlange. Die entsprechende Delta- oder Basisabfrage wird dann ausgeführt, bevor Ereignisse aus der Warteschlange zusammengeführt und letztlich Abonnements wie gewohnt verarbeitet werden.

Die Dokumentation zu den Client-Konfigurationsoptionen, einschließlich Amplify DataStore, ist auf der Amplify Framework-Website verfügbar. In dieser Dokumentation wird beschrieben, wie Sie versionierte DynamoDB-Datenquellen und Sync-Vorgänge so einrichten, dass sie mit dem Delta Sync-Client für optimalen Datenzugriff arbeiten.

One-Click-Setup

Verwenden Sie diese Vorlage, um den GraphQL-Endpunkt AWS AppSync mit allen konfigurierten Resolvern und den erforderlichen AWS Ressourcen automatisch einzurichten: AWS CloudFormation

Dieser Stack erstellt die folgenden Ressourcen in Ihrem Konto:

  • 2 DynamoDB-Tabellen (Base und Delta)

  • 1 AWS AppSync -API mit API-Schlüssel

  • 1 IAM-Rolle mit Richtlinie für DynamoDB-Tabellen

Es werden zwei Tabellen verwendet, um Ihre Sync-Abfragen in eine zweite Tabelle zu partitionieren, die als Journal der Ereignisse fungiert, welche verpasst wurden, während die Clients offline waren. Um die Effizienz der Abfragen in der Delta-Tabelle aufrechtzuerhalten, können Sie Amazon DynamoDB TTLs verwenden, um die Ereignisse nach Bedarf automatisch zu bereinigen. Die TTL-Zeit ist für Ihre Anforderungen an die Datenquelle konfigurierbar (Sie können dies als 1 Stunde, 1 Tag usw. verwenden).

Schema

Um Delta Sync zu demonstrieren, erstellt die Beispielanwendung ein Posts-Schema, das von einer Base - und Delta-Tabelle in DynamoDB unterstützt wird. AWS AppSync schreibt die Mutationen automatisch in beide Tabellen. Die Sync-Abfrage ruft Datensätze entsprechend aus der Basis- oder der Delta-Tabelle ab. Außerdem ist ein einziges Abonnement definiert, das zeigt, wie die Clients dies in ihrer Logik für erneute Verbindungen nutzen können.

input CreatePostInput { author: String! title: String! content: String! url: String ups: Int downs: Int _version: Int } interface Connection { nextToken: String startedAt: AWSTimestamp! } type Mutation { createPost(input: CreatePostInput!): Post updatePost(input: UpdatePostInput!): Post deletePost(input: DeletePostInput!): Post } type Post { id: ID! author: String! title: String! content: String! url: AWSURL ups: Int downs: Int _version: Int _deleted: Boolean _lastChangedAt: AWSTimestamp! } type PostConnection implements Connection { items: [Post!]! nextToken: String startedAt: AWSTimestamp! } type Query { getPost(id: ID!): Post syncPosts(limit: Int, nextToken: String, lastSync: AWSTimestamp): PostConnection! } type Subscription { onCreatePost: Post @aws_subscribe(mutations: ["createPost"]) onUpdatePost: Post @aws_subscribe(mutations: ["updatePost"]) onDeletePost: Post @aws_subscribe(mutations: ["deletePost"]) } input DeletePostInput { id: ID! _version: Int! } input UpdatePostInput { id: ID! author: String title: String content: String url: String ups: Int downs: Int _version: Int! } schema { query: Query mutation: Mutation subscription: Subscription }

Das GraphQL-Schema ist Standard. Einige Aspekte sind jedoch der Erwähnung wert, bevor Sie fortfahren. Zuerst werden alle Mutationen automatisch in die Basis-Tabelle und dann in die Delta-Tabelle geschrieben. Die Basis-Tabelle ist die zentrale Datenquelle (Single Source of Truth) für den Status, während die Delta-Tabelle Ihr Journal ist. Wenn Sie die lastSync: AWSTimestamp nicht übergeben, wird die syncPosts-Abfrage über die Basis-Tabelle ausgeführt. Sie hydratisiert den Cache und wird regelmäßig als globaler Catchup-Prozess für Sonderfälle ausgeführt, in denen Clients länger als die in der Delta-Tabelle konfigurierte TTL-Zeit offline sind. Wenn Sie die lastSync: AWSTimestamp-Abfrage jedoch übergeben, wird die syncPosts-Abfrage über die Delta-Tabelle ausgeführt und von Clients verwendet, um Ereignisse abzurufen, die seit ihrem letzte Offline-Zeitpunkt geändert wurden. Amplify-Clients übergeben den lastSync: AWSTimestamp-Wert automatisch und halten ihn entsprechend dauerhaft auf der Festplatte.

Das Feld _deleted auf Post wird für DELETE-Vorgänge verwendet. Wenn Clients offline sind und Datensätze aus der Basis-Tabelle entfernt werden, benachrichtigt dieses Attribut Clients, die eine Synchronisierung durchführen, dass sie Elemente aus ihrem lokalen Cache entfernen müssen. In Fällen, in denen Clients für längere Zeiträume offline sind und das Element entfernt wurde, bevor der Client diesen Wert mit einer Delta Sync-Abfrage abrufen kann, wird das globale Catchup-Ereignis in der Basis-Abfrage (im Client konfigurierbar) ausgeführt und entfernt das Element aus dem Cache. Dieses Feld ist als optional gekennzeichnet, weil es nur dann einen Wert zurückgibt, wenn es eine Sync-Abfrage ausführt, in der gelöschte Elemente vorhanden sind.

Mutationen

Für alle Mutationen führt AWS AppSync eine Standardoperation „Erstellen/Aktualisieren/Löschen“ in der Basis-Tabelle durch und zeichnet die Änderung in der Delta-Tabelle automatisch auf. Sie können den Aufbewahrungszeitraum für Datensätze verlängern oder verkürzen, indem Sie den DeltaSyncTableTTL-Wert in der Datenquelle anpassen. Für Unternehmen, deren Daten häufigen Änderungen unterliegen, ist es sinnvoll, einen kurzen Zeitraum anzugeben. Wenn Ihre Clients für längere Zeiträume offline sind, kann es ratsam sein, einen längeren Zeitraum anzugeben.

Sync-Abfragen

Die Basisabfrage ist ein DynamoDB-Synchronisierungsvorgang ohne Angabe eines lastSync Werts. Dies funktioniert in vielen Organisationen, weil die Basis-Abfrage nur beim Start und danach in regelmäßigen Abständen ausgeführt wird.

Die Deltaabfrage ist ein DynamoDB-Synchronisierungsvorgang mit einem angegebenen lastSync Wert. Die Delta-Abfrage wird jedes Mal ausgeführt, wenn der Client wieder in den Online-Zustand wechselt (sofern nicht die periodische Basis-Abfrage die Ausführung ausgelöst hat). Clients verfolgen automatisch das letzte Mal nach, als sie eine Abfrage zum Synchronisieren von Daten erfolgreich ausgeführt haben.

Wenn eine Delta-Abfrage ausgeführt wird, verwendet der Resolver der Abfrage ds_pk und ds_sk, um nur die Datensätze abzufragen, die seit der letzten Synchronisierung durch den Client geändert wurden. Der Client speichert die entsprechende GraphQL-Antwort.

Weitere Informationen zum Ausführen von Sync-Abfragen finden Sie in der Dokumentation zu Synchronisierungsoperationen.

Beispiel

Beginnen wir zunächst mit dem Aufruf einer createPost-Mutation, um ein Element zu erstellen:

mutation create { createPost(input: {author: "Nadia", title: "My First Post", content: "Hello World"}) { id author title content _version _lastChangedAt _deleted } }

Der Rückgabewert dieser Mutation sieht wie folgt aus:

{ "data": { "createPost": { "id": "81d36bbb-1579-4efe-92b8-2e3f679f628b", "author": "Nadia", "title": "My First Post", "content": "Hello World", "_version": 1, "_lastChangedAt": 1574469356331, "_deleted": null } } }

Wenn Sie den Inhalt der Basis-Tabelle untersuchen, wird ein Datensatz angezeigt, der wie folgt aussieht:

{ "_lastChangedAt": { "N": "1574469356331" }, "_version": { "N": "1" }, "author": { "S": "Nadia" }, "content": { "S": "Hello World" }, "id": { "S": "81d36bbb-1579-4efe-92b8-2e3f679f628b" }, "title": { "S": "My First Post" } }

Wenn Sie den Inhalt der Delta-Tabelle untersuchen, wird ein Datensatz angezeigt, der wie folgt aussieht:

{ "_lastChangedAt": { "N": "1574469356331" }, "_ttl": { "N": "1574472956" }, "_version": { "N": "1" }, "author": { "S": "Nadia" }, "content": { "S": "Hello World" }, "ds_pk": { "S": "AppSync-delta-sync-post:2019-11-23" }, "ds_sk": { "S": "00:35:56.331:81d36bbb-1579-4efe-92b8-2e3f679f628b:1" }, "id": { "S": "81d36bbb-1579-4efe-92b8-2e3f679f628b" }, "title": { "S": "My First Post" } }

Jetzt können wir eine Basis-Abfrage simulieren, die von einem Client ausgeführt wird, um seinen lokalen Datenspeicher mit einer syncPosts-Abfrage zu hydratisieren, die wie folgt aussieht:

query baseQuery { syncPosts(limit: 100, lastSync: null, nextToken: null) { items { id author title content _version _lastChangedAt } startedAt nextToken } }

Der Rückgabewert dieser Basis-Abfrage sieht wie folgt aus:

{ "data": { "syncPosts": { "items": [ { "id": "81d36bbb-1579-4efe-92b8-2e3f679f628b", "author": "Nadia", "title": "My First Post", "content": "Hello World", "_version": 1, "_lastChangedAt": 1574469356331 } ], "startedAt": 1574469602238, "nextToken": null } } }

Wir speichern den startedAt-Wert später, um eine Delta-Abfrage zu simulieren, aber zuerst müssen wir eine Änderung an unserer Tabelle vornehmen. Verwenden wir die updatePost-Mutation zum Ändern unseres vorhandenen Beitrags:

mutation updatePost { updatePost(input: {id: "81d36bbb-1579-4efe-92b8-2e3f679f628b", _version: 1, title: "Actually this is my Second Post"}) { id author title content _version _lastChangedAt _deleted } }

Der Rückgabewert dieser Mutation sieht wie folgt aus:

{ "data": { "updatePost": { "id": "81d36bbb-1579-4efe-92b8-2e3f679f628b", "author": "Nadia", "title": "Actually this is my Second Post", "content": "Hello World", "_version": 2, "_lastChangedAt": 1574469851417, "_deleted": null } } }

Wenn Sie den Inhalt der Basis-Tabelle jetzt untersuchen, sollten Sie das aktualisierte Element sehen:

{ "_lastChangedAt": { "N": "1574469851417" }, "_version": { "N": "2" }, "author": { "S": "Nadia" }, "content": { "S": "Hello World" }, "id": { "S": "81d36bbb-1579-4efe-92b8-2e3f679f628b" }, "title": { "S": "Actually this is my Second Post" } }

Wenn Sie den Inhalt der Delta-Tabelle jetzt untersuchen, sollten Sie zwei Datensätze sehen:

  1. Ein Datensatz zum Zeitpunkt der Erstellung des Elements

  2. Ein Datensatz zum Zeitpunkt der Aktualisierung des Elements.

Das neue Element sieht folgendermaßen aus:

{ "_lastChangedAt": { "N": "1574469851417" }, "_ttl": { "N": "1574473451" }, "_version": { "N": "2" }, "author": { "S": "Nadia" }, "content": { "S": "Hello World" }, "ds_pk": { "S": "AppSync-delta-sync-post:2019-11-23" }, "ds_sk": { "S": "00:44:11.417:81d36bbb-1579-4efe-92b8-2e3f679f628b:2" }, "id": { "S": "81d36bbb-1579-4efe-92b8-2e3f679f628b" }, "title": { "S": "Actually this is my Second Post" } }

Jetzt können wir eine Delta-Abfrage simulieren, um Änderungen abzurufen, die aufgetreten sind, als ein Client offline war. Wir verwenden den startedAt-Wert, der von unserer Basis-Abfrage zurückgegeben wird, um folgende Anfrage zu stellen:

query delta { syncPosts(limit: 100, lastSync: 1574469602238, nextToken: null) { items { id author title content _version } startedAt nextToken } }

Der Rückgabewert dieser Delta-Abfrage sieht wie folgt aus:

{ "data": { "syncPosts": { "items": [ { "id": "81d36bbb-1579-4efe-92b8-2e3f679f628b", "author": "Nadia", "title": "Actually this is my Second Post", "content": "Hello World", "_version": 2 } ], "startedAt": 1574470400808, "nextToken": null } } }