Dynamo 논문에서 DynamoDB까지
2007년 "Dynamo: Amazon's Highly Available Key-value Store" 논문과 오늘 여러분이 호출하는 DynamoDB는 이름과 목표 — 어떤 규모에서든 예측 가능한 성능 — 를 공유하지만, 같은 시스템은 아닙니다. 논문은 여러분이 직접 운영하는 내부의 최종적 일관성 저장소를 설명했습니다. DynamoDB는 그 교훈은 지키고 대부분의 기계 장치는 던져버린 관리형 서비스입니다.
DynamoDB는 Dynamo 논문에 기반하나요?
부분적으로 그렇습니다. DynamoDB는 이름과 핵심 목표 — 규모에서의 예측 가능한 성능과 높은 가용성 — 를 2007년 Amazon Dynamo 논문에서 가져왔고, 해싱 아이디어는 거의 그대로 유지했습니다. 하지만 그것은 다른, 관리형 시스템입니다. 논문의 벡터 클록, 가십 멤버십, 조정 가능한 읽기/쓰기 쿼럼은 사라지고 AWS 소유의 내부 구조로 대체되었습니다.
- 논문은 인체공학이 아니라 가용성을 해결했습니다. 그 역할은 오래된 읽기를 반환하는 대가를 치르더라도 휴일 트래픽 급증 중에 절대 쓰기를 거부하지 않는 것이었습니다.
- DynamoDB는 모양은 유지하고 내부는 대체했습니다. 키의 해시로 파티셔닝되고, AZ 전반에 복제되며, 수평으로 확장됩니다 — 하지만 충돌 해결 내장(벡터 클록, 가십, 읽기 복구)은 사라졌습니다.
- 더 이상 손잡이를 조정하지 않습니다. 논문의
N,R,W는 하나의 선택이 되었습니다:ConsistentRead참 또는 거짓. 나머지는 AWS가 소유합니다. - 멘탈 모델은 여전히 값을 합니다. 계보를 알면 왜
Scan이 비싼지, 왜 GSI 읽기가 지연될 수 있는지 설명됩니다 — 둘 다 원래 설계에서 흘러나옵니다.
논문이 실제로 해결하려던 것
Amazon의 장바구니는 다운될 수 없었습니다. 부하 아래서 쓰기를 거부하거나 — 실패한 복제본에서 블록되는 — 관계형 데이터베이스는 용납할 수 없었습니다. 2007년 Dynamo 논문은 일관성보다 가용성을 선택했습니다: 항상 쓰기를 받아들이고, 불일치는 나중에 조정한다. 그 트레이드오프가 아래 모든 것의 뿌리입니다.
단일 마스터 없이 그렇게 하려면, Dynamo는 스스로 두 가지 질문에 답해야 했습니다. 키가 어디에 사는가, 그리고 읽기나 쓰기가 유효하기 전에 몇 개의 사본이 동의해야 하는가.
일관된 해싱: 키가 사는 곳
논문은 모든 노드를 해시 링에 배치했습니다. 키의 위치는 그 키의 해시입니다. 시계
방향으로 다음 노드가 소유하고, 뒤따르는 N-1개 노드에 복제됩니다. 노드를 추가하거나
제거하면 그 이웃들의 키만 다시 섞일 뿐 — 전체 데이터셋은 아닙니다. 그것이 일관된
해싱이고, DynamoDB가 거의 그대로 유지한 하나의 아이디어입니다.
DynamoDB는 여전히 여러분의 를 해싱해 어느 물리 파티션이
항목을 저장할지 결정합니다. 카디널리티가 낮은 파티션 키 — 예를 들어 값이 둘뿐인
STATUS — 를 고르면, 같은 값을 가진 모든 항목이 같은 파티션에 떨어집니다. 그것이
함정이고, 링의 직접적인 결과입니다: 해시가 동일한 키를
동일한 집으로 보냅니다.
쿼럼: 몇 개의 사본이 동의해야 하는가
논문의 두 번째 손잡이는 쿼럼이었습니다. N개의 복제본에서, 그중 W개가 ack하면
쓰기가 성공하고, 읽기는 그중 R개에 조회합니다. R + W > N으로 설정하면 어떤 읽기든
가장 새로운 쓰기를 가진 노드와 최소 하나는 겹칩니다 — 강력한 일관성입니다. 더 낮게
설정하면 최신성을 속도와 가동 시간과 맞바꿉니다.
Dynamo는 "느슨한" 쿼럼을 운영했습니다: 대상 노드가 다운되면 쓰기는 대타에게 가고 나중에 되돌려졌습니다(힌티드 핸드오프). 충돌하는 버전은 벡터 클록으로 태그되어 읽기 시점에 애플리케이션이 조정했습니다.
DynamoDB가 유지한 것과 바꾼 것
DynamoDB는 목표와 파티셔닝을 물려받은 다음, 원래 시스템을 운영하기 어렵게 만들던 부분들을 삭제했습니다.
| 관심사 | 2007 Dynamo 논문 | 오늘의 DynamoDB |
|---|---|---|
| 키 배치 | 일관된 해싱 링 | 파티션 키의 해시 → 관리형 파티션 |
| 복제 | N개 노드, 직접 선택 | AZ 전반 3개 사본, AWS가 고정 |
| 일관성 손잡이 | R, W 쿼럼 조정 | 하나의 플래그: ConsistentRead |
| 충돌 해결 | 벡터 클록, 읽기 시점 앱 측 병합 | 리전 내에서는 필요 없음 — 쓰기가 리더 복제본을 통해 직렬화됨; last-writer-wins는 글로벌 테이블에서 리전 간에만 |
| 멤버십 | 피어 간 가십 프로토콜 | 완전 관리형; 여러분에게 보이지 않음 |
| 다중 키 연산 | 없음 — 순수 키-값 | 위에 Query, GSI, 트랜잭션 계층화 |
논문의 API는 두 개의 호출이었습니다: get(key)와 put(key, value). DynamoDB는 같은
키-값 코어 위에 정렬 키, 인덱스, 쿼리를 더했습니다 — 그래서 Query는 저렴하고(한
파티션) Scan은 그렇지 않습니다(링이 만들어낸 모든 파티션을 훑습니다).
쓰기가 이동하는 방식, 그때와 지금
아래 흐름은 논문의 쿼럼 쓰기와 DynamoDB의 관리형 쓰기를 대비합니다. 모양은 서로 운을 맞추지만, 책임은 여러분의 코드에서 AWS로 옮겨갔습니다.
논문에서는 여러분이 쿼럼 계산과 병합을 소유했고, DynamoDB에서는 그 아래 절반 전체가
관리되며 여러분은 요청마다 ConsistentRead만 선택합니다.
계보가 여러분의 코드로 새어 나오는 곳
최종적 일관성 기본값은 논문이 비쳐 보이는 것입니다. 글로벌 보조 인덱스는 비동기적으로 복제되므로, 방금 쓴 항목이 잠시 인덱스에서 빠져 있을 수 있습니다 — 같은 "나중에 조정한다"는 거래가, 그저 인덱스 계층에서 일어날 뿐입니다. 그 지연이 중요한 때는 GSI vs LSI를 참고하세요.
강력한 일관성은 두 가지 방식으로 되사올 수 있습니다. 베이스 테이블 읽기에
ConsistentRead: true를 쓰거나(리더 사본으로 라우팅됨), 쓰기를
ConditionExpression으로 보호해 항목의 현재 상태가 일치할 때만 반영되게 하는
것입니다.
DynamoDB expression builder에서 하나 스케치해
보세요 — 예를 들어 attribute_not_exists(PK)로 PutItem을 삽입 전용 연산으로 만드는
것은 논문의 충돌 감지를 대신하는 현대적 방식입니다.
기억할 단 하나
논문은 쓰기에 절대 아니라고 말하지 않도록 최적화했습니다. DynamoDB는 그 편향을
물려받았고, 그래서 기본값이 가용성을 선호하고 강력한 읽기가 더 비쌉니다.
단일 테이블 설계처럼 단일 파티션 Query를 위해 키를
모델링하고, 정말 필요할 때만 Scan에 손을 뻗으세요 — 링은
전체 테이블 훑기를 들리는 만큼 비싸게 만듭니다.
DynoTable을 사용해 테이블과 그 GSI를 탐색하고, SQL Workbench에서 여러분 자신의 데이터에 JOIN과 GROUP BY를 실행하세요.