DynamoDB Partitions 심층 탐구

DynamoDB Partitions 심층 탐구

A Deep Dive into DynamoDB Partitions 한글 번역

27 Jun 2016

A Deep Dive into DynamoDB Partitions

Posted by

데이터베이스는 현대 웹 어플리케이션 대부분의 기간이 되고있어 데이터베이스의 성능이 유져 경험에 큰 영향을 미칩니다. 빠른 응답시간이 유져들이 어떤 앱을 사용할지 결정하게하는 요소 중 하나입니다. 그러므로 응답시간을 고려하여 데이터베이스를 디자인하여 최대한 좋은 성능을 낼 수 있도록 하는것이 중요합니다. 이 아티클에서는 어떻게 파티션을 활용하여 DynamoDB 성능을 최적화 할 수 있는지에 대해 설명할 것입니다.

파티션 소개

DynamoDB 성능의 시작과 끝은 파티션이라는 개념입니다. 파티션은 저장공간과 서능의 유닛들이라고 볼 수 있습니다. 파티션을 이해하지 못하면 DynamoDB를 고효율로 활요할 수 없습니다. 그래서 이 파티션에 대해 제대로 파악하고 있으면 좋습니다.

처음 DynamoDB에 테이블을 생성하면 파티션이 하나 만들어지고 이 파티션이 테이블에 할당됩니다. 이 테이블에 이루어지는 생성, 삭제, 업데이트같은 작업들은 할당된 파티션이 있는 노드에서 다루게 됩니다. 우리가 모든 파티션들을 제어할 수는 없지만 어느 정도 영향은 줄 수 있습니다.

한 파티션은 10GB 데이터, 3000 RCU, 1000WCU를 다룰 수 있는데, 새 파티션은 한 테이블에 10GB이상의 데이터가 적재되거나 RCU가 3000을 넘거나 WCU가 1000을 넘게되면 생성됩니다. 새 파티션이 생성되면 데이터들은 새로운 파티션들로 분산됩니다.

DynamoDB는 어떻게 여러개의 파티션으로 데이터를 분산시킬까요? 파티션은 데이터의 파티션 키를 통해서 선택됩니다. 유닉한 파티션 키가있고 데이터마다 파티션이 할당 됩니다. 아래 예제로 확인해보겠습니다. 아래 테이블은 시험과목과 시험을 치른 학생들에 대한 내용입니다.

이 예제는 시험과 학생간에 many-to-one관계가 있습니다. (문제를 단순히 하기위해 한 학생이 같은 과목을 재시험 치는 경우는 없다고 가정합니다.) 이 테이블이 한 학교 학생들의 데이터라면 데이터셋은 크지 않을 것입니다. 하지만 지역의 모든 학생이나, 전국 학생들의 데이터라고 한다면 엄청나게 많은 데이터가 있을 것입니다. 이렇게 되면 우리는 저장, 성능 한도를 초과하여 파티션을 새로 만들어야하게 됩니다.

아래 위 데이터들을 가상으로 분산시켜보았습니다. 초과 된 RCU, WCU, 데이터 사이즈에 기반해서 DynamoDB가 파티션을 3개로 늘리기로 결정했습니다.

위에 보시면 exam ID가 하나의 유일한 파티션으로 할당되었습니다. 하나의 파티션은 데이터 사이즈에 따라 여러개의 파티션키를 가질 수 있습니다. 하지만 하나의 파티션키는 한 개의 파티션에만 할당이 가능합니다. (한 파티션은 여러개 exam_id를 가지는 것이 가능, 한 exam_id는 한개의 파티션 안에만 존재 가능) 하나의 시험은 많은 학생들이 치룹니다. 그러므로 Student ID가 데이터를 검색하는데 좋은 소팅키가 도리 수 있습니다.

더 파티션을 추가하거나, 데이터이 할당 된 파티션을 변경함으로써 원하는대로 무한 확장이 가능합니다. 하지만 여기서 아주 중요한 한계점을 반드시 고려해야합니다.

먼저 파티션의 갯수는 DynamoDB가 결정합니다. 더 높은 성능이 필요하거나 데이터 사이즈가 커지면 DynamoDB가 파티션을 추가합니다. 한번 증가된 파티션은 데이터의 양이나 성능 필요치가 작아진다고 해서 사라지지 않습니다.

다음에는 RCU와 WCU를 적당히 파티션 갯수별로 나눠주어야 합니다. 만약에 30000RCU가 필요하다면 한 파티션이 3000 RCU씩 감당할 수 있으니 총 10개의 파티션이 자동으로 생성됩니다.

콘솔에서 직접 RCU, WCU를 올리면 AWS가 아래처럼 예상 비용을 보여줍니다.

시험-학생 예시를 이용해서, 각 시험별로 데이터들이 파티션에 나누어져 있습니다. 그리고 한 파티션은 10GB 데이터, 3000RCU, 1000 WCU를 수용합니다. 각 시험은 백만명의 학생 데이터를 가질 수 있어, 데이터 사이즈는 10GB를 초과하게됩니다. (파티션 키를 설정할 때 이 사실을 잘 알아두어야 합니다.)(한 파티션 키에 해당되는 데이터들은 여러 파티션으로 쪼개질 수 없음)

RCU, WCU가 테이블당 3000 RCUs, 1000 WCUs를 넘어서게되면 DynamoDB는 파티션을 추가하고 다시 RCUs, WCUs 가 떨어진다고 해서 만들었던 파티션을 다시 제거하지는 않습니다. 그래서 어떤 경우에는 한 파티션에서 정말 작은 RCUs, WCUs를 처리하게 되기도 합니다.

왜냐하면 RCUs 와 WCUs가 원하는대로 잘 문산되어있다 하더라도 성능 병목현상이 발생할 수 있어서입니다. 원하는 성능이 몇개의 파티션을 필요로 하는지에 대한 공식이 있습니다.

읽기 성능에 대한 공식 ,

읽기 성능에 필요한 파티션 수 = 요구되는 RCU / 3000 RCU

쓰기 성능에 대한 공식,

쓰기 성능에 필요한 파티션 수 = 요구되는 WCU / 1000 WCU

전체 성능에 필요한 파티션 수 = (요구되는 RCU / 3000 RCU) + (요구되는 WCU / 1000 WCU)

하지만 이것은 성능에 대한 관점만이고 데이터 저장공간에 대한 관점도 생각해야합니다. 한 파티션에서 수용 가능한 데이터가 10GB라고 하면

저장공간에 필요한 파티션 수 = 원하는 저장공간 크기 in GB / 10GB

아래 공식은 성능관점과 저장공간 관점 모두 포함하여 수용 가능한 파티션 수를 나타내는 공식입니다.

전체 파티션 수 = MAX(전체 성능에 필요한 파티션 수, 저장공간에 필요한 파티션 수)

예를들어서 아래의 성능, 저장공간이 요구된다고 해봅시다.:

RCU Capacity: 7500

WCU Capacity: 4000

Storage Capacity: 100GB

성능 관점으로 필요한 파티션 수는 아래와 같이 계산됩니다.:

(7500/3000) + (4000/1000) = 2.5 + 4 = 6.5

반올림 해서 : 7.

저장공간 크기 관점으로 필요한 파티션 수는 아래와 같이 계산됩니다.:

100/10 = 10

그래서 총 필요한 파티션 수는 아래처럼 계산됩니다.:

MAX(7, 10) = 10

RCU와 WCU는 여러 파티션에 골고루 분산됩니다. 그러므로 여러개의 파티션을 이용하더라도 테이블에 대한 총 RCU와 WCU만을 알 수 있습니다. 파티션 키를 잘 설정해서 파티션 키가 전체 파티션에 골고루 잘 분산이 되어야 이 모든것이 가능하게 됩니다.

좋은 파티션 키 고르기

파티션 키를 고르는데 정답은 없습니다. – 각 데이터셋들의 특성에 따라서 달라집니다. 용량이 작은 테이블에서는 어떤 키를 고르던지 상고나이 없습니다.(3000 RCU 와 1000 RCU 로 한 파티션에서 수용이 가능하다면 좋지 않은 키 구조를 선택하더라도 괜찮습니다.). 하지만 데이터가 점점 커질수록 키를 고르는것이 중요해집니다.

파티션 키는 테이블 생성 시점에 정해야합니다. 만약 콘솔을 사용하신다면 아래와 비슷한 화면을 마주하시게 될겁니다,

아니면 CLI를 사용하신다면 아래와 같은 명령어를 실행해야합니다.

aws dynamodb create-table \ --table-name us_election_2016 \ --attribute-definitions \ AttributeName=candidate_id,AttributeType=S \ AttributeName=voter_id,AttributeType=S \ AttributeName=state,AttributeType=S \ --key-schema AttributeName=candidate_id,KeyType=HASH AttributeName=voter_id,KeyType=RANGE \ --provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1

파티션 키를 고를 때 가장 먼저 할 일은 최대한 많이 구분이 가능한 속성을 선택하는 것입니다. 예를들어 직원들이 많이 있다면 직원 ID를 고를 수 있고, 부서 ID를 고르는 것은 좋지 않습니다. 부서는 몇개 되지 않을테니까요.

그 다음에는 균등하게 모든 키 값에 접근할 수 있는 속성을 고르는 것입니다. 예를들어 투표 기록 시스템을 생각해보면, 모든 후보자가 비슷한 표를 얻는다고 가정할 때 후보자 ID가 적당합니다. 만약 한 명이나 두 명의 후보자가 90%의 표를 받게된다면 후보자 ID가 적절하지 않게됩니다.

또 하나 할일은 시간 제약을 받지 않는 읽기/쓰기 패턴을 가진 속성을 고르는 것입니다. 만약 이런 속성을 찾기 어렵다면 키들을 결합해서 만들어볼 수도 있습니다.

지금 까지 얘기한 것을 모두 2016 미국 선거를 예로 다시 설명해보겠습니다. 우리는 모든 후보자들에 대한 모든 표를 기록하고 싶다고 해봅니다.

각 정당은 2명에서 10명의 후보자들을 지명할 수 있습니다. 표들은 각 후보자들에게 균등하게 분포되지 않을 것입니다. 아마 한 두명의 후보자들이 대다수의 표를 얻게 될 것입니다.

여기서 10000 WCU 정도로 표를 받는다고 가정해 봅시다. 가장 첫번째 인스턴스에서 우리는 테이블을 만들고 자연스럽게 후보자 ID를 파티션 키로 설정합니다. 그리고 date/time을 range key로 설정합니다. DynamoDB는 이 예시에서 10개의 파티션을 생성하게 됩니다. (방금 나왔던 공식을 기억해봅시다. 10000WCU를 감당하려면 10개의 파티션이 필요합니다) 만약 후보자가 10명이라면 DynamoDB는 파티션키를 아래처럼 분산시킬 것입니다:

이 모델은 크게 잘못되었습니다. 먼저 우리는 후보자당 WCU를 10000 WCU보다 한참 이하로 제한하고 있습니다. 위에 얘기한 대로 실세계에서는 한두명의 후보자에게 대부분의 표가 몰릴 것입니다. 그래서 인기 없는 후보자들은 WCU를 낭비하게 될 것입니다.

표들이 전체 후보자들에게 균일하게 분산된다고 하더라도 투표자들은 제각각 다른 시간대에서 제각각 다른 시간에 투표를 할 것입니다. 그러므로 어떤 시간에는 특정 투표자에게 부하가 몰리게 될 수 있습니다. 파티션 키를 섬세하게 디자인 하더라도 이런 시간대 관련된 이슈는 발생할 수 있습니다.

전국 투표로 두 명의 후보자만 있다고 해봅시다. 100000 WCU가 요구되고 DynamoDB는 이를 위해 100개의 파티션을 생성합니다. 하지만 후보자 ID가 파티션키로 선택되어 있다면 한 후보자는 한 파티션에밖에 들어갈 수 없습니다. 100개의 파티션이 만들어졌지만 98개의 파티션은 아무일도 안하고 놀게됩니다. 결과적으로 파티션 저장공간 제한을 금방 넘어서게 되고 어플리케이션은 금방 뻗어 투표를 기록할 수 없게 될 것입니다.

이 이슈를 해결하기 위한 key-sharing plan 을 소개합니다. 파티션 키에 prefix를 1~10 까지나 1~ 1000으로 붙이는 것입니다(데이터 셋 크기에 따라 달라질 수 있습니다). 이렇게 되면 더 많은 파티션 키를 가질 수 있어 DynamoDB가 데이터를 전체 파티션에 골고루 나눌 수 있습니다. 아래를 그림을 보세요:

key-sharing을 하지 않은 히스토그램입니다:

파티션 키는 이런 모습일 것입니다. (예시를 위해 두 후보자를 넣었습니다):

key-sharing을 한 이후 히스토그램 입니다.:

key sharing plan을 통해 어떻게 파티션 전체에 골고루 데이터를 분산시킬 수 있는지 배워봤습니다. 쓰로틀링을 최소화한 파티션 키는 아래와 같습니다:

결론

DynamoDB에 넣을 데이터모델을 디자인하기 위해 고려해야할 요소들은 Local Secondary Indexes 와 Global Secondary Indexes 등 더 많습니다. 데이터모델을 디자인하기 위해 고려해야할 인덱스에대해 더 알고싶다면 AWS문서를 보시고 인덱스가 어떻게 데이터베이스 성능에 영향을 주는지 이해하시면 도움이 됩니다.

데이터베이스 모델링은 데이터 베이스 구조를 짜는데와 성능 최적화를 하는데 아주 중요합니다. DynamoDB는 확장이 아주 용이한 솔루션이긴 하지만 데이터베이스 모델이 후지다면 어플리케이션 성능도 후질 것입니다.

출처

https://shinesolutions.com/2016/06/27/a-deep-dive-into-dynamodb-partitions/

from http://limago.tistory.com/4 by ccl(A) rewrite - 2021-09-19 01:00:20