의 충돌 감지 및 해결 AWS AppSync - AWS AppSync

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

의 충돌 감지 및 해결 AWS AppSync

에서 동시 쓰기가 발생하면 충돌 감지 및 충돌 해결 전략을 구성하여 업데이트를 적절하게 처리할 AWS AppSync수 있습니다. 충돌 감지는 변형이 데이터 원본에 실제 기록된 항목과 충돌하는지 판단합니다. conflictDetection 필드의 값을 로 설정하면 충돌 감지 SyncConfig 가 활성화됩니다VERSION.

충돌 해결은 충돌이 감지될 경우 수행되는 작업입니다. 이는 에서 충돌 핸들러 필드를 설정하여 결정됩니다 SyncConfig. 다음과 같은 세 가지 충돌 해결 전략이 있습니다.

  • OPTIMISTIC_CONCURRENCY

  • AUTOMERGE

  • LAMBDA

버전은 쓰기 작업 AWS AppSync 중에 에 의해 자동으로 증가되며 클라이언트에 의해 또는 버전 지원 데이터 소스로 구성된 해석기 외부에서 수정해서는 안 됩니다. 이렇게 하면 시스템의 일관성 동작이 변경되어 데이터가 손실될 수 있습니다.

최적의 동시성

최적의 동시성은 버전화된 데이터 소스를 AWS AppSync 제공하는 충돌 해결 전략입니다. 충돌 해석기가 낙관적 동시성으로 설정된 경우, 수신 중인 변형의 버전이 실제 객체 버전과 다른 것으로 감지되면 충돌 핸들러가 수신 중인 요청을 거부합니다. GraphQL 응답 내에, 최신 버전 서버의 기존 항목이 제공됩니다. 그런 다음 클라이언트는 이 충돌을 로컬로 처리하고, 항목 버전이 업데이트된 변형을 다시 시도해야 합니다.

Automerges

Automerge를 사용하면 개발자가 다른 전략으로는 처리할 수 없었던 충돌을 수동으로 병합하는 클라이언트 측 로직을 작성하지 않고도 충돌 해결 전략을 쉽게 구성할 수 있습니다. Automerge는 충돌을 해결하기 위해 데이터를 병합할 때 엄격한 규칙 세트를 준수합니다. Automerge의 원칙은 GraphQL 필드의 기본 데이터 유형을 중심으로 합니다. 그 속성이란 다음과 같습니다.

  • 스칼라 필드의 충돌: GraphQL 스칼라 또는 컬렉션이 아닌 필드(목록, 집합, 맵). 스칼라 필드의 수신 값을 거부하고 서버에 있는 값을 선택합니다.

  • 목록의 충돌: GraphQL 유형과 데이터베이스 유형은 목록입니다. 수신 목록을 서버의 기존 목록과 연결합니다. 수신 중인 변형의 목록 값이 서버의 목록 끝에 추가됩니다. 중복 값은 유지됩니다.

  • 집합의 충돌: GraphQL 유형은 목록이고 데이터베이스 유형은 집합입니다. 서버의 기존 집합과 수신 집합을 사용하여 집합 공용 구조체를 적용합니다. 이는 중복 항목이 없음을 의미하는 집합의 속성을 준수합니다.

  • 수신 중인 변형이 항목에 새 필드를 추가하거나 null 값이 있는 필드에 대해 만들어진 경우, 이를 기존 항목에 병합합니다.

  • 맵의 충돌: 데이터베이스의 기본 데이터 유형이 맵(키-값 문서)인 경우, 맵의 각 속성을 구문 분석하고 처리할 때 위의 규칙을 적용합니다.

Automerge는 업데이트된 버전의 요청을 자동으로 검색, 병합 및 재시도하여 클라이언트가 충돌하는 데이터를 수동으로 병합할 필요가 없도록 합니다.

Automerge가 스칼라 유형에서 충돌을 처리하는 방법의 예를 보여줍니다. 우선, 다음 레코드를 사용하겠습니다.

{ "id" : 1, "name" : "Nadia", "jersey" : 5, "_version" : 4 }

현재 수신 중인 변형이 항목을 업데이트하려고 시도할 수 있으나, 클라이언트가 아직 서버와 동기화되지 않았기 때문에 이전 버전으로 업데이트됩니다. 다음과 같은 형태입니다.

{ "id" : 1, "name" : "Nadia", "jersey" : 55, "_version" : 2 }

수신 중인 요청이 이전 버전인 2임을 알 수 있습니다. 이 흐름 동안 Automerge는 'jersey' 필드를 '55'로 업데이트하기를 거부하여 데이터를 병합하고 '5' 값을 유지하므로, 서버에 이 항목이 다음 이미지와 같이 저장됩니다.

{ "id" : 1, "name" : "Nadia", "jersey" : 5, "_version" : 5 # version is incremented every time automerge performs a merge that is stored on the server. }

버전 5에서 위 항목의 상태를 감안할 때, 이번에는 수신 중인 변형이 다음 이미지로 항목을 변형하려고 시도한다고 가정해 봅시다.

{ "id" : 1, "name" : "Shaggy", "jersey" : 5, "interests" : ["breakfast", "lunch", "dinner"] # underlying data type is a Set "points": [24, 30, 27] # underlying data type is a List "_version" : 3 }

수신 중인 변형에서 세 가지를 관심 있게 봐야 합니다. 스칼라라는 이름이 변경되었지만 “interests” 집합과 “points” 목록이라는 두 개의 새로운 필드가 추가되었습니다. 이 시나리오에서는 버전 불일치로 인해 충돌이 감지됩니다. Automerge는 속성을 준수하고, 스칼라이기 때문에 이름 변경을 거부하고 충돌하지 않는 필드에 추가합니다. 그러면 서버에 저장된 항목이 다음과 같이 표시됩니다.

{ "id" : 1, "name" : "Nadia", "jersey" : 5, "interests" : ["breakfast", "lunch", "dinner"] # underlying data type is a Set "points": [24, 30, 27] # underlying data type is a List "_version" : 6 }

항목 이미지는 버전 6으로 업데이트된 가운데, 이번에는 수신 중인 변형(다른 버전 불일치)이 항목을 다음과 같이 변환하려고 한다고 가정합시다.

{ "id" : 1, "name" : "Nadia", "jersey" : 5, "interests" : ["breakfast", "lunch", "brunch"] # underlying data type is a Set "points": [30, 35] # underlying data type is a List "_version" : 5 }

여기에서 “interests”에 대해 수신 중인 필드를 보면, 서버에 하나의 중복 값이 있고 두 개의 새로운 값이 있습니다. 이 경우 기본 데이터 유형이 집합이므로 Automerge는 서버에 있는 값과 수신 중인 요청의 값을 결합하여 중복을 제거합니다. 마찬가지로 하나의 중복 값과 하나의 새로운 값이 있는 “points” 필드에는 충돌이 있습니다. 그러나 여기에서는 기본 데이터 유형이 목록이므로, Automerge는 수신 중인 요청의 모든 값을 서버에 이미 있는 값의 끝에 추가하기만 합니다. 그 결과, 서버에 저장된 병합 이미지는 다음과 같이 나타납니다.

{ "id" : 1, "name" : "Nadia", "jersey" : 5, "interests" : ["breakfast", "lunch", "dinner", "brunch"] # underlying data type is a Set "points": [24, 30, 27, 30, 35] # underlying data type is a List "_version" : 7 }

이제 서버에 저장된 항목이 버전 8에서 다음과 같이 표시된다고 가정해 봅시다.

{ "id" : 1, "name" : "Nadia", "jersey" : 5, "interests" : ["breakfast", "lunch", "dinner", "brunch"] # underlying data type is a Set "points": [24, 30, 27, 30, 35] # underlying data type is a List "stats": { "ppg": "35.4", "apg": "6.3" } "_version" : 8 }

그러나 이번에도 버전 불일치로 수신 중인 요청이 다음 이미지로 항목을 업데이트하려고 시도합니다.

{ "id" : 1, "name" : "Nadia", "stats": { "ppg": "25.7", "rpg": "6.9" } "_version" : 3 }

이제 이 시나리오에서는 서버에 이미 있는 필드가 없음을 알 수 있습니다(interests, points, jersey). 또한 맵 “stats” 내의 “ppg” 값이 편집되고, 새로운 값 “rpg”가 추가되며, “apg”가 생략되고 있습니다. Automerge는 생략된 필드를 유지하므로(참고: 필드를 제거하려는 경우 일치하는 버전으로 요청을 다시 시도해야 함) 손실되는 법이 없습니다. 또한 맵 내의 필드에 동일한 규칙을 적용하므로 “ppg”에 대한 변경은 거부되지만 “apg”는 보존되고 새 필드인 “rpg”가 추가됩니다. 그 결과 이제 서버에 저장된 항목이 다음과 같이 표시됩니다.

{ "id" : 1, "name" : "Nadia", "jersey" : 5, "interests" : ["breakfast", "lunch", "dinner", "brunch"] # underlying data type is a Set "points": [24, 30, 27, 30, 35] # underlying data type is a List "stats": { "ppg": "35.4", "apg": "6.3", "rpg": "6.9" } "_version" : 9 }

Lambdas

선택할 수 있는 Lambda 해결 전략은 다음과 같습니다.

  • RESOLVE: 기존 항목을 응답 페이로드에 제공된 새 항목으로 바꿉니다. 한 번에 하나의 항목에만 동일한 작업을 다시 시도할 수 있습니다. 현재 DynamoDB PutItem & UpdateItem에 지원됩니다.

  • REJECT: 돌연변이를 거부하고 GraphQL 응답의 기존 항목에 오류를 반환합니다. 현재 DynamoDB PutItem, UpdateItem & DeleteItem에 지원됩니다.

  • REMOVE: 기존 항목을 제거합니다. 현재 DynamoDB DeleteItem에 지원됩니다.

Lambda 호출 요청

AWS AppSync DynamoDB 해석기는 에 지정된 Lambda 함수를 호출합니다LambdaConflictHandlerArn. 데이터 원본에 대해 구성된 동일한 service-role-arn을 사용합니다. 호출의 페이로드 구조는 다음과 같습니다.

{ "newItem": { ... }, "existingItem": {... }, "arguments": { ... }, "resolver": { ... }, "identity": { ... } }

필드는 다음과 같이 정의됩니다.

newItem

미리 보기 항목(변형이 성공한 경우)입니다.

existingItem

현재 DynamoDB 테이블에 있는 항목입니다.

arguments

GraphQL 변형의 인수.

resolver

AWS AppSync 해석기에 대한 정보입니다.

identity

호출자에 대한 정보. API 키를 사용한 액세스의 경우 이 필드는 null로 설정됩니다.

페이로드의 예:

{ "newItem": { "id": "1", "author": "Jeff", "title": "Foo Bar", "rating": 5, "comments": ["hello world"], }, "existingItem": { "id": "1", "author": "Foo", "rating": 5, "comments": ["old comment"] }, "arguments": { "id": "1", "author": "Jeff", "title": "Foo Bar", "comments": ["hello world"] }, "resolver": { "tableName": "post-table", "awsRegion": "us-west-2", "parentType": "Mutation", "field": "updatePost" }, "identity": { "accountId": "123456789012", "sourceIp": "x.x.x.x", "username": "AIDAAAAAAAAAAAAAAAAAA", "userArn": "arn:aws:iam::123456789012:user/appsync" } }

Lambda 호출 응답

PutItemUpdateItem 충돌 해결

변형 RESOLVE. 응답은 다음 형식이어야 합니다.

{ "action": "RESOLVE", "item": { ... } }

item 필드는 기본 데이터 원본의 기존 항목을 대체하는 데 사용할 객체를 나타냅니다. item에 포함된 경우 기본 키와 동기화 메타데이터는 무시됩니다.

변형 REJECT. 응답은 다음 형식이어야 합니다.

{ "action": "REJECT" }

DeleteItem 충돌 해결

항목을 REMOVE합니다. 응답은 다음 형식이어야 합니다.

{ "action": "REMOVE" }

변형 REJECT. 응답은 다음 형식이어야 합니다.

{ "action": "REJECT" }

아래의 예제 Lambda 함수는 호출하는 사람과 해석기 이름을 확인합니다. 에서 만든 경우 해석기의 jeffTheAdmin REMOVE 객체 DeletePost 또는 업데이트/입력 해석기의 새 항목과의 RESOLVE 충돌입니다. 그렇지 않으면 변형이 REJECT됩니다.

exports.handler = async (event, context, callback) => { console.log("Event: "+ JSON.stringify(event)); // Business logic goes here. var response; if ( event.identity.user == "jeffTheAdmin" ) { let resolver = event.resolver.field; switch(resolver) { case "deletePost": response = { "action" : "REMOVE" } break; case "updatePost": case "createPost": response = { "action" : "RESOLVE", "item": event.newItem } break; default: response = { "action" : "REJECT" }; } } else { response = { "action" : "REJECT" }; } console.log("Response: "+ JSON.stringify(response)); return response; }

Errors

다음은 충돌 해결 프로세스 중에 발생할 수 있는 오류 목록입니다.

ConflictUnhandled

충돌 감지는 버전 불일치를 찾아내고, 충돌 핸들러는 변형을 거부합니다.

예: 낙관적 동시성 충돌 핸들러를 사용한 충돌 해결. 또는 REJECT와 함께 반환된 Lambda 충돌 핸들러.

ConflictError

충돌을 해결하려고 하면 내부 오류가 발생합니다.

예: Lambda 충돌 핸들러가 잘못된 응답을 반환했습니다. 또는 제공된 리소스 LambdaConflictHandlerArn을 찾을 수 없어 Lambda 충돌 핸들러를 호출할 수 없습니다.

MaxConflicts

충돌 해결을 위한 최대 재시도 횟수에 도달했습니다.

예: 동일한 객체에 대한 동시 요청이 너무 많습니다. 충돌이 해결되기 전에 객체가 다른 클라이언트에 의해 새 버전으로 업데이트됩니다.

BadRequest

클라이언트는 메타데이터 필드(_version, _ttl, _lastChangedAt, _deleted)를 업데이트하려고 합니다.

예: 클라이언트가 업데이트 변형_version이 있는 객체를 업데이트하려고 합니다.

DeltaSyncWriteError

델타 동기화 레코드를 쓰지 못했습니다.

예: 변형이 성공했지만 델타 동기화 테이블에 쓰려고 할 때 내부 오류가 발생했습니다.

InternalFailure

내부 오류가 발생했습니다.

UnsupportedOperation

지원되지 않는 작업 'X'. Datasource Versioning은 다음 작업(TransactGetItems,,ScanPutItemBatchGetItem,Query,GetItem,DeleteItem,UpdateItem,,Sync)만 지원합니다.

예: 충돌 감지/해결이 활성화된 상태에서 특정 트랜잭션 및 배치 작업 사용. 이러한 작업은 현재 지원되지 않습니다.

CloudWatch 로그

가 로깅 설정이 필드 수준 CloudWatch 로그로 설정되어 있고 필드 수준 로그enabled가 로 설정되어 있는 로그를 활성화한 경우 AWS AppSync API ALL AWS AppSync 는 로그 그룹에 충돌 감지 및 해결 정보를 내보냅니다. 로그 메시지 형식에 대한 자세한 내용은 충돌 탐지 및 동기화 로깅 설명서를 참조하십시오.