중급7분 분량

DynamoDB 스로틀링 — 왜 생기고 어떻게 고치나

스로틀링은 한도에 걸렸다고 DynamoDB가 알려주는 것입니다 — 그런데 서로 다른 한도가 네 개, 서로 다른 예외가 세 개 있고, 한 원인에 맞는 해결책이 다른 원인은 더 나쁘게 만듭니다. 테이블 용량을 올리는 것은 뜨거운 키에 아무 도움이 되지 않고, 온디맨드로 바꾸는 것 역시 뜨거운 키에는 도움이 되지 않으면서 자체 규칙으로 여전히 스로틀링할 수 있습니다. 이 가이드는 그 우산입니다. 여러분이 실제로 부딪힌 한도가 무엇인지, 지표가 그것들을 어떻게 구분하는지, 그리고 각 원인에 맞는 해결책이죠.

DynamoDB는 왜 내 요청을 스로틀링하나요?

문서화된 네 가지 이유 중 하나입니다. 단일 파티션이 초당 읽기 단위 3,000개 또는 쓰기 단위 1,000개라는 고정된 파티션당 한도를 넘었거나(뜨거운 키 — 두 용량 모드 모두에서 일어납니다), 테이블이 프로비저닝된 RCU/WCU를 넘었거나(프로비저닝 모드), 계정이 리전 수준 처리량 할당량을 넘었거나, 온디맨드 테이블이 30분 이내에 이전 피크의 두 배보다 빠르게 자란 경우입니다. 해결책은 그중 어느 것이었는지에 달렸으니, 무엇이든 크기를 조정하기 전에 진단하세요.

네 가지 스로틀링 시나리오

AWS 자체 문제 해결 페이지는 스로틀링을 정확히 네 가지 경우로 나눕니다.

  1. 키 범위(파티션) 처리량 초과 — 두 모드 모두. 모든 파티션은 초당 읽기 단위 3,000개와 쓰기 단위 1,000개를 최대로 설계되었으며 (파티션 키 문서), 항목 크기가 여기에 계산됩니다. 어떤 테이블 수준 설정도 이 값을 올리지 못하고, 오직 키 설계만이 이를 분산합니다. 이것이 핫 파티션 경우이며, 스로틀링되는 동안에도 테이블은 엄청나게 저활용된 것처럼 보일 수 있습니다.
  2. 프로비저닝된 처리량 초과 — 프로비저닝 모드. 소비가 테이블의(또는 GSI의) 프로비저닝된 RCU/WCU를 넘어섰고, 약 5분짜리 버스트 용량 완충이 소진된 것입니다. 해결 사다리는 용량 쪽에 있습니다. 오토 스케일링, 더 높은 프로비저닝, 또는 모드 전환이죠.
  3. 계정 수준 할당량 초과. 리전별 계정 할당량이 전체 처리량을 제한합니다 — 기본값으로 테이블당 읽기 단위 40,000개와 쓰기 단위 40,000개, 그리고 프로비저닝 모드의 경우 계정당 80,000 RCU와 80,000 WCU입니다 (할당량). 이 값들은 초기 기본값이고 Service Quotas를 통해 조정 가능하며, 온디맨드 테이블에는 계정 수준 처리량 할당량이 없습니다.
  4. 온디맨드 최대 처리량 초과. 온디맨드는 이전 피크의 두 배까지 즉시 수용합니다. 30분 이내에 두 배를 넘어서 자라면 스로틀링할 수 있습니다 (온디맨드 문서). 새 온디맨드 테이블은 기본 상태로 초당 4,000회 쓰기와 12,000회 읽기를 지탱합니다. 계획된 계단형 급증(출시, 세일, 마이그레이션)에는 램프가 완만하기를 바라는 대신 웜 스루풋으로 테이블을 사전 예열하세요.

세 가지 예외, 그리고 원인을 이름 짓는 필드

  • ProvisionedThroughputExceededException — 프로비저닝 모드 용량 스로틀링입니다. "테이블 또는 하나 이상의 글로벌 보조 인덱스에 대해 허용된 최대 프로비저닝 처리량을 초과했습니다"라는 뜻이죠. 자세한 내용은 전용 오류 페이지에 있습니다.
  • ThrottlingException — 너무 빠르게 발행된 컨트롤 플레인 작업, 그리고 온디맨드 테이블에서는 속도가 너무 높은 모든 데이터 플레인 작업입니다(두 배 피크 규칙 뒤에 있는 예외가 이것입니다 — 온디맨드 오류 페이지ThrottlingException을 보세요).
  • RequestLimitExceeded — 계정 수준 처리량 한도입니다. "AWS Support에 문의하세요" 영역이며, 해당 오류 페이지에서 다룹니다.

세 가지 모두 재시도 가능으로 표시되며, 세 가지 모두 이제 리소스 + 작업 + 한도 형태의 구조화된 ThrottlingReason 값을 담고 있습니다 — TableReadProvisionedThroughputExceeded, IndexWriteKeyRangeThroughputExceeded, TableWriteAccountLimitExceeded 같은 식이죠(오류 레퍼런스). 예외 클래스만 보지 말고 이유를 읽으세요. 리소스(테이블인지 인덱스인지), 작업 방향, 그리고 네 한도 중 어느 것에 부딪혔는지를 이름으로 알려주는데 — 그것이 바로 진단입니다. 문서 자체가 강제하는 유보가 하나 있습니다. 계정 한도 스로틀링이 RequestLimitExceeded로 드러나는지, 아니면 AccountLimitExceeded 이유를 가진 ThrottlingException으로 드러나는지에 대해 AWS 페이지들이 서로 다르므로, 처리 로직은 이유 문자열을 기준으로 만드세요.

스로틀링되기 전에 부하를 흡수하는 것

두 가지 내장 기능이 한도를 완화해 주며, 그 가장자리를 아는 것이 "어제는 됐는데"를 설명해 줍니다.

  • 버스트 용량은 급증에 대비해 최대 5분(300초) 분량의 사용되지 않은 읽기 및 쓰기 용량을 보유합니다 — 하지만 DynamoDB가 "사전 통지 없이" 백그라운드 유지 관리에 그것을 소비할 수도 있고, AWS는 세부 사항이 바뀔 수 있다고 명시적으로 밝힙니다. 버스트를 전제로 설계하지 말고, 운으로 취급하세요.
  • 적응형 용량 — 뜨거운 파티션 쪽으로 처리량을 자동으로, 즉시 옮기며 자주 액세스되는 항목을 자기 자신의 파티션으로 격리할 수 있습니다. 다만 "트래픽이 테이블의 총 프로비저닝 용량이나 파티션 최대 용량을 초과하지 않는 한"에서만 그렇습니다. 이것은 치우침을 재조정할 뿐, 파티션당 3,000/1,000 천장을 결코 올려주지 않으며, 테이블에 LSI가 있으면 항목 컬렉션을 나누지도 않습니다. 현재 AWS 문제 해결 페이지들은 split-for-heat — 지속적인 열기 아래에서 파티션이 분할되는 것 — 에 기대는데, 이는 시간이 걸리고 단일 뜨거운 키에는 도움이 되지 않습니다.

지표로 진단하기

CloudWatch는 요청이벤트를 구분하며, 그 구분이 진단을 해냅니다(지표 레퍼런스).

  • ThrottledRequests — 내부의 어떤 이벤트라도 스로틀링되었다면 요청을 한 번 셉니다. GSI가 세 개인 테이블에 대한 PutItem은 요청 하나이지만 쓰기 이벤트는 네 개죠. 배치에서는 모든 항목이 스로틀링된 경우에만 증가합니다.
  • ReadThrottleEvents / WriteThrottleEvents — 스로틀링된 각 이벤트를 셉니다. 항목 10개짜리 BatchGetItemGetItem 이벤트 10개입니다. GSI의 쓰기 스로틀을 보려면 TableNameGlobalSecondaryIndexName을 모두 넣어 지표를 조회해야 합니다 — 이것이 GSI 백프레셔가 테이블 수준 대시보드에서 숨는 방식입니다.
  • 더 새로운 이유별 이벤트 지표(WriteProvisionedThroughputThrottleEvents, ReadKeyRangeThroughputThrottleEvents, …AccountLimitThrottleEvents, …MaxOnDemandThroughputThrottleEvents)는 같은 네 가지 원인으로 카운트를 나눕니다 — 여러분의 리전에 이 지표들이 보인다면 "어느 한도인가" 질문에 곧바로 답해 줍니다.

함정 하나. SDK는 스로틀링된 요청을 자동으로 재시도합니다 — 표준 재시도 모드는 기본으로 총 3회 시도를 합니다(2026년 옵트인 재시도 롤아웃은 DynamoDB 클라이언트를 더 촘촘한 지연과 함께 4회 시도로 옮깁니다). 따라서 가벼운 스로틀링은 오류가 아니라 지연 시간으로 나타납니다. 예외 로그만 보지 말고 스로틀 지표를 지켜보세요.

yesnoyesnoprovisionedon-demandThrottling observedThrottleEvents on a GSI(TableName + IndexName)?GSI back-pressure:scale the indexTable utilization far belowprovisioned / expected?Hot key: fix key design,split-for-heat needs timeCapacity mode?Raise capacity /auto scaling / switch modeGrew past 2x previous peak:pre-warm or spread the ramp

GSI 백프레셔: 엉뚱한 테이블을 가리키는 스로틀

어떤 GSI든 쓰기 증폭을 흡수하지 못하면, "DynamoDB는 데이터 일관성을 유지하기 위해 베이스 테이블에 대한 쓰기를 스로틀링합니다" (GSI 스로틀링 문서) — 베이스 테이블에 여유 용량이 있을 때조차 말입니다. 예외의 ResourceArn은 인덱스를 가리키지만, 실패한 작업은 여러분의 베이스 테이블 쓰기입니다. 모든 인덱스에는 자체 용량 계획이(그리고 자체 오토 스케일링 정책이) 필요합니다. GSI가 베이스 테이블 쓰기를 스로틀링하는 이유가 그 메커니즘을 짚어 줍니다.

원인에 맞는 해결책 고르기

원인해결하는 것해결하지 못하는 것
뜨거운 키 / 파티션부하를 분산하는 키 설계(핫 파티션); split-for-heat를 위한 시간테이블 용량 올리기, 온디맨드로 전환하기
프로비저닝된 용량오토 스케일링, 더 높은 최소값, 또는 온디맨드재시도만 하기 — 부하만 더합니다
GSI 백프레셔인덱스 확장하기; 희소 인덱스 또는 프로젝션 변경베이스 테이블 확장하기
계정 할당량Service Quotas 증가 요청테이블 수준 설정
온디맨드 계단형 급증사전 예열(웜 스루풋); 램프를 30분 이상에 걸쳐 펼치기기다리기 — 두 배 피크는 천천히 재설정됩니다

DynoTable에서 하기

자초한 스로틀링 대부분은 보이는 것보다 비싼 읽기에서 시작합니다. 필터링된 Scan은 어느 쪽이든 전체 읽기를 소비하죠. DynoTable의 실행 전 비용 미리보기는 문장이 Query가 되는지 Scan이 되는지, 어떤 인덱스를 치는지, 그리고 쓰기 전 예상 읽기 비용을 보여 줍니다 — 가장 값싼 스로틀링 해결책은 실행하지 않은 비싼 읽기입니다. Scan 대 Query 가이드가 그 차이를 다루고, 무료 항목 크기 계산기는 실제 항목을 위 한도들이 측정되는 단위인 RCU/WCU 숫자로 바꿔 줍니다.

함정과 다음 단계

  • 재시도는 과부하를 증폭합니다. 백오프는 SDK에 내장되어 있지만, SDK 재시도 위에 얹힌 촘촘한 애플리케이션 수준 재시도 루프는 하필 힘겨워하는 바로 그 파티션에 대한 압력을 몇 배로 키웁니다.
  • 배치는 부분 스로틀링을 감춥니다. BatchWriteItem은 어떤 항목이라도 성공하는 한 예외를 던지는 대신 처리되지 않은 항목을 반환합니다 — 예외만 보지 말고 UnprocessedItems를 확인하세요.
  • 테이블 수준 뷰는 GSI에 대해 거짓말합니다. 스로틀 이벤트는 항상 인덱스별로 차트를 그리세요. 백프레셔가 벌어지는 동안 베이스 테이블 대시보드는 깨끗해 보입니다.
  • 용량 해결은 몇 분이 걸리고, 키 설계는 영원합니다. 오토 스케일링은 약 5분 만에 반응하고 할당량 증가는 지원 티켓이 필요하지만, 뜨거운 키는 어떤 용량 모드로 가든 여러분을 따라옵니다 — 복리가 붙는 곳에 노력을 쓰세요. 파티션 키가 작동하는 방식.

여러분의 용량에 대해 실행되기 전에 각 쿼리의 Scan 대 Query 계획과 읽기 비용을 보려면 DynoTable을 다운로드하세요.

업데이트됨