BLOG

트랜잭션을 사용한 Amazon DynamoDB 고유 제약 조건 시뮬레이션
작성일: 2019-10-14

대부분의 관계형 데이터베이스 시스템 및 일부 비 관계형 데이터베이스 시스템에는 고유 키 또는 고유 제한 조건으로 알려진 구성이 있습니다. 이는 열 또는 필드의 모든 값이 행에서 고유해야 함을 뜻합니다.

예를 들어 User 테이블이 있는 경우 각 사용자를 고유하게 식별하는 기본 키로 UUID가있을 수 있지만 사용자 이름 및 이메일 필드(DynamoDB 용어의 “속성”)도 있을 수 있습니다. 이 사용 사례는 AWS Summit 2018 당시 DynamoDB Transaction DAT374 세션에서 언급된 적 있습니다.

아마존 DynamoDB에서는 기본 키가 파티션 키(테이블을 위한 키가 정렬되지 않은 경우) , 파티션의 조합 또는 정렬 키 중에 있습니다. 기본 키는 테이블 내에서 고유해야 합니다. 그러나 DynamoDB에는 기본 키가 아닌 속성의 고유성을 보장하기 위한 기본 제공 메커니즘이 없습니다.

오늘 메가존 테크블로그에선 애플리케이션 측에서 이러한 종류의 고유성을 구현하는 데 사용되는 패턴에 대해 설명해 드릴 예정입니다. 또한 단일 테이블 스키마 디자인에서 해당 패턴을 사용할 때 항목을 작성, 업데이트 및 삭제하는 방법에 대한 예제를 보여드리겠습니다.

 

 

솔루션 개요

 

앞의 예제를 사용하여 테이블에 다음과 같은 속성이 있다고 가정해보겠습니다.

  • pk (UUID로 저장된 기본 키)
  • 사용자 이름
  • 이메일
  • fullName
  • 전화 번호

UUID , userName 및 이메일 속성은 고유해야하지만 fullName PHONENUMBER은 고유하지 않습니다. 여러 사람이 동일한 집 전화 번호를 공유 할 수 있기 때문입니다. 이에 대한 샘플은 다음과 같습니다.

Pk 사용자 이름 이메일 fullName 전화 번호
b201c1f2-238e-461f-88e6-0e606fbc3c51 테이블 bobby.tables@gmail.com 바비 테이블 + 1-202-555-0124
8ec436a8-97e6-4e72-aec2-b47668e96a94 jsmith johnsmith@yahoo.com 존 스미스 + 1-404-555-9325
eed78b78-29f9-4893-a432-4c4f50b0d1c4 phonork pphonork 피터 포노르 쿠스 + 1-805-555-0820

 

DynamoDB는 이미 pk 속성이 고유하다는 것을 보장하므로 userName 및 email 속성도 고유 하도록 메커니즘이 필요합니다.

이렇게 하려면 pk 속성을 항목의 속성 이름 및 값으로 설정하고 해시 부호로 구분 하여 동일한 테이블에 추가 항목을 삽입해야 합니다.  새 테이블에 대한 예는 다음과 같습니다.

Pk 사용자 이름 이메일 fullName 전화 번호
b201c1f2-238e-461f-88e6-0e606fbc3c51 테이블 bobby.tables@gmail.com 바비 테이블 + 1-202-555-0124
userName # btables
email#bobby.tables@gmail.com
8ec436a8-97e6-4e72-aec2-b47668e96a94 jsmith johnsmith@yahoo.com 존 스미스 + 1-404-555-9325
userName # jsmith
email#johnsmith@yahoo.com
eed78b78-29f9-4893-a432-4c4f50b0d1c4 phonork pphonork@calpoly.edu 피터 포노르 쿠스 + 1-805-555-0820
userName # phonork
email#pphonork@calpoly.edu

 

 

새 항목을 테이블에 삽입할 때마다 다른 두 항목도 삽입해야 합니다. 이는 userName 및 email 속성의 고유성을 보장 합니다. 마찬가지로 항목을 삭제하는 경우 다른 두 개의 해당 항목을 삭제해야 합니다.

마지막으로 고유 속성 중 하나를 수정하는 경우(예 : 사용자가 자신의 계정에서 이메일 주소를 변경하려는 경우) 관련 고유 항목도 업데이트해야 합니다. 이러한 모든 수정 사항은 DynamoDB 트랜잭션에서 함께 바인딩되어 모두 성공하거나 함께 실패해야 합니다.

 

 

명령 줄 예제

다음으로 이 디자인을 구현하기 위한 몇 가지 명령 줄 예제를 살펴보겠습니다. 이러한 CLI 예제는 원하는 프로그래밍 언어에 맞게 DynamoDB SDK로 쉽게 이식 할 수 있습니다.

비어있는 사용자 테이블이 있다고 가정해보겠습니다. 트랜잭션의 일부로 세 개의 행을 삽입하여 첫 번째 사용자를 등록하고 트랜잭션 식별자를 사용하여 dem 등성을 보장합니다. 이 트랜잭션 식별자 (클라이언트 요청 토큰)를 사용하면 응용 프로그램이 다시 시작되거나 재개된 경우에도 동일한 트랜잭션을 두 번 이상 제출할 수 있으며 결과는 여전히 같습니다.

 

aws dynamodb transact-write-items –client-request-token TRANSACTION1 –transact-items ‘[  {    “Put”: {      “TableName” : “User”,       “ConditionExpression”: “attribute_not_exists(pk)”,        “Item” : {          “pk”:{“S”:”b201c1f2-238e-461f-88e6-0e606fbc3c51″},          “userName”:{“S”:”btables”},          “email”:{“S”:”bobby.tables@gmail.com”},          “fullName”:{“S”:”Bobby Tables”},          “phoneNumber”:{“S”:”+1-202-555-0124″}       }    }},  {    “Put”: {      “TableName” : “User”,       “ConditionExpression”: “attribute_not_exists(pk)”,      “Item” : {        “pk”:{“S”:”userName#btables”}       }    }},  {    “Put”: {      “TableName” : “User”,       “ConditionExpression”: “attribute_not_exists(pk)”,      “Item” : {        “pk”:{“S”:”email#bobby.tables@gmail.com”}       }    }}

]’

 

이제 항목을 나열하면 세 항목이 모두 생성 된 것을 볼 수 있습니다.

 

aws dynamodb scan –table-name User{    “Count”: 3,    “Items”: [        {            “userName”: {                “S”: “btables”            },            “pk”: {                “S”: “b201c1f2-238e-461f-88e6-0e606fbc3c51”            },            “fullName”: {                “S”: “Bobby Tables”            },            “phoneNumber”: {                “S”: “+1-202-555-0124”            },            “email”: {                “S”: “bobby.tables@gmail.com”            }        },        {            “pk”: {                “S”: “email#bobby.tables@gmail.com”            }        },        {            “pk”: {                “S”: “userName#btables”            }        }    ],    “ScannedCount”: 3,    “ConsumedCapacity”: null

}

 

다음은 가짜 Bobby Tables가 동일한 이메일 주소를 사용하여 가입하려고 할 때 발생하는 상황입니다.

 

aws dynamodb transact-write-items –client-request-token TRANSACTION2 –transact-items ‘[   {     “Put”: {       “TableName” : “User”,       “ConditionExpression”: “attribute_not_exists(pk)”,         “Item” : {           “pk”:{“S”:”8ec436a8-97e6-4e72-aec2-b47668e96a94″},           “userName”:{“S”:”caulfield”},           “email”:{“S”:”bobby.tables@gmail.com”},           “fullName”:{“S”:”Phony Bobby Tables”},           “phoneNumber”:{“S”:”+1-202-555-0124″}        }     } },   {     “Put”: {       “TableName” : “User”,       “ConditionExpression”: “attribute_not_exists(pk)”,       “Item” : {         “pk”:{“S”:”userName#caulfield”}        }     } },   {     “Put”: {       “TableName” : “User”,       “ConditionExpression”: “attribute_not_exists(pk)”,       “Item” : {         “pk”:{“S”:”email#bobby.tables@gmail.com”}        }     }  }

]’

An error occurred (TransactionCanceledException) when calling the TransactWriteItems operation: Transaction cancelled, please refer cancellation reasons for specific reasons [None, None, ConditionalCheckFailed]

 

보다시피 ConditionalCheckFailed, pk 값이“email#bobby.tables@gmail.com” 인 아이템이 이미 존재 하기 때문에 트랜잭션의 세 번째 요소가 오류를 수신했기 때문에이 트랜잭션이 실패합니다.

작은 Bobby 테이블이 가상 도메인을 등록하고 저장된 이메일 주소를 변경하려는 경우 두 항목 만 수정해야 합니다. 그러나 DynamoDB에서는 항목의 기본 키를 수정할 수 없으므로 고유한 이메일 항목을 삭제하고 새 이메일에 다른 항목을 삽입해야 합니다.

 

aws dynamodb transact-write-items –client-request-token TRANSACTION3 –transact-items ‘[  {    “Update”: {      “TableName” : “User”,      “Key” : {“pk”:{“S”:”b201c1f2-238e-461f-88e6-0e606fbc3c51″}},      “UpdateExpression”:”SET email = :email”,      “ExpressionAttributeValues”:{“:email”:{“S”:”bobby@tables.com”}}    }  },    {    “Delete”: {      “TableName” : “User”,      “Key” : {“pk”:{“S”:”email#bobby.tables@gmail.com”}}    }  },  {    “Put”: {      “TableName” : “User”,      “ConditionExpression”: “attribute_not_exists(pk)”,      “Item” : {        “pk”:{“S”:”email#bobby@tables.com”}       }    }}

]’

 

스캔한 결과 의도한 변경이 이루어 졌음을 보여줍니다.

 

aws dynamodb scan –table-name User{    “Count”: 3,    “Items”: [        {            “userName”: {                “S”: “btables”            },            “pk”: {                “S”: “b201c1f2-238e-461f-88e6-0e606fbc3c51”            },            “fullName”: {                “S”: “Bobby Tables”            },            “phoneNumber”: {                “S”: “+1-202-555-0124”            },            “email”: {                “S”: “bobby@tables.com”            }        },        {            “pk”: {                “S”: “userName#btables”            }        },        {            “pk”: {                “S”: “email#bobby@tables.com”            }        }    ],    “ScannedCount”: 3,    “ConsumedCapacity”: null

}

 

마찬가지로 Bobby가 인터넷에서 자신을 삭제하려는 경우 사용자와 관련된 세 행을 모두 제거해야 합니다.

 

aws dynamodb transact-write-items –client-request-token TRANSACTION4 –transact-items ‘[  {    “Delete”: {      “TableName” : “User”,      “Key” : {“pk”:{“S”:”b201c1f2-238e-461f-88e6-0e606fbc3c51″}}    }  },  {    “Delete”: {      “TableName” : “User”,      “Key” : {“pk”:{“S”:”userName#btables”}}    }  },  {    “Delete”: {      “TableName” : “User”,      “Key” : {“pk”:{“S”:”email#bobby@tables.com”}}    }  }

]’

 

최종 스캔은 이제 테이블이 비어 있음을 보여줍니다.

 

aws dynamodb scan –table-name User{    “Count”: 0,    “Items”: [],    “ScannedCount”: 0,    “ConsumedCapacity”: null

}

 

 

결론

이 패턴은 관계형 데이터베이스에서 마이그레이션하고 DynamoDB에서 고유 제약 조건을 유지해야 하는 경우에 유용하게 쓰일 수 있습니다. 단일 트랜잭션이 둘 이상의 테이블을 수정할 수 있으므로 두 개의 테이블을 사용하여 동일한 패턴을 구현할 수 있습니다. 사용자 테이블에“주 데이터”를 유지하고 두 번째 테이블을 사용하십시오. 이 테이블은 특정 속성에서 고유성을 보장하기 위해 순수하게 사용됩니다.

 

AWS는 DynamoDB에서 가능한 단일 테이블 디자인 개념을 유지하려고 노력 하지만 이 패턴에는 두 개의 테이블을 사용하셔야 보다 편리하게 활용하실 수 있습니다.

 

원문 URL: https://aws.amazon.com/ko/blogs/database/simulating-amazon-dynamodb-unique-constraints-using-transactions/

 

** 메가존 클라우드 TechBlog는 AWS BLOG 영문 게재 글 중에서 한국 사용자들에게 유용한 정보 및 콘텐츠를 우선적으로 번역하여 내부 엔지니어 검수를 받아서, 정기적으로 게재하고 있습니다. 추가로 번역 및 게재를 희망하는 글에 대해서 관리자에게 메일 또는 SNS 페이지에 댓글을 남겨주시면, 우선적으로 번역해서 전달해드리도록 하겠습니다.