중급4분 분량

DynamoDB 배치 작업: BatchGetItem & BatchWriteItem

여러 아이템을 한꺼번에 읽거나 써야 할 때, 아이템마다 GetItem이나 PutItem을 하나씩 쏘는 것은 아이템당 네트워크 왕복 한 번을 뜻합니다 — 느리고 수다스럽습니다. DynamoDB의 배치 API는 여러 아이템 작업을 단일 요청으로 접습니다. 읽기는 BatchGetItem, 쓰기는 BatchWriteItem.

이들은 처리량과 지연 시간의 승리이지 일관성 보장이 아닙니다 — 그리고 바로 그 구분에서 사람들이 데입니다. 배치는 트랜잭션이 아닙니다.

DynamoDB 배치 작업이란 무엇인가요?

DynamoDB 배치 작업은 여러 아이템의 읽기나 쓰기를 단일 요청으로 접습니다. BatchGetItem은 최대 100개 아이템을 가져오고, BatchWriteItem은 최대 25개를 put하거나 delete하며, 각각 16 MB로 제한됩니다. 이들은 왕복을 줄이지 용량을 줄이지는 않습니다. 결정적으로, 배치는 트랜잭션이 아닙니다 — 아이템은 각각 독립적으로 성공하거나 실패하며, 롤백이 없습니다.

  • BatchGetItem — 하나 이상의 테이블에 걸쳐 최대 100개 아이템(또는 16 MB)을 한 호출로 가져옵니다.
  • BatchWriteItem — 한 호출로 최대 25개의 put/delete 작업(또는 16 MB). 갱신은 없습니다 — put과 delete만 됩니다.
  • 원자적이지 않습니다. 개별 아이템은 일부가 성공하고 일부가 실패할 수 있습니다. 롤백이 없습니다.
  • 부분 실패는 정상입니다. 스로틀링된 아이템은 UnprocessedItems / UnprocessedKeys로 돌아옵니다 — 백오프와 함께 직접 재시도해야 합니다.
  • 개별 호출과 같은 용량 비용 — 배치는 왕복을 줄이지 용량 단위를 줄이지 않습니다.

문제: 많은 아이템, 한 번의 왕복

지원 데스크를 운영한다고 합시다. 대시보드는 큐를 렌더링하려고 ID로 티켓 50개를 불러와야 하고, 야간 작업은 해결된 티켓 1,000개를 보관 처리합니다. 그것을 아이템 하나씩 하면 50번(또는 1,000번)의 순차 왕복입니다 — 지연이 쌓이고 작업이 기어갑니다.

배치는 그것을 몇 번의 호출로 접습니다. 티켓 50개 읽기는 단일 BatchGetItem이 되고, 보관 작업은 각 25개 삭제로 된 BatchWriteItem 호출의 흐름이 됩니다. 왕복은 훨씬 적게, 옮기는 데이터는 그대로.

배치 API의 작동 방식

**BatchGetItem**은 (하나 이상의 테이블에 걸친) 기본 키 집합을 받아 일치하는 아이템을 돌려줍니다. 테이블별로 강력한 일관성 읽기를 요청할 수 있습니다. 읽지 못한 것은 — 보통 요청이 처리량 한도를 스쳤기 때문에 — 전체 호출을 실패시키는 대신 **UnprocessedKeys**로 돌아옵니다.

**BatchWriteItem**은 PutRequest / DeleteRequest 작업의 리스트를 받습니다. 빠진 것에 주목하세요. 갱신이 없습니다. 배치 쓰기는 아이템 전체를 교체(put)하거나 제거(delete)합니다 — 특정 속성을 수정하려면 여전히 UpdateItem이 필요합니다. 쓰지 못한 아이템은 **UnprocessedItems**로 돌아옵니다.

succeededthrottledretry with backoffBatchWriteItem: 25 puts/deletesPer-item processingWrittenUnprocessedItems

핵심 멘탈 모델: 배치는 각각 스스로 성공하거나 실패하는 독립적 작업의 묶음이지, 전부 아니면 전무인 하나의 단위가 아닙니다.

배치는 트랜잭션이 아닙니다

이것이 함정입니다. 보관 작업의 배치가 중간에 처리량 한도에 부딪히면, 일부 티켓은 삭제되고 일부는 안 됩니다 — 그리고 DynamoDB는 통과된 것들을 되돌리지 않습니다. 롤백도, 격리도, "25개 전부 아니면 전무"도 없습니다.

전부 아니면 전무 시맨틱이 필요하다면 — "티켓을 보관됨으로 옮기고 그리고 미해결 티켓 카운터를 감소시키거나, 아니면 둘 다 하지 않거나" — 그건 배치가 아니라 TransactWriteItems입니다. 트랜잭션은 비용이 더 들고(각 작업이 두 배 청구됨) 100개 아이템에서 막히지만, 배치가 일부러 제공하지 않는 원자성을 줍니다.

처리되지 않은 아이템 다루기

올바른 배치 호출자는 항상 처리되지 않은 집합을 확인하고 재시도합니다. DynamoDB는 요청 전체는 수락되었지만 일부 아이템을 처리할 수 없을 때마다 — 보통 일시적 스로틀링 — UnprocessedItems/UnprocessedKeys를 돌려줍니다.

처리되지 않은 아이템만 지수 백오프와 지터 와 함께 다시 제출하세요. 배치를 쏘고 잊는 것으로 취급하면 쓰기가 소리 없이 누락됩니다 — 몇 달 뒤 누락된 데이터로 드러나는 종류의 버그입니다.

DynoTable에서의 배치 쓰기

대량 작업의 비용을 먼저 DynamoDB 요금 계산기로 추정하세요 — 배치는 묶는 개별 쓰기와 같은 용량을 소비하지만, 요청 수는 더 적습니다.

DynoTable에서는 편집을 로컬에 스테이징하고 효율적인 배치 쓰기로 커밋하기 전에 검토할 수 있습니다 — 여러 행에 걸친 대량 변경이 변경당 API 호출 하나씩이 아니라 묶인 요청으로 나가며, 처리되지 않은 아이템의 재시도가 대신 처리됩니다.

DynoTable에서 스테이징된 편집을 배치로 커밋하기 전에 검토하는 모습.
DynoTable에서 스테이징된 편집을 배치로 커밋하기 전에 검토하는 모습.

함정과 다음 단계

  • UnprocessedItems/UnprocessedKeys를 항상 백오프와 함께 재시도하세요 — 예외적인 게 아니라 예상되는 것입니다.
  • 부분 실패 롤백이 없습니다. 원자성이 필요하세요? 트랜잭션을 쓰세요.
  • 배치 쓰기에 갱신은 없습니다BatchWriteItem은 put/delete 전용입니다. 속성을 바꾸려면 UpdateItem을 꺼내세요.
  • 호출당 상한을 유념하세요 — 쓰기 25 / 읽기 100 / 16 MB. 더 큰 작업은 페이지로 나누세요. 페이지네이션을 보세요.

재시도 루프를 스크립팅하지 않고 대량 읽기·쓰기를 실행하고 싶으세요? DynoTable을 다운로드해서 테이블을 직접 편집하세요.

업데이트됨