
분산 시스템인 NoSQL은 대부분 CAP 이론을 따른다. 이는 분산 시스템이 일관성(Consistency), 가용성(Availability), 분할 내성(Partition Tolerance) 세 가지 중 두 가지만 보장할 수 있다는 원칙이다.
분산 네트워크 환경에서 시스템은 가용성(AP) 또는 일관성(CP) 중 하나를 우선해야 한다. DynamoDB는 이 CAP 이론을 위배하지 않으면서도 요청별로 사용자가 두 가지 모드(Strong Consistency or Eventual Consistency) 중 하나를 선택할 수 있도록 하여 AP와 CP 모두를 지원한다.
: 가장 최신 상태의 데이터를 반환하도록 보장한다.
: 강한 일관성 읽기보다 빠르고 비용 효율적이지만, 쓰기 직후에 데이터가 최신 상태가 아닐 수 있다.
DynamoDB는 요청 시 간단한 Boolean flag를 사용하여 일관성 수준을 설정할 수 있도록 한다.
| 모드 | 장점 | 단점 | 적합한 사례 |
|---|---|---|---|
| 강한 일관성 | 최신 데이터 보장. SERIALIZABLE 격리 수준 | 비용이 두 배 높음. 가용성이 떨어질 수 있음. | 은행 거래 검증, 실시간 재고 관리 등. |
| 최종 일관성 | 비용 효율적(절반). 높은 가용성 및 처리량 | 쓰기 직후 데이터가 stale data일 수 있음. | 소셜 미디어 좋아요/댓글 수, 개인 프로필 세부 정보 업데이트 등. |
DynamoDB가 지원하는 read API는 다음과 같다.
가장 간단한 키-값 조회(key-value lookup)를 제공한다.
잘못된 키를 제공하면 오류가 아닌 빈 목록을 반환한다.
제한 사항:
GetItem은 보조 인덱스(GSI or LSI)에서는 수행될 수 없다. 보조 인덱스는 다른 키 구조를 사용하므로 (예: GSI는 다른 attribute를 Partition Key나 Sort Key로 가질 수 있다), 보조 인덱스의 키만으로는 '항목이 유일하다'는 보장이 없다.
개별 GetItem 요청들을 배치로 묶어 실행할 수 있게 해준다.
단일 네트워크 요청으로 최대 100개의 개별 GetItem 요청을 처리합니다.
(network round trips를 줄여 밀리초 단위의 성능을 최적화한다.)
항목 컬렉션(동일한 PK를 공유하는 항목 그룹)을 읽는 가장 효율적인 방법이다.
동일한 파티션 키(PK) 값을 가지지만 정렬 키(SK) 값이 다를 수 있는 하나 이상의 항목을 검색한다. (PK 값과 1:M 관계를 공유하는 항목을 처리할 때 유용함)
begins_with()와 같은 함수를 정렬 키에 사용하여 여러 관련 엔터티를 단일 요청으로 검색할 수 있다.Query 응답은 최대 1MB의 항목으로 제한됩니다. 이 제한을 초과하면 LastEvaluatedKey 요소가 반환되어, 클라이언트가 후속 요청을 통해 다음 페이지의 결과를 요청해야 합니다.DynamoDB 테이블 데이터에 액세스하는, 유연하지만 Resource-intensive Operation(많은 자원을 요구)이다.
SCAN allows filtering on every attribute in the data, supporting functions such as contains(), logical AND/OR operators, and more.--생략--
DynamoDB의 단일 항목 작업은 본질적으로 ACID이지만, 특정 트랜잭션 API는 다중 항목 작업에도 ACID를 보장한다.
DynamoDB는 기존 RDBMS와 달리 명시적인 트랜잭션 시작/종료 지시어가 없다.
DynamoDB 트랜잭션의 경우, all-or-nothing으로 실행되어야 하는 모든 Put, Update, Delete 작업은 단일 트랜잭션 쓰기 요청에 포함되어야 한다. 마찬가지로, all-or-nothing으로 실행되어야 하는 모든 읽기 작업은 단일 트랜잭션 읽기 요청에 포함되어야 한다.
읽기 또는 쓰기 트랜잭션 요청에 포함된 항목이 다른 진행 중인 트랜잭션의 일부인 경우, 최신 트랜잭션 요청은
TransactionConflictException과 함께 즉시 취소된다.
쓰기 트랜잭션 요청에는 조건 검사(condition check) 외의 작업으로는 오직 쓰기 작업만 허용된다. 즉, DynamoDB의 쓰기 트랜잭션 API 중 하나인 TransactWriteItems API에는 다음 작업이 포함될 수 있다.
단일 TransactWriteItems 요청은 Put, Update, Delete, ConditionCheck를
조합하여 최대 100개의 작업을 허용한다.
트랜잭션 내부 매커니즘: 2단계 프로토콜
- PREPARE: 트랜잭션 읽기 또는 쓰기 요청 내의 모든 작업은 오류, 조건 검사, 스로틀링 예외, 트랜잭션 충돌에 대해 검증된다. 검증에 실패하면 COMMIT은 절대 실행되지 않고 해당하는 예외와 함께 트랜잭션이 거부된다.
- COMMIT: 검증된 작업들은 트랜잭션에 기여하는 모든 백엔드 노드에 의해 병렬로 커밋된다.
다중 항목 ACID 준수가 절대적으로 필요한 경우
금융 거래 검증이나 복잡한 일관성 요구 사항이 있는 시나리오와 같이, read-after-write consistency와 all-or-nothing이 필수적일 때 사용된다.
복잡한 작업의 회피
만약 ACID가 필수적이지 않다면, 벌크 업데이트(BatchWriteItem, BatchGetItem)와 같은 비트랜잭션 연산이 더 적합하며, 비용 절감, 평균 지연 시간 개선, 복잡성 감소 및 고가용성을 제공할 수 있다.
여러 항목을 한 번에 쓰면서 all-or-nothing 동작을 보장하려는 경우, 읽기 작업에도 트랜잭션 API를 사용하는 것이 바람직하다. 트랜잭션 쓰기 중 COMMIT 단계가 병렬로 실행되기 때문입니다.
DynamoDB는 가용 영역(AZ)에 걸쳐 분산된 저장 노드로 구성된 분산 시스템이기 때문에, COMMIT 단계에서 각 노드가 병렬로 요청을 독립적으로 처리한다.
따라서, 트랜잭션이 아직 진행 중인 상태에서 트랜잭션에 포함된 항목에 대해 비트랜잭션 읽기를 수행하면, 일부 노드는 COMMIT을 완료했지만 다른 노드는 완료하지 못한 상태일 수 있다.
따라서 이 경우, 최신 커밋된 데이터를 읽을 수도, 읽지 못할 수도 있는 상황이 발생할 수 있다.