자습서: 델타 동기화 - AWS AppSync

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

자습서: 델타 동기화

참고

이제 우리는 주로 APPSYNC_JS 런타임과 해당 문서를 지원합니다. 여기에서 APPSYNC_JS 런타임과 해당 안내서를 사용해 보세요.

AWS AppSync의 클라이언트 애플리케이션은 GraphQL 응답을 모바일/웹 애플리케이션의 디스크로 로컬로 캐싱해 데이터를 저장합니다. 버전이 지정된 데이터 원본 및 Sync 작업을 통해 고객은 해석기 하나로 동기화 프로세스를 수행할 수 있습니다. 따라서 클라이언트가 수 많은 레코드가 있을 수 있는 기본 쿼리 하나의 결과로 로컬 캐시를 하이드레이션한 다음 마지막 쿼리 이후 변경된 데이터만 수신할 수 있습니다(델타 업데이트). 클라이언트가 최초 요청을 사용한 캐시의 기본 하이드레이션과 다른 요청의 증분 업데이트를 수행하도록 해 클라이언트 애플리케이션에서 백엔드로 컴퓨팅을 이전할 수 있습니다. 이는 온라인과 오프라인 상태 간에 자주 전환하는 클라이언트 애플리케이션에 훨씬 더 효율적입니다.

Delta Sync를 구현하기 위해 Sync 쿼리는 버전이 지정된 데이터 원본에 대한 Sync 작업을 사용합니다. AWS AppSync 뮤테이션이 버전 지정된 데이터 소스의 항목을 변경하면 해당 변경의 레코드는 델타 테이블에도 저장됩니다. 버전이 지정된 다른 데이터 원본에 대해 서로 다른 델타 테이블(예: 유형당 하나, 도메인 영역당 하나)을 사용하거나 API에 대해 단일 델타 테이블을 사용하도록 선택할 수 있습니다. AppSync에서는 기본 키의 충돌을 피하기 위해 여러 API에 단일 델타 테이블을 사용하지 않을 것을 권장합니다.

또한 Delta Sync 클라이언트는 구독을 인수로 수신할 수 있고, 그런 다음 오프라인-온라인 전환 간에 구독 다시 연결 및 쓰기를 조정합니다. Delta Sync는 지수 백오프, 여러 네트워크 오류 시나리오 간에 지터를 사용한 재시도 및 대기열에 이벤트 저장을 비롯하여 구독을 자동으로 재개해 이를 수행합니다. 그런 다음 대기열의 모든 이벤트를 병합하여 최종적으로 구독을 정상적으로 처리하기 전에 적절한 델타 또는 기본 쿼리가 실행됩니다.

Amplify DataStore를 포함한 클라이언트 구성 옵션에 대한 문서는 Amplify Framework 웹사이트를 참조하십시오. 이 문서에서는 최적의 데이터 액세스를 위해 Delta Sync 클라이언트와 작동하도록 버전이 지정된 DynamoDB 데이터 원본과 Sync 작업을 설정하는 방법을 설명합니다.

원클릭 설치

구성된 모든 해석기와 필수 AWS 리소스를 모두 사용해 AWS AppSync에서 GraphQL 엔드포인트를 자동으로 설정하려면 이 AWS CloudFormation 템플릿을 사용합니다.

이 스택은 계정에 다음 리소스를 생성합니다.

  • DynamoDB 테이블 2개(기본 및 델타)

  • API 키가 있는 AWS AppSync API 1개

  • DynamoDB 테이블에 대한 정책이 연결된 IAM 역할 1개

클라이언트가 오프라인 상태였을 때 누락된 이벤트 저널로 작동하는 두 번째 테이블로 동기화 쿼리를 분할하는 데 테이블 2개가 사용됩니다. 델타 테이블에 대해 쿼리를 효율적으로 유지하기 위해 Amazon DynamoDB TTL을 사용하면 필요에 따라 이벤트를 자동으로 정리됩니다. TTL 시간은 데이터 원본의 필요에 맞게 구성할 수 있습니다(1시간, 1일 등).

Schema

델타 동기화를 시연하기 위해 샘플 애플리케이션은 DynamoDB의 기본델타 테이블을 기반으로 하는 Posts 스키마를 생성합니다. AWS AppSync는 두 테이블에 뮤테이션을 자동으로 기록합니다. 동기화 쿼리는 기본 또는 델타 테이블에서 레코드를 적절하게 가져오고 재연결 로직에서 클라이언트가 이러한 테이블을 어떻게 활용하는지 보여주도록 단일 구독이 정의됩니다.

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 }

GraphQL 스키마가 표준이긴 하지만 계속 진행하기 전에 첫째, 모든 변형이 자동으로 먼저 기본 테이블에 기록한 다음 델타 테이블에 기록합니다. 기본 테이블은 상태에 대한 중앙 출처인 반면에 델타 테이블은 저널입니다. lastSync: AWSTimestamp를 전달하지 않으면 syncPosts 쿼리가 기본 테이블에 대해 실행되어 캐시를 하이드레이트하고, 클라이언트가 델타 테이블에서 구성한 TTL 시간보다 오랫동안 오프라인 상태일 때 에지 케이스에 대한 글로벌 캐치업 프로세스로 주기적으로 실행됩니다. lastSync: AWSTimestamp를 전달하지 않으면 syncPosts 쿼리는 델타 테이블에 대해 실행되고 클라이언트가 마지막 오프라인 상태였던 이후 변경된 이벤트를 검색하는 데 사용됩니다. Amplify 클라이언트는 자동으로 lastSync: AWSTimestamp 값을 전달하고 디스크에 적절하게 계속 씁니다.

Post_deleted 필드는 삭제 작업에 사용됩니다. 클라이언트가 오프라인 상태이고 레코드가 기본 테이블에서 제거된 경우 이 속성은 클라이언트에 동기화를 수행하여 로컬 캐시에서 항목을 제거하라고 알립니다. 클라이언트가 장기간 오프라인 상태로 유지되고 Delta Sync 쿼리를 사용하여 클라이언트가 이 값을 검색하기 전에 항목이 제거되면 (클라이언트에서 구성 가능한) 기본 쿼리의 전역 캐치업 이벤트가 실행되어 캐시에서 항목을 제거합니다. 존재하는 항목을 삭제하는 동기화 쿼리를 실행할 때 값만 반환하기 때문에 이 필드는 선택 사항으로 표시됩니다.

변형

모든 뮤테이션에 대해 AWS AppSync는 기본 테이블에서 표준 생성/업데이트/삭제 작업을 수행하고 델타 테이블의 변경 사항을 자동으로 기록합니다. 데이터 원본에서 DeltaSyncTableTTL 값을 수정하여 레코드를 보관할 시간을 줄이거나 늘릴 수 있습니다. 데이터의 속도가 빠른 조직의 경우 이 시간을 짧게 유지하는 것이 합리적일 수 있습니다. 또는 클라이언트가 장기간 오프라인 상태인 경우에는 이 시간을 늘리는 것이 좋을 수 있습니다.

동기화 쿼리

기본 쿼리lastSync 값이 지정되지 않은 DynamoDB 동기화 작업입니다. 기본 쿼리는 시작 시 그 이후에는 정기적으로만 실행되기 때문에 이는 다수의 조직에 해당하는 내용입니다.

델타 쿼리lastSync 값이 지정된 DynamoDB 동기화 작업입니다. (기본 쿼리 주기가 실행되지 않는 한) 델타 쿼리는 클라이언트의 상태가 오프라인에서 다시 온라인으로 전환될 때마다 실행됩니다. 클라이언트는 데이터를 동기화하기 위해 마지막으로 쿼리를 실행한 시간을 자동으로 추적합니다.

델타 쿼리가 실행되면 쿼리의 해석기에서 ds_pkds_sk를 사용하여 클라이언트가 마지막으로 동기화를 수행한 이후 변경된 레코드에 대해서만 쿼리합니다. 클라이언트는 적절한 GraphQL 응답을 저장합니다.

동기화 쿼리 실행에 대한 자세한 내용은 동기화 작업 설명서를 참조하십시오.

먼저 createPost 변형을 호출하여 항목을 만듭니다.

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

이 변형의 반환 값은 다음과 같습니다.

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

기본 테이블의 내용을 검사하면 다음과 같은 레코드를 볼 수 있습니다.

{ "_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" } }

델타 테이블의 내용을 검사하면 다음과 같은 레코드를 볼 수 있습니다.

{ "_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" } }

이제 syncPosts 쿼리와 같이 클라이언트가 로컬 데이터 저장소를 하이드레이트하기 위해 실행하는 기본 쿼리를 시뮬레이션할 수 있습니다:

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

기본 쿼리의 반환 값은 다음과 같습니다.

{ "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 } } }

나중에 startedAt 값을 저장하여 델타 쿼리를 시뮬레이션하겠지만 먼저 테이블을 변경해야 합니다. updatePost 변형을 사용하여 기존 게시물을 수정하겠습니다.

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 } }

이 변형의 반환 값은 다음과 같습니다.

{ "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 } } }

이제 기본 테이블의 내용을 검사하면 업데이트된 항목을 볼 수 있습니다.

{ "_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" } }

이제 델타 테이블의 내용을 검사하면 두 개의 레코드를 볼 수 있습니다.

  1. 항목이 생성되었을 때의 레코드

  2. 항목이 업데이트되었을 때에 대한 레코드.

새 항목은 다음과 같습니다.

{ "_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" } }

이제 델타 쿼리를 시뮬레이션하여 클라이언트가 오프라인 상태일 때 발생한 수정 사항을 검색할 수 있습니다. Base 쿼리에서 반환된 startedAt 값을 사용하여 요청해 보겠습니다.

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

델타 쿼리의 반환 값은 다음과 같습니다.

{ "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 } } }