DAX 및 DynamoDB 정합성 모델 - Amazon DynamoDB

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

DAX 및 DynamoDB 정합성 모델

Amazon DynamoDB Accelerator(DAX)는 캐시를 DynamoDB 테이블에 추가하는 프로세스를 간소화하기 위해 설계된 라이트-스루(write-through) 캐싱 서비스입니다. DAX는 DynamoDB와 별개로 작동하므로 DAX와 DynamoDB 모두의 일관성 모델을 파악하여 애플리케이션이 예상대로 작동하는지 확인하는 것이 중요합니다.

많은 사용 사례를 보면, 애플리케이션이 DAX를 사용하는 방법에 따라 DAX 클러스터 내의 데이터 일관성뿐만 아니라 DAX와 DynamoDB 간 데이터 일관성도 영향을 받는 것으로 나타났습니다.

DAX 클러스터 노드 간 정합성

애플리케이션의 고가용성을 얻으려면 최소 3개 이상의 노드가 있는 DAX 클러스터를 프로비저닝한 다음, 이러한 노드들을 한 리전 내에 여러 개의 가용 영역에 배포하는 것이 좋습니다.

DAX 클러스터가 실행 중인 경우 데이터를 클러스터의 모든 노드에 복제합니다(2개 이상의 노드를 프로비저닝한 경우). DAX를 사용하여 성공적인 UpdateItem 작업을 수행하는 애플리케이션을 생각해봅니다. 이 작업으로 인해 기본 노드의 항목 캐시가 새 값으로 수정되는 경우가 발생할 수 있습니다. 이 값은 클러스터의 다른 모든 노드에 복제됩니다. 이 복제 작업은 최종적으로 일관성이 있는 작업이고, 완료되는 데 보통 1초 미만이 걸립니다.

이 시나리오에서는 두 개의 클라이언트가 동일한 DAX 클러스터에서 동일한 키를 읽지만, 각 클라이언트가 액세스한 노드에 따라 서로 다른 값을 수신할 수 있습니다. 이러한 노드는 클러스터의 모든 노드에 업데이트가 완전히 복제되면 전체 일관성이 달성됩니다. (이러한 동작은 DynamoDB의 특징인 최종적 일관성과 유사합니다.)

DAX를 사용하는 애플리케이션을 구축하고 있는 경우, 데이터가 최종적 일관성을 유지해도 괜찮은 방식으로 애플리케이션이 설계되어야 합니다.

DAX 항목 캐시 동작

모든 DAX 클러스터에는 두 개의 개별 캐시인 항목 캐시와 쿼리 캐시가 있습니다. 자세한 정보는 DAX: 작동 방식을 참조하십시오.

이 단원에서는 DAX 항목 캐시를 읽고 쓸 때 발생하는 일관성 영향에 대해 설명합니다.

읽기 정합성

DynamoDB를 사용하면 기본적으로 GetItem 작업이 최종적으로 일관된 읽기를 수행합니다. DynamoDB 클라이언트에서 UpdateItem을 사용한다고 가정합니다. 그 직후 동일한 항목을 읽으려고 하면 업데이트하기 전에 표시된 데이터가 그대로 표시될 수 있습니다. 이는 전체 DynamoDB 스토리지 위치에 걸쳐 전파 지연이 발생하기 때문입니다. 일관성은 일반적으로 몇 초 안에 이루어집니다. 따라서 읽기를 다시 시도하면 업데이트된 항목이 나타날 것입니다.

DAX 클라이언트에서 GetItem을 사용하는 경우에는 작업(이 경우 최종적으로 일관된 읽기)이 다음과 같이 수행됩니다.


                    항목을 업데이트하기 위한 번호가 지정된 단계를 보여주는 워크플로 다이어그램.
  1. DAX 클라이언트가 GetItem 요청을 실행합니다. DAX는 항목 캐시에서 요청된 항목을 읽으려고 시도합니다. 항목이 캐시에 있으면(캐시 적중), DAX가 이를 애플리케이션에 반환합니다.

  2. 항목이 없으면(캐시 누락) DAX가 DynamoDB에 대해 최종적 일관된 GetItem 작업을 수행합니다.

  3. DynamoDB는 요청된 항목을 반환하고, DAX는 이를 항목 캐시에 저장합니다.

  4. DAX가 항목을 애플리케이션에 반환합니다.

  5. (표시되지 않음) DAX 클러스터에 2개 이상의 노드가 있으면 항목이 클러스터의 다른 모든 노드에 복제됩니다.

캐시의 유지 시간(TTL) 설정 및 가장 오랫동안 사용되지 않음(LRU) 알고리즘에 따라 항목이 DAX 항목 캐시에 유지됩니다. 자세한 정보는 DAX: 작동 방식을 참조하십시오.

단, 이 기간 동안에는 DAX가 DynamoDB에서 항목을 다시 읽지 않습니다. 다른 사용자가 DAX를 완전히 우회하는 방식으로 DynamoDB 클라이언트를 사용하여 항목을 업데이트하는 경우, DAX 클라이언트를 사용하는 GetItem 요청은 DynamoDB 클라이언트를 사용하는 동일한 GetItem 요청의 결과와 다릅니다. 이러한 경우 DAX 항목에 대한 TTL이 만료될 때까지 DAX 및 DynamoDB가 동일한 키에 대해 일관되지 않은 값을 갖고 있게 됩니다.

애플리케이션이 DAX를 우회하여 기본 DynamoDB 테이블에 있는 데이터를 수정하는 경우 애플리케이션은 이로 인해 발생할 수 있는 데이터 비일관성을 예상하고 허용할 수 있어야 합니다.

참고

GetItem 외에도 DAX 클라이언트는 BatchGetItem 요청도 지원합니다. BatchGetItem은 기본적으로 하나 이상의 GetItem 요청을 포함하는 래퍼이므로 DAX는 이러한 요청을 각각 개별 GetItem 작업으로 처리합니다.

쓰기 정합성

DAX는 동시 기록 캐시로, DAX 항목 캐시가 기본 DynamoDB 테이블과 일관성을 유지하도록 하는 프로세스를 간소화합니다.

DAX 클라이언트는 DynamoDB와 동일한 쓰기 API 작업을 지원합니다(PutItem, UpdateItem, DeleteItem, BatchWriteItemTransactWriteItems). DAX 클라이언트를 사용하여 이러한 작업을 수행하면 DAX 및 DynamoDB 모두에서 항목이 수정됩니다. DAX는 이러한 항목의 TTL 값에 상관없이 항목 캐시에 있는 항목을 업데이트합니다.

예를 들어, DAX 클라이언트에서 GetItem 요청을 실행하여 ProductCatalog 테이블의 항목을 읽는다고 가정합니다. (파티션 키는 Id이고 정렬 키는 없습니다.) Id101인 항목을 검색합니다. 해당 항목의 QuantityOnHand 값은 42입니다. DAX는 특정 TTL을 가진 항목 캐시에 해당 항목을 저장합니다. 이 예제에서는 TTL이 10분이라고 가정합니다. 3분 후, 다른 애플리케이션이 DAX 클라이언트를 사용하여 동일한 항목을 업데이트합니다. 그러면 QuantityOnHand 값이 이제 41이 됩니다. 항목이 다시 업데이트되지 않는다고 가정하면, 다음 10분 동안 동일한 항목의 후속 읽기가 수행되면 QuantityOnHand에 대해 캐시된 값(41)이 반환됩니다.

DAX에서 쓰기를 처리하는 방식

DAX는 고성능 읽기가 필요한 애플리케이션을 위해 만들어졌습니다. 동시 기록 캐시인 DAX는 동시 기록을 DynamoDB에 동기식으로 전달한 다음 결과 업데이트를 클러스터에 있는 모든 노드의 항목 캐시에 비동기식으로 자동 복제합니다. DAX에서 자동으로 처리해주므로 사용자가 캐시 무효화 로직을 관리할 필요가 없습니다.

DAX는 PutItem, UpdateItem, DeleteItem, BatchWriteItem, TransactWriteItems 등의 쓰기 작업을 지원합니다.

PutItem, UpdateItem, DeleteItem 또는 BatchWriteItem 요청을 DAX에 전송하면 다음 작업이 수행됩니다.

  • DAX가 요청을 DynamoDB에 보냅니다.

  • DynamoDB가 쓰기 성공을 확인하는 응답을 DAX에 보냅니다.

  • DAX가 항목 캐시에 항목을 씁니다.

  • DAX가 요청자에게 성공을 반환합니다.

TransactWriteItems 요청을 DAX에 전송하면 다음 작업이 수행됩니다.

  • DAX가 요청을 DynamoDB에 보냅니다.

  • DynamoDB가 트랜잭션 완료를 확인하는 응답을 DAX에 보냅니다.

  • DAX가 요청자에게 성공을 반환합니다.

  • 백그라운드에서 DAX는 TransactWriteItems 요청의 각 항목에 대해 TransactGetItems 요청을 수행하여 항목 캐시에 항목을 저장합니다. TransactGetItems직렬화 가능 격리를 유지하기 위해 사용됩니다.

제한을 비롯한 어떤 이유로든 DynamoDB에 쓰기가 실패하면 항목이 DAX에 캐시되지 않습니다. 이러한 실패에 대한 예외는 요청자에게 반환됩니다. 따라서 데이터가 먼저 DynamoDB에 성공적으로 쓰여질 때까지 DAX 캐시에 데이터가 쓰여지지 않습니다.

참고

DAX에 쓸 때마다 항목 캐시의 상태가 바뀝니다. 그러나 해당 항목 캐시에 대한 쓰기는 쿼리 캐시에 영향을 미치지 않습니다. (DAX 항목 캐시 및 쿼리 캐시는 용도가 서로 다르며, 서로 독립적으로 작동합니다.)

DAX 쿼리 캐시 동작

DAX는 QueryScan 요청의 결과를 쿼리 캐시에 캐시합니다. 그러나 이러한 결과는 항목 캐시에 전혀 영향을 미치지 않습니다. 애플리케이션이 DAX에서 Query 또는 Scan 요청을 실행하면 결과 집합이 항목 캐시가 아닌 쿼리 캐시에 저장됩니다. 항목 캐시와 쿼리 캐시는 별도의 엔터티이므로 Scan 작업을 수행하여 항목 캐시를 "워밍업"할 수 없습니다.

쿼리-업데이트-쿼리 정합성

항목 캐시나 기본 DynamoDB 테이블 업데이트 작업은 쿼리 캐시에 저장된 결과를 무효화하거나 수정하지 않습니다.

다음 시나리오를 예로 들어보겠습니다. 애플리케이션이 파티션 키가 DocId이고 정렬 키가 RevisionNumberDocumentRevisions 테이블에서 작동 중입니다.

  1. 클라이언트는 RevisionNumber5보다 크거나 같은 모든 항목의 DocId 101에 대해 Query를 실행합니다. DAX는 결과 집합을 쿼리 캐시에 저장하고 결과 집합을 사용자에게 반환합니다.

  2. 클라이언트는 20의 값이 RevisionNumberDocId 101에 대해 PutItem 요청을 발행합니다.

  3. 클라이언트가 1단계에서 설명한 것과 동일한 Query(DocId 101RevisionNumber5 이상인)를 발행합니다.

이 시나리오에서는 3단계에서 발행된 Query의 캐시된 결과 집합이 1단계에서 캐시된 결과 집합과 동일합니다. 이는 DAX가 개별 항목에 대한 업데이트를 기반으로 Query 또는 Scan 결과 집합을 무효화하지 않기 때문입니다. 2단계의 PutItem 작업은 Query의 TTL이 만료될 때만 DAX 쿼리 캐시에 반영됩니다.

사용자는 쿼리 캐시의 TTL 값과 더불어, 애플리케이션이 쿼리 캐시와 항목 캐시 간 비일관적인 결과를 허용할 수 있는 기간을 고려해야 합니다.

강력히 정합하는 트랜잭션 읽기

강력히 일관된 GetItem, BatchGetItem, Query 또는 Scan 요청을 수행하려면 ConsistentRead 파라미터를 true로 설정합니다. DAX는 강력히 일관된 읽기 요청을 DynamoDB에 전달합니다. DynamoDB에서 응답을 받으면 DAX는 결과를 클라이언트에 반환하지만 결과를 캐시하지 않습니다. DAX는 DynamoDB와 긴밀하게 결합되어 있지 않으므로 강력히 일관된 읽기를 자체적으로 수행할 수 없습니다. 이러한 이유로 DAX에서의 후속 읽기는 최종적으로 일관된 읽기가 되어야 합니다. 또한 이후의 모든 최종적으로 일관된 읽기는 DynamoDB으로 전달되어야 합니다.

DAX는 강력히 일관된 읽기를 처리하는 것과 동일한 방법으로 TransactGetItems 요청을 처리합니다. DAX는 모든 TransactGetItems 요청을 DynamoDB에 전달합니다. DynamoDB에서 응답을 받으면 DAX는 결과를 클라이언트에 반환하지만 결과를 캐시하지 않습니다.

음성 캐싱

DAX는 항목 캐시 및 쿼리 캐시 모두에서 음성 캐시 엔트리를 지원합니다. 음성 캐시 엔트리는 DAX가 기본 DynamoDB 테이블에서 요청한 항목을 찾을 수 없을 때 발생합니다. DAX는 오류를 생성하는 대신 빈 결과를 캐시하고 해당 결과를 사용자에게 반환합니다.

예를 들어, 애플리케이션이 GetItem 요청을 DAX 클러스터에 보내지만 DAX 항목 캐시에 일치하는 항목이 없다고 가정합니다. 이렇게 되면 DAX가 기본 DynamoDB 테이블에서 해당 항목을 읽게 됩니다. 항목이 DynamoDB에 없으면, DAX가 항목 캐시에 빈 항목을 저장한 다음, 빈 항목을 애플리케이션에 반환합니다. 이제 애플리케이션에서 동일한 항목에 대해 다른 GetItem 요청을 보낸다고 가정합니다. DAX는 항목 캐시에서 빈 항목을 찾고 이를 애플리케이션에 즉시 반환합니다. DynamoDB는 전혀 고려하지 않습니다.

음성 캐시 항목은 항목 TTL이 만료되거나, LRU가 호출되거나, 항목이 PutItem, UpdateItem 또는 DeleteItem을 통해 수정될 때까지 DAX 항목 캐시에 유지됩니다.

DAX 쿼리 캐시도 유사한 방식으로 음성 캐시 결과를 처리합니다. 애플리케이션이 Query 또는 Scan을 수행하고 DAX 쿼리 캐시에 캐시된 결과가 없는 경우 DAX가 요청을 DynamoDB로 보냅니다. 결과 집합에 일치하는 항목이 없으면, DAX가 쿼리 캐시에 빈 결과 집합을 저장한 다음, 빈 결과 집합을 애플리케이션에 반환합니다. 해당 결과 집합의 TTL이 만료될 때까지 후속 Query 또는 Scan 요청은 동일한(빈) 결과 집합을 산출합니다.

쓰기 전략

DAX의 동시 기록 동작은 많은 애플리케이션 패턴에 적합합니다. 그러나, 라이트-스루 모델이 적합하지 않은 일부 애플리케이션 패턴도 있습니다.

대기 시간에 민감한 애플리케이션의 경우, DAX를 통해 쓰기를 수행하면 추가 네트워크 홉이 발생합니다. 따라서 DAX에 쓰기를 하는 것이 DynamoDB에 직접 쓰기를 하는 것보다 속도가 약간 느립니다. 애플리케이션이 쓰기 지연 시간에 민감한 경우 대신 DynamoDB에 직접 쓰기를 수행함으로써 지연 시간을 줄일 수 있습니다. 자세한 정보는 라이트-어라운드(Write-Around)을 참조하십시오.

쓰기 집약적인 애플리케이션(대량 데이터 로딩 작업을 수행하는 애플리케이션 등)의 경우 애플리케이션에서 매우 낮은 비율의 데이터만 읽을 수 있으므로 DAX를 통해 모든 데이터를 쓰는 것이 바람직하지 않을 수 있습니다. DAX를 통해 대량의 데이터를 쓰면 LRU 알고리즘이 호출되어 새로운 항목을 읽을 수 있도록 캐시에 공간이 마련됩니다. 이는 읽기 캐시로서의 DAX의 효율성을 떨어뜨립니다.

항목을 DAX에 쓰면, 새로운 항목을 수용하기 위해 항목 캐시 상태가 변경됩니다. (예를 들어, DAX는 항목 캐시에 있는 오래된 데이터를 제거하여 새로운 항목을 위한 공간을 마련해야 할 수 있습니다.) 캐시의 LRU 알고리즘 및 TTL 설정에 따라 새로운 항목이 항목 캐시에 유지됩니다. 항목이 항목 캐시에 유지되는 동안 DAX는 DynamoDB에서 항목을 다시 읽지 않습니다.

라이트-스루

DAX 항목 캐시는 라이트-스루 정책을 구현합니다. 자세한 정보는 DAX에서 쓰기를 처리하는 방식을 참조하십시오.

항목을 쓰면, DAX가 캐시된 항목이 해당 항목(DynamoDB에 있는 경우)과 동기화되도록 합니다. 이러한 기능은 항목을 쓴 직후 다시 읽어야 하는 애플리케이션에 유용합니다. 그러나 다른 애플리케이션이 DynamoDB 테이블에 직접 쓰는 경우 DAX 항목 캐시의 항목이 더 이상 DynamoDB와 동기화 상태가 아니게 됩니다.

예를 들어, ProductCatalog 테이블을 사용하고 있는 두 명의 사용자(Alice와 Bob)를 가정해 보겠습니다. Alice는 DAX를 사용하여 테이블에 액세스하지만 Bob은 DAX를 우회하고 DynamoDB의 테이블에 직접 액세스합니다.


                    사용자인 Alice와 Bob이 DAX 및 DynamoDB를 사용해 테이블에 액세스할 수 있는 방법에 대한 번호가 지정된 단계를 보여주는 워크플로 다이어그램.
  1. Alice는 ProductCatalog 테이블의 항목을 업데이트합니다 DAX는 요청을 DynamoDB에 전달하고 업데이트가 성공합니다. 그런 다음 DAX는 항목 캐시에 항목을 쓰고 성공한 응답을 Alice에 반환합니다. 이 시점에서 항목이 캐시에서 궁극적으로 제거될 때까지, DAX로부터 항목을 읽는 모든 사용자에게는 Alice가 업데이트한 항목이 표시됩니다.

  2. 잠시 후 Bob이 Alice가 쓰기 작업을 한 것과 동일한 ProductCatalog 항목을 업데이트합니다. 그러나 Bob은 DynamoDB에서 직접 항목을 업데이트합니다. DAX는 DynamoDB를 통한 업데이트에 대한 응답으로 항목 캐시를 자동으로 새로 고치지 않습니다. 따라서 DAX 사용자는 Bob의 업데이트를 알 수 없습니다.

  3. Alice가 DAX에서 항목을 다시 읽습니다. 항목이 항목 캐시에 있으므로 DAX가 DynamoDB 테이블에 액세스하지 않고 Alice에게 항목을 반환합니다.

이 시나리오에서는 Alice와 Bob에게 동일한 ProductCatalog 항목의 다른 값이 표시됩니다. 이러한 현상은 DAX가 항목 캐시로부터 항목을 제거할 때까지, 또는 다른 사용자가 DAX를 사용하여 동일한 항목을 다시 업데이트할 때까지 계속됩니다.

라이트-어라운드(Write-Around)

애플리케이션에서 대량의 데이터를 써야 하는 경우(대량 데이터 로드 등), DAX를 우회하고 데이터를 DynamoDB에 직접 쓰는 것이 좋을 수 있습니다. 이러한 라이트-어라운드 전략은 쓰기 지연 시간을 줄여줍니다. 그러나 항목 캐시는 DynamoDB에서 데이터와 동기화된 상태가 유지되지 않습니다.

라이트-어라운드 전략을 사용하기로 결정했다면 애플리케이션이 DAX 클라이언트를 사용하여 데이터를 읽을 때마다 DAX가 항목 캐시를 채운다는 점을 명심하세요. 이러한 점은 가장 자주 읽는 데이터가 캐시된다는 점에서(가장 자주 쓰는 데이터와 달리) 어떤 경우에는 장점이 될 수 있습니다.

예를 들어, DAX를 사용하는 다른 테이블인 GameScores 테이블로 작업하려는 사용자(Charlie)를 고려해봅니다. GameScores의 파티션 키는 UserId이므로 Charlie의 모든 점수의 UserId는 동일합니다.


                    Charlie가 DAX를 사용하여 DynamoDB 테이블을 처리하는 방법에 대한 번호가 지정된 단계를 보여주는 워크플로 다이어그램.
  1. Charlie는 자신의 모든 점수를 검색하기 위해 DAX에 Query를 보냅니다. DAX은 이 쿼리가 이전에 실행된 적이 없다고 가정하고 처리를 위해 DynamoDB로 해당 쿼리를 전송합니다. 그리고 DAX 쿼리 캐시에 결과를 저장한 다음, Charlie에게 결과를 반환합니다. 결과 집합은 제거되기 전까지 쿼리 캐시에서 사용 가능한 상태로 유지됩니다.

  2. 이제 Charlie가 Meteor Blasters 게임을 하여 높은 점수를 획득한다고 가정해 봅니다. Charlie가 GameScores 테이블의 항목을 수정하는 UpdateItem 요청을 DynamoDB에 보냅니다.

  3. 마지막으로, Charlie는 이전에 수행한 Query를 다시 실행하여 GameScores로부터 자신의 모든 데이터를 검색하기로 합니다. Charlie는 결과에서 자신이 Meteor Blasters에서 얻은 높은 점수를 볼 수 없습니다. 쿼리 캐시에서 오는 쿼리 결과가 항목 캐시가 아니기 때문입니다. 두 캐시는 서로 독립적이므로 한 캐시가 변경되어도 다른 캐시에 영향을 주지 않습니다.

DAX는 DynamoDB의 가장 최신 데이터로 쿼리 캐시의 결과 집합을 새로 고치지 않습니다. 쿼리 캐시의 각 결과 집합은 Query 또는 Scan 작업이 수행되었던 당시를 기준으로 최신 상태입니다. 따라서 Charlie의 Query 결과에는 PutItem 작업이 반영되지 않습니다. 이러한 현상은 DAX가 쿼리 캐시에서 결과 집합을 제거할 때까지 계속됩니다.