Amazon DynamoDB Transactions: 작동 방식 - Amazon DynamoDB

Amazon DynamoDB Transactions: 작동 방식

Amazon DynamoDB Transactions를 사용하면 여러 작업을 그룹화하고 하나의 양자택일 TransactWriteItems 또는 TransactGetItems 작업으로 제출할 수 있습니다. 다음 단원에서는 DynamoDB에서 트랜잭션 작업 사용과 관련된 API 작업, 용량 관리, 모범 사례 및 기타 세부 정보를 설명합니다.

TransactWriteItems API

TransactWriteItems는 최대 100개의 쓰기 작업을 한 번에 모두 수행하거나 아무것도 수행하지 않는 작업으로 그룹화하는 동기식 idempotent 쓰기 작업입니다. 이러한 작업에서는 동일한 AWS 계정과 동일한 리전에 속한 하나 이상의 DynamoDB 테이블에서 최대 100개의 개별 항목을 대상으로 지정할 수 있습니다. 트랜잭션 내 항목의 총 크기는 4MB를 초과할 수 없습니다. 작업은 원자 단위로 완료되므로 작업이 모두 성공하거나 모두 실패하게 됩니다.

참고
  • TransactWriteItems 작업은 BatchWriteItem 작업과 달리 포함된 작업이 모두 성공적으로 완료되거나 전혀 변경되지 않아야 합니다. BatchWriteItem 작업에서는 배치 내 일부 작업만 성공하고 나머지는 실패할 수 있습니다.

  • 인덱스를 사용하여 트랜잭션을 수행할 수 없습니다.

동일한 트랜잭션 내에서 동일한 항목을 여러 작업의 대상으로 지정할 수 없습니다. 예를 들어 동일한 트랜잭션에서 동일한 항목에 대해 ConditionCheck 작업과 Update 작업을 동시에 수행할 수 없습니다.

다음과 같은 유형의 작업은 동일한 트랜잭션에 추가할 수 있습니다.

  • Put - PutItem 작업을 시작하여 조건부로 또는 조건을 지정하지 않고 새 항목을 생성하거나 이전 항목을 새 항목으로 바꿉니다.

  • Update - UpdateItem 작업을 시작하여 기존 항목의 속성을 편집합니다. 아직 항목이 없는 경우 새 항목을 테이블에 추가합니다. 이 작업을 사용하여 조건부로 또는 조건을 적용하지 않고 기존 항목에 대한 속성을 추가, 삭제 또는 업데이트할 수 있습니다.

  • Delete - DeleteItem 작업을 시작하여 테이블에서 기본 키로 식별된 단일 항목을 삭제합니다.

  • ConditionCheck - 항목이 있는지 확인하거나 항목의 특정 속성에 대한 조건을 검사합니다.

트랜잭션이 완료된 이후에 트랜잭션에 대한 변경 사항이 글로벌 보조 인덱스(GSI), 스트림 및 백업에 최종적으로 전파됩니다. 전파는 즉시 또는 즉각적으로 이루어지지 않기 때문에 전파 중간에 테이블을 백업에서 복원하거나(RestoreTableFromBackup) 특정 시점으로 내보낸(ExportTableToPointInTime) 경우에는 최근 트랜잭션 동안 수행된 변경 사항의 일부만이 포함될 수 있습니다.

멱등성

TransactWriteItems를 호출할 때 요청이 멱등성인지 확인하기 위해 클라이언트 토큰을 선택적으로 포함할 수 있습니다. 트랜잭션을 멱등성으로 지정하면 연결 시간 초과 또는 기타 연결 문제로 인해 동일한 작업이 여러 번 제출될 경우에 애플리케이션 오류를 방지할 수 있습니다.

원래 TransactWriteItems 호출이 성공한 경우 동일한 클라이언트 토큰을 포함하는 후속 TransactWriteItems 호출은 변경 없이 성공적으로 반환됩니다. ReturnConsumedCapacity 파라미터를 설정한 경우 초기 TransactWriteItems 호출은 변경하는 데 사용된 쓰기 용량 단위 수를 반환합니다. 동일한 클라이언트 토큰을 포함하는 후속 TransactWriteItems 호출은 항목을 읽는 데 사용된 읽기 용량 단위 수를 반환합니다.

멱등성에 대한 중요 사항
  • 클라이언트 토큰은 해당 토큰을 사용하는 요청이 완료된 후 10분 동안 유효합니다. 10분이 경과한 이후에는 동일한 클라이언트 토큰을 사용하는 모든 요청이 새 요청으로 처리됩니다. 10분이 경과한 이후에는 동일한 요청에 대해 동일한 클라이언트 토큰을 재사용하면 안 됩니다.

  • 10분 멱등성 기간 내에 동일한 클라이언트 토큰으로 요청을 반복하지만 일부 다른 요청 파라미터를 변경할 경우 DynamoDB는 IdempotentParameterMismatch 예외를 반환합니다.

쓰기 오류 처리

다음과 같은 경우 쓰기 트랜잭션이 실패합니다.

  • 조건식 중 하나의 조건이 충족되지 않는 경우

  • 동일한 TransactWriteItems 작업 내 여러 작업에서 동일한 항목을 대상으로 지정하여 트랜잭션 검증 오류가 발생하는 경우

  • TransactWriteItems 요청이 TransactWriteItems 요청에 있는 한 개 이상의 항목에 대한 지속적 TransactWriteItems 작업과 충돌하는 경우 이 경우 요청은 실패하고 TransactionCanceledException이 반환됩니다.

  • 트랜잭션을 완료하기 위한 프로비저닝 용량이 부족한 경우

  • 트랜잭션에 의한 변경으로 인해 항목 크기가 지나치게 커지거나(400KB 초과), 로컬 보조 인덱스(LSI)가 너무 커지거나, 유사한 검증 오류가 발생하는 경우

  • 사용자 오류(예: 잘못된 데이터 형식)가 발생하는 경우

TransactWriteItems 작업과의 충돌을 처리하는 방법에 대한 자세한 내용은 DynamoDB의 트랜잭션 충돌 처리 단원을 참조하십시오.

TransactGetItems API

TransactGetItems는 최대 100개의 Get 작업을 함께 그룹화하는 동기식 읽기 작업입니다. 이러한 작업에서는 동일한 AWS 계정과 리전에 속한 하나 이상의 DynamoDB 테이블에서 최대 100개의 개별 항목을 대상으로 지정할 수 있습니다. 트랜잭션 내 항목의 총 크기는 4MB를 초과할 수 없습니다.

Get 작업은 원자 단위로 수행되므로 작업이 모두 성공하거나 모두 실패하게 됩니다.

  • Get - GetItem 작업을 시작하여 지정된 기본 키의 항목에 대한 속성 집합을 검색합니다. 일치하는 항목이 없으면 Get이 데이터를 반환하지 않습니다.

읽기 오류 처리

다음과 같은 경우 읽기 트랜잭션이 실패합니다.

  • TransactGetItems 요청이 TransactGetItems 요청에 있는 한 개 이상의 항목에 대한 지속적 TransactWriteItems 작업과 충돌하는 경우 이 경우 요청은 실패하고 TransactionCanceledException이 반환됩니다.

  • 트랜잭션을 완료하기 위한 프로비저닝 용량이 부족한 경우

  • 사용자 오류(예: 잘못된 데이터 형식)가 발생하는 경우

TransactGetItems 작업과의 충돌을 처리하는 방법에 대한 자세한 내용은 DynamoDB의 트랜잭션 충돌 처리 단원을 참조하십시오.

DynamoDB Transactions의 격리 수준

트랜잭션 작업(TransactWriteItems 또는 TransactGetItems) 및 기타 작업의 격리 수준은 다음과 같습니다.

직렬화

직렬화 격리 수준에서는 여러 동시 작업의 결과가 이전 작업이 완료된 때까지 다른 작업이 시작되지 않는 경우와 동일합니다.

다음과 같은 작업 유형 간에는 직렬화 격리가 존재합니다.

  • 트랜잭션 작업과 표준 쓰기 작업(PutItem, UpdateItem 또는 DeleteItem) 사이

  • 트랜잭션 작업과 표준 읽기 작업(GetItem) 사이

  • TransactWriteItems 작업과 TransactGetItems 작업 사이

트랜잭션 작업과 BatchWriteItem 작업의 각 표준 쓰기 사이에는 직렬화 격리가 존재하지만, 트랜잭션과 단위 BatchWriteItem 작업 사이에는 직렬화 격리가 없습니다.

그리고 트랜잭션 작업과 BatchGetItem 작업의 개별 GetItems사이의 격리 수준도 직렬화할 수 있습니다. 그러나 트랜잭션과 하나의 유닛으로서 BatchGetItem 작업 사이의 격리 수준은 읽기 커밋됩니다.

단일 GetItem 요청은 TransactWriteItems 요청 이전이나 이후에 두 가지 방법 중 하나로 TransactWriteItems 요청을 기준으로 직렬화할 수 있습니다. 동시 TransactWriteItems 요청의 키에 대한 여러 GetItem 요청은 원하는 순서로 실행할 수 있으므로 결과는 읽기 커밋됩니다.

예를 들어 항목 A와 항목 B에 대한 GetItem 요청이 항목 A와 항목 B를 모두 수정하는 TransactWriteItems 요청과 동시에 실행되는 경우 네 가지 가능성이 있습니다.

  • GetItem 요청이 TransactWriteItems 요청 전에 실행됩니다.

  • GetItem 요청이 TransactWriteItems 요청 후에 실행됩니다.

  • 항목 A에 대한 GetItem 요청이 TransactWriteItems 요청 전에 실행됩니다. 항목 B의 경우는 GetItemTransactWriteItems 후에 실행됩니다.

  • 항목 B에 대한 GetItem 요청이 TransactWriteItems 요청 전에 실행됩니다. 항목 A의 경우는 GetItemTransactWriteItems 후에 실행됩니다.

여러 GetItem 요청에 직렬화 가능 격리 수준을 사용하는 것을 선호하면 TransactGetItems를 사용해야 합니다.

진행 중인 동일한 트랜잭션 쓰기 요청에 포함된 여러 항목에 대해 비트랜잭션 읽기가 수행되면 일부 항목의 새 상태와 다른 항목의 이전 상태를 읽을 수 있습니다. 트랜잭션 쓰기에 대한 응답이 성공적으로 수신된 경우에만 트랜잭션 쓰기 요청에 포함된 모든 항목의 새 상태를 읽을 수 있습니다.

읽기 커밋됨

읽기 커밋됨 격리는 읽기 작업이 항상 항목에 대해 커밋된 값을 반환하도록 합니다. 따라서 읽기는 최종적으로 성공하지 못한 트랜잭션 쓰기의 상태를 나타내는 항목에 대한 보기를 제공하지 않습니다. 읽기 커밋됨 격리는 읽기 작업 직후에 항목에 대한 수정을 막지 않습니다.

트랜잭션 작업과 여러 표준 읽기(BatchGetItem, Query 또는 Scan)를 포함하는 읽기 작업 사이에는 읽기 커밋됨 격리 수준이 있습니다. 트랜잭션 쓰기가BatchGetItem, Query, Scan 작업 중에 항목을 업데이트하는 경우 읽기 작업의 후속 부분에서 새로 커밋된 값(ConsistentRead) 사용) 또는 이전 커밋된 값(최종 읽기 일관성)을 반환합니다.

작업 요약

요약하면 다음 표는 트랜잭션 작업(TransactWriteItems 또는 TransactGetItems)과 다른 작업 사이의 격리 수준을 보여줍니다.

Operation 격리 수준

DeleteItem

직렬화

PutItem

직렬화

UpdateItem

직렬화

GetItem

직렬화

BatchGetItem

읽기 커밋됨*

BatchWriteItem

직렬화 불가*

Query

읽기 커밋됨

Scan

읽기 커밋됨

기타 트랜잭션 작업

직렬화

별표(*) 표시된 수준은 작업에 하나의 단위로 적용됩니다. 하지만 이러한 작업 내의 개별 작업에는 직렬화 격리 수준이 있습니다.

DynamoDB의 트랜잭션 충돌 처리

트랜잭션 안의 항목에 대해 항목 수준에서 동시에 여러 요청이 있을 경우 트랜잭션 충돌이 발생할 수 있습니다. 다음과 같은 시나리오에서 트랜잭션 충돌이 발생할 수 있습니다.

  • 한 항목에 대핸 PutItem, UpdateItem 또는 DeleteItem 요청이 이 항목을 포함하는 진행 중인 TransactWriteItems 요청과 충돌합니다.

  • TransactWriteItems 안의 한 항목이 진행 중인 다른 TransactWriteItems 요청에 속합니다.

  • TransactGetItems 안의 한 항목이 진행 중인 TransactWriteItems, BatchWriteItem, PutItem, UpdateItem 또는 DeleteItem 요청에 속합니다.

참고
  • PutItem, UpdateItem 또는 DeleteItem 요청이 거부되면 TransactionConflictException와 함께 해당 요청에 실패합니다.

  • TransactWriteItems 또는 TransactGetItems 안의 항목 수준 요청이 하나라도 거부되면 TransactionCanceledException과 함께 해당 요청에 실패합니다. 해당 요청이 실패하면 AWS SDK는 요청을 다시 시도하지 않습니다.

    AWS SDK for Java를 사용 중인 경우 CancellationReasons의 목록이 TransactItems 요청 파라미터의 항목 목록에 따라 정렬되어 예외에 포함됩니다. 기타 언어는 목록의 문자열 표현이 예외의 오류 메시지에 포함됩니다.

  • 지속적 TransactWriteItems 또는 TransactGetItems 작업이 동시 GetItem 요청과 충돌하는 경우에는 두 작업 모두 성공할 수 있습니다.

실패한 각 항목 수준의 요청에 대해 TransactionConflict CloudWatch 지표가 증가합니다.

DynamoDB Accelerator(DAX)에서 트랜잭션 API 사용

DynamoDB와 격리 수준이 동일한 DynamoDB Accelerator(DAX)에서는 TransactWriteItemsTransactGetItems가 모두 지원됩니다​.

TransactWriteItems는 DAX를 통해 씁니다. DAX는 TransactWriteItems 호출을 DynamoDB에 전달하고 응답을 반환합니다. 쓰기 후 캐시를 채우기 위해 DAX는 TransactWriteItems 작업의 각 항목에 대해 백그라운드에서 TransactGetItems를 호출하며, 이 작업은 추가 읽기 용량 단위를 사용합니다. (자세한 설명은 트랜잭션 용량 관리 섹션을 참조하십시오.) 이 기능을 사용하면 애플리케이션 로직을 단순하게 유지할 수 있으며 트랜잭션 작업과 비트랜잭션 작업 모두에 대해 DAX를 사용할 수 있습니다.

TransactGetItems 호출은 항목을 로컬로 캐시하지 않고 DAX를 통해 전달됩니다. 이는 DAX의 강력한 읽기 일관성 API에서와 동일한 동작입니다.

트랜잭션 용량 관리

DynamoDB 테이블에 대해 트랜잭션을 활성화하는 데 추가 비용이 들지 않습니다. 트랜잭션에 포함되는 읽기 또는 쓰기에 대해서만 비용을 지불하면 됩니다. DynamoDB는 트랜잭션의 모든 항목에 대해 두 개의 기본 읽기 또는 쓰기를 수행합니다. 하나는 트랜잭션을 준비하고, 하나는 트랜잭션을 커밋하기 위한 것입니다. 이 두 개의 기본 읽기/쓰기 작업은 Amazon CloudWatch 지표로 표시됩니다.

테이블에 대한 용량을 프로비저닝할 때 트랜잭션 API에 필요한 추가 읽기 및 쓰기를 계획합니다. 예를 들어, 애플리케이션은 초당 1개의 트랜잭션을 실행하고 각 트랜잭션은 테이블에서 500바이트 항목 3개를 쓴다고 가정합니다. 각 항목은 각각 트랜잭션 준비 및 커밋을 위한 2개의 쓰기 용량 단위(WCU)가 필요합니다. 따라서 테이블에 대해 6 WCU를 프로비저닝해야 합니다.

이전 예제에서 DynamoDB Accelerator(DAX)를 사용하는 경우에도 TransactWriteItems 호출의 각 항목에 대해 두 개의 읽기 용량 단위(RCU)를 사용하게 됩니다. 따라서 테이블에 대해 6 WCU를 추가로 프로비저닝해야 합니다.

마찬가지로 애플리케이션이 초당 1개의 쓰기 트랜잭션을 실행하고 각 트랜잭션이 테이블에서 500바이트 항목 3개를 읽는 경우 테이블에 대해 6개의 읽기 용량 단위(RCU)를 프로비저닝해야 합니다. 각 항목을 읽는 데 2 RCU(트랜잭션 준비 및 커밋)가 필요합니다.

또한 기본 SDK 동작에서는 TransactionInProgressException 예외가 발생할 경우 트랜잭션을 다시 시도합니다. 이러한 재시도에서 사용되는 추가 읽기 용량 단위(RCU)를 계획합니다. ClientRequestToken을 사용하여 자체 코드에서 트랜잭션을 재시도하는 경우에도 마찬가지입니다.

트랜잭션 모범 사례

DynamoDB 트랜잭션을 사용할 경우 다음과 같은 권장 방법을 고려하세요.

  • 테이블에서 Auto Scaling을 활성화하거나, 트랜잭션의 모든 항목에 대해 2회의 읽기 또는 쓰기 작업을 수행하는 데 충분한 처리량을 프로비저닝했는지 확인합니다.

  • AWS 제공 SDK를 사용하지 않을 경우 TransactWriteItems를 호출할 때 요청이 멱등성인지 확인하도록 ClientRequestToken 속성을 포함합니다.

  • 필요하지 않은 경우 트랜잭션에서 작업을 그룹화하지 않습니다. 예를 들어, 애플리케이션 동시성을 훼손하지 않으면서 10개 작업을 포함하는 단일 트랜잭션을 여러 트랜잭션으로 분류할 수 있는 경우 트랜잭션을 분할하는 것이 좋습니다. 트랜잭션이 간단할수록 처리량이 향상되어 성공할 가능성이 더 높아집니다.

  • 여러 트랜잭션에서 동일한 항목을 동시에 업데이트할 경우 충돌이 발생하여 트랜잭션이 취소될 수 있습니다. 그런 충돌을 최소화하려면 데이터 모델링에 대한 DynamoDB 모범 사례를 따르는 것이 좋습니다.

  • 종종 속성 세트가 단일 트랜잭션의 일부로 여러 항목에 걸쳐 업데이트되는 경우 속성을 단일 항목으로 그룹화하여 트랜잭션의 범위를 좁히는 것이 좋습니다.

  • 대량으로 데이터를 수집하는 트랜잭션을 수행하지 마십시오. 대량 쓰기의 경우 BatchWriteItem을 사용하는 것이 좋습니다.

전역 테이블에 트랜잭션 API 사용

DynamoDB 트랜잭션 내에 포함된 작업은 트랜잭션이 처음 실행된 리전에서만 트랜잭션이 보장됩니다. 트랜잭션 내에 적용된 변경 사항이 리전 간 글로벌 테이블 복제본으로 복제되는 경우 트랜잭션 특성이 유지되지 않습니다.

DynamoDB Transactions와 AWSLabs 트랜잭션 클라이언트 라이브러리 비교

DynamoDB Transactions는 AWSLabs 트랜잭션 클라이언트 라이브러리보다 경제적이고 강력하고 성능이 우수한 대체 방법입니다. 기본 서버측 트랜잭션 API를 사용하도록 애플리케이션을 업데이트하는 것이 좋습니다.