중급5분 분량

DynamoDB 강력한 일관성 대 최종적 일관성 읽기

아이템을 갱신하고 곧바로 다시 읽었는데 옛 값이 돌아옵니다. 쓰기는 성공했고 — 잠시 뒤 같은 읽기가 새 값을 돌려줍니다. 망가진 건 없습니다. DynamoDB의 기본인 최종적 일관성 읽기에 부딪힌 것이고, 요청마다 이를 끌 수 있습니다.

이것은 DynamoDB가 직접 여러분 손에 쥐여주는 몇 안 되는 정합성 손잡이 중 하나이고, 실제 대가가 따라붙습니다. 제대로 쓰려면 각 모드가 무엇을 보장하는지, 비용이 얼마인지, 그리고 강력한 읽기가 아예 제공되지 않는 곳이 어디인지 알아야 합니다.

DynamoDB에서 강력한 일관성 읽기와 최종적 일관성 읽기의 차이는 무엇인가요?

최종적 일관성 읽기(기본값)는 아무 복제본에서나 처리되므로 쓰기 직후 잠깐 묵은 데이터를 돌려줄 수 있지만, 비용은 절반입니다. 강력한 일관성 읽기는 요청마다 ConsistentRead=true로 켜며, 파티션 리더로 라우팅되어 커밋된 모든 쓰기를 항상 반영합니다 — 그 대가로 읽기 용량은 2배입니다.

  • 최종적 일관성(기본값) — 쓰기 직후 잠깐 묵은 데이터를 돌려줄 수 있습니다. 가장 저렴한 읽기 모드입니다.
  • 강력한 일관성 — 읽기 전에 커밋된 모든 쓰기를 항상 반영합니다. 요청마다 ConsistentRead=true로 켜세요.
  • 강력한 읽기는 최종적 읽기의 2배 비용입니다. 같은 데이터에 대해 강력한 일관성 읽기는 최종적 일관성 읽기의 두 배 읽기 용량을 소모합니다.
  • 어디서나 되는 건 아닙니다. 강력한 읽기는 베이스 테이블과 로컬 보조 인덱스에서 가능합니다. 글로벌 보조 인덱스는 최종적 일관성 전용이라 끌 수 없습니다.
  • 기본은 최종적 일관성으로. 방금 자신이 쓴 데이터를 읽는데 한순간 묵은 값이 틀린 답이 될 때만 강력한 읽기를 꺼내 쓰세요.

문제: 최신 쓰기를 못 보는 읽기

사용자 계정 서비스를 운영한다고 합시다. 사용자가 알림 이메일을 바꾸면, 앱이 그 갱신을 쓰고, 확인 화면이 곧바로 프로필을 다시 읽어 새 주소를 보여줍니다. 기본 읽기 모드에서는 그 재읽기가 아직 변경을 받지 못한 복제본에 닿을 수 있고 — 그래서 사용자는 자신의 이메일을 보고 저장이 실패했다고 단정합니다.

그 창은 작고(보통 1초 한참 아래) 저절로 닫힙니다. 하지만 "대체로 맞음"은 읽기-직후-쓰기 확인에는 충분하지 않습니다. 바로 그 경우를 위해 강력한 일관성이 존재합니다.

최종적 일관성이 생기는 이유

DynamoDB는 모든 파티션을 별개의 가용 영역에 걸쳐 세 개의 스토리지 노드 — 하나의 프라이머리와 두 개의 복제본 — 에 저장합니다. 쓰기는 프라이머리와 한 복제본에 안착하면 확인 응답되고, 그다음 세 번째 노드로 비동기로 전파됩니다.

읽기는 부하를 분산하려고 세 노드 아무거나가 처리할 수 있습니다. 최종적 일관성 읽기는 가장 최근 쓰기를 아직 받지 못한 노드에 닿을 수 있어 — 약간 묵은 값을 돌려줍니다. 강력한 일관성 읽기는 항상 최신 커밋 데이터를 쥐고 있는 파티션 리더로 라우팅되므로 결코 묵은 결과를 돌려주지 않습니다.

sync, acknowledgedasync, lags brieflymay hit a lagging nodeWrite: new emailPrimary nodeReplica 1Replica 2Strongly consistent readEventually consistent read

그 복제 지연이 차이의 전부입니다. 그것이 2배 비용도 설명합니다. 강력한 읽기는 최종적 읽기처럼 복제본에 걸쳐 부하 분산을 할 수 없으므로 DynamoDB는 두 배 용량으로 가격을 매깁니다.

비용을 구체적으로

읽기는 각각 최대 4 KB를 포괄하는 읽기 용량 단위(RCU)로 계량됩니다. 1 RCU는 4 KB 아이템의 강력한 일관성 읽기 한 번 또는 최종적 일관성 읽기 두 번을 삽니다. 그래서 뜨거운 읽기 경로에서 ConsistentRead=true를 켜면 읽기 비용이 두 배가 됩니다 — 트래픽 많은 엔드포인트에서는 눈에 띄는 항목입니다.

전면적으로 강력한 읽기를 기본값 삼기 전에 DynamoDB 요금 계산기로 여러분 자신의 아이템 크기와 요청 속도에 대한 차이를 모델링해 보세요 — 전반에 걸쳐 두 배를 무는 게 그럴 가치가 있는 경우는 드뭅니다.

강력한 읽기가 가능한(그리고 불가능한) 곳

읽기 대상강력한 일관성?
베이스 테이블예 — ConsistentRead=true로 켜기
로컬 보조 인덱스(LSI)예 — 베이스 테이블과 같은 방식으로 켜기
글로벌 보조 인덱스(GSI)아니오 — 최종적 일관성 전용, 무효화 불가

GSI는 베이스 테이블에서 비동기로 복제된 자체 데이터 사본을 유지하므로 결코 강력한 읽기를 제공할 수 없습니다. 어떤 액세스 패턴이 진정으로 읽기-직후-쓰기가 필요한데 그것을 GSI에서 처리할 계획이었다면, 대신 베이스 테이블이나 LSI에서 처리하라는 신호입니다.

함정과 다음 단계

  • 강력한 읽기를 기본값으로 삼지 마세요. 대부분의 읽기는 1초 미만의 묵은 창을 견딥니다. 어디서나 2배를 무는 것은 낭비입니다.
  • GSI에서 읽기-직후-쓰기를 기대하지 마세요. 설계상 최종적 일관성입니다 — GSI가 최종적 일관성인 이유를 보세요.
  • 트랜잭션은 강하게 읽습니다. TransactGetItems는 항상 강력한 일관성입니다 — DynamoDB 트랜잭션을 보세요.
  • 일관성은 용량과 맞물립니다. 2배 승수는 온디맨드 대 프로비저닝 비용 계획으로 곧장 이어집니다.

API 호출을 작성하지 않고 DynamoDB 테이블과 인덱스를 탐색하고 싶으신가요? DynoTable을 받아서 데이터를 직접 들여다보세요.

업데이트됨