중급6분 분량

DynamoDB의 싱글톤 아이템

싱글톤 아이템은 애플리케이션 전체의 상태를 담는, 고정되고 하드코딩된 키를 가진 단일 행입니다 — 사용자별이나 주문별 레코드가 아니라, 하나의 레코드, 그게 전부입니다. 피처 플래그, 설정 블롭, 전역 킬스위치 — 관계형 앱이라면 한 행짜리 설정 테이블에 둘 법한 그런 것들입니다.

SQL에서 왔다면 id = 1config 테이블과 SELECT * FROM config에 손을 뻗을 겁니다. DynamoDB에서는 하드코딩된 파티션 키로 같은 일을 합니다 — 그리고 그 키를 항상 알고 있으므로, QueryScan이 아니라 GetItem으로 읽습니다.

DynamoDB에서 싱글톤 아이템이란 무엇인가요?

싱글톤 아이템은 고정되고 하드코딩된 키 아래에 저장된 단일 DynamoDB 행으로, 사용자별이나 주문별 레코드가 아니라 애플리케이션 전체의 전역 상태 — 피처 플래그, 설정 블롭, 시스템 전체 버전 — 를 담습니다. 그 키를 항상 알고 있으므로, GetItem으로 읽고 업데이트 표현식 및 조건 표현식으로 업데이트합니다.

  • 싱글톤은 상수 키를 가진 아이템 하나입니다. 사용자나 주문 id를 템플릿으로 채우는 대신, 코드에 PK/SK(예: CONFIG#GLOBAL)를 하드코딩합니다.
  • Scan이 아니라 GetItem으로 읽으세요. 전체 키를 항상 알고 있으므로, 포인트 읽기는 필터도 없고 테이블 순회도 없는, 일관되고 예측 가능한 한 번의 RCU입니다.
  • 정의상 핫 키입니다. 모든 요청이 같은 파티션을 건드릴 수 있으므로, 캐시하고 아이템을 작게 유지하세요. 쓰기 병목이 되게 하지 마세요.
  • 업데이트 + 조건 표현식으로 안전하게 변경하세요. 앱에서 읽기-수정-쓰기를 하지 마세요 — 바로 거기에 손실 업데이트 경합이 살고 있습니다.

패턴 알아보기

데이터가 어떤 단일 엔터티에 종속되지 않을 때 전역 상태가 생깁니다. 몇 가지 신호:

  • 모두에게 동일한 플래그(signup_enabled = false).
  • 앱이 부팅 시 읽는 조정값 블롭(속도 제한, 기본 쿼터).
  • 행별이 아닌 시스템 전체를 위한 카운터나 버전 번호.

사용자, 테넌트, 주문에 종속된 것은 무엇이든 싱글톤이 아닙니다 — 그건 그 엔터티의 id로 키가 지정된 평범한 아이템입니다. 싱글톤은 달리 둘 데가 없는 남겨진 전역 조각입니다.

상수 키를 주세요

이 패턴 전체는 한 가지 결정에 달려 있습니다. 키는 템플릿이 아니라 리터럴이라는 것입니다. 오버로드된 단일 테이블에 있는 전역 피처 플래그 아이템이라면, 고정 접두사와 고정 값을 고르세요:

PKSKattributes
SETTINGS#APPFLAGS#V1signup_enabled, maintenance_mode, ai_search_enabled

PK = "SETTINGS#APP"SK = "FLAGS#V1"은 코드에 박혀 있습니다. 사용자 id도, 테넌트 id도 없습니다 — 애플리케이션은 매번 정확히 이 아이템을 요청합니다. 그 예측 가능성이 핵심입니다. 알려진 키는 GetItem이고, GetItem은 DynamoDB가 제공하는 가장 저렴하고 가장 일관된 읽기입니다.

V1 접미사는 의도적입니다. 나중에 플래그 스키마의 형태가 바뀌면, 살아 있는 아이템을 제자리에서 변경하는 대신 FLAGS#V2 아이템을 쓰고 읽는 쪽을 넘깁니다. 싱글톤 키에 버전을 매기면 깔끔한 마이그레이션 이음새를 얻습니다.

GetItem으로 읽으세요

키가 완전히 알려져 있으므로, 싱글톤에 대해서는 절대 QueryScan도 하지 않습니다. Scan은 테이블 전체를 읽고 클라이언트 측에서 필터링합니다 — 고전적인 Scan 지뢰 — 그리고 직접 주소를 지정할 수 있는 행 하나를 가져오는 데에는 터무니없는 과잉입니다.

SETTINGS#APP / FLAGS#V1에 대한 GetItem은 강력한 일관성 또는 최종적 일관성 읽기 한 번으로 플래그를 반환합니다. AWS는 ≤ 4 KB 아이템의 GetItem을 최종적 일관성 0.5 RCU 또는 강력한 일관성 1 RCU로 과금합니다 (AWS 읽기/쓰기 용량 문서). 싱글톤을 작게 유지하면 그 비용은 영원히 평평하게 유지됩니다.

읽기 경로는 단순합니다. 앱이 부팅되거나 요청이 들어오면, 고정 키를 GetItem하고 결과를 캐시합니다. 흐름은 다음과 같습니다.

아니오 / 요청GetItem PK=SETTINGS#APPSK=FLAGS#V1아이템 발견?플래그 사용, 로컬에 캐시안전한 기본값으로 폴백

고정 키는 전역 조회를, 기본 경로가 내장된 하나의 포인트 읽기로 바꿔 줍니다.

아니오 분기를 주목하세요. 싱글톤이 없다고 해서 절대 앱이 죽으면 안 됩니다. 안전한 값(피처 꺼짐, 유지보수 켜짐)으로 기본 처리해, 첫 배포 시의 공백이나 잘못된 키가 열린 상태가 아니라 닫힌 상태로 실패하게 하세요.

경합 없이 업데이트하세요

함정은 앱에서 읽기-수정-쓰기로 싱글톤을 업데이트하는 것입니다. 플래그를 GetItem하고, 메모리에서 하나를 뒤집은 다음, 전체를 다시 PutItem합니다. 두 동시 작성기가 모두 옛 아이템을 읽고, 두 번째 Put이 첫 번째의 변경을 덮어씁니다. 손실 업데이트입니다.

두 가지 DynamoDB 기능이 앱 측 잠금 없이 경합을 없앱니다:

  • 업데이트 표현식은 나머지는 건드리지 않고 한 속성을 서버 측에서 변경합니다. 전체 아이템을 다시 Put할 필요가 없습니다.
  • 조건 표현식은 아이템이 여전히 여러분이 기대하는 모습일 때만 쓰기가 성공하게 만들어, 오래된 쓰기는 ConditionalCheckFailedException으로 거부됩니다 (AWS 조건 표현식 문서).

플래그 하나를 뒤집으려면, SET으로 그 속성만 겨냥하고 동시 작성기가 서로를 짓밟지 못하도록 버전 증가로 보호하세요:

# UpdateItem
Key                  PK=SETTINGS#APP  SK=FLAGS#V1
UpdateExpression     SET signup_enabled = :on, schema_version = :next
ConditionExpression  schema_version = :current

두 작성기가 경합하면, 두 번째의 schema_version = :current 검사가 실패하고 갱신된 값에 대해 재시도합니다. 이 이름, 값, 그리고 정확히 이 표현식 형태를 DynamoDB 표현식 빌더에서 미리 짜 본 뒤 코드에 연결할 수 있습니다. 연산자를 더 깊이 살펴보려면 업데이트 표현식 관용구 가이드를 참고하세요.

핫 키에 주의하세요

싱글톤은 구조상 핫 키입니다 — 앱의 모든 부분이 같은 파티션을 읽을 수 있습니다. 캐시한다면 읽기에는 괜찮지만, 이 패턴의 하나뿐인 진짜 위험입니다.

  • 적극적으로 캐시하세요. 매 요청마다가 아니라, 프로세스당(또는 N초당) 한 번 플래그를 읽으세요. 싱글톤의 값은 메모이즈하기 가장 저렴한 것입니다.
  • 쓰기 핫스팟으로 만들지 마세요. 관리자가 하루에 몇 번 토글하는 플래그는 아무것도 아닙니다. 매 요청마다 증가시키는 싱글톤은 파티션 처리량 병목입니다 — 그건 싱글톤 문제가 아니라 카운터 문제입니다.
  • 작게 유지하세요. 읽기 비용은 아이템 크기에 따라 4 KB 블록 단위로 늘어납니다. 비대해진 설정 블롭은 매 부팅을 필요 이상으로 비싸게 만듭니다.

쓰기가 많은 전역 카운터가 정말로 필요하다면, 싱글톤은 잘못된 형태입니다 — N개의 아이템에 샤딩하고 읽을 때 합산하세요. 그건 다른 패턴입니다.

싱글톤 vs 엔터티별 아이템

경계는 단순히 데이터가 무엇에 종속되는가 입니다.

싱글톤 아이템엔터티별 아이템
하드코딩된 상수(SETTINGS#APP)id로 템플릿화(USER#42)
개수정확히 하나사용자 / 주문 / 테넌트당 하나
전형적 읽기알려진 키에 대한 GetItem엔터티별 GetItem 또는 Query
범위애플리케이션 전체단일 엔터티
용도전역 플래그, 설정, 시스템 버전프로필, 주문, id별인 것 무엇이든

같은 종류의 싱글톤을 원하고 있다면, 그건 싱글톤이 아닙니다 — 엔터티별 아이템인데 키로 지정하는 걸 깜빡한 그 엔터티(이를테면 테넌트별 설정)가 있는 것입니다.

함정과 다음 단계

  • 그걸 위해 Scan하지 마세요. 키를 알고 있습니다. 직접 주소를 지정하세요.
  • 읽기-수정-쓰기 하지 마세요. 업데이트 + 조건 표현식을 사용하세요.
  • 조용히 사라지게 두지 마세요. 캐시 미스 시 안전한 값으로 기본 처리하세요.
  • 고빈도 쓰기로 과부하시키지 마세요. 그건 샤딩된 카운터의 일입니다.

싱글톤은 단일 테이블 설계 안에서 편안하게 삽니다 — 엔터티 행들 옆에 고정 키를 가진 하나의 아이템 컬렉션이 더 있을 뿐입니다.

DynoTable을 사용해 보세요 — 테이블을 둘러보고, 고정 키로 싱글톤 행을 찾고, 쓰기 경로를 만드는 동안 플래그를 손으로 편집할 수 있습니다.

업데이트됨