NoSQL DynamoDB 기본 개념
다음 글에서는 관계형 데이터베이스와 NoSQL의 차이점을 알아보고, DynamoDB의 기본개념을 설명합니다.
그리고 DynamoDB에 맞게 데이터 구조를 설계해보고,
DynamoDB 테이블을 생성하는 방법과 데이터를 추가하는 방법,
데이터를 검색하는 하는 방법에 대해서 이야기 하겠습니다.
DynamoDB는 NoSQL 데이터베이스를 제공하는 서비스입니다.
아마존에서 개발한 NoSQL 데이터베이스이며, 사용자가 따로 설치, 운영, 확장을 하지 않아도 원할 때 바로 서비스를 이용할 수 있습니다.
DynamoDB를 사용하는 이유는 다음과 같습니다.
1. 성능과 편의성, 대규모 DB 구축에 필요한 인적자원과 비용을 절감할 수 있습니다.
왜냐하면, DB를 구축하고 서비스에 맞게 사용이 가능하게 하려면 전문가가 필요하고 그것을 구축하고 확장하는 데에 추가 비용이 들어가기 때문입니다.
2. 읽기와 쓰기가 매우 빈번해서 처리 속도가 빨라야 하는 서비스 또는 작은 용량의 데이터가 매우 많을 때,
고가용성(High Availability)의 분산 데이터베이스를 자체적으로 운영하기에는 부담이 될 때 적합합니다.
* 여기서 데이터 베이스의 고가용성 즉, High Availability의 분산 데이터 베이스가 장애가 네트워크던 시스템 내부장애 건 어떠한 장애가 발생하였을 때,
해당 데이터 베이스를 사용하는 사용자들에게 지속적인 데이터 베이스 사용을 위해 어떤 대책을 마련해두어서 사용을 지속적으로 할 수 있게 보장해주는 것이라 생각할 수 있습니다.
3. 모바일 게임이나 소셜 네트워크와 같은 서비스를 많이 사용하는 현대에 짧은 데이터의 정보를 처리하는 NoSQL 방식의 데이터베이스를 효과적입니다.
이상 DynamoDB를 사용해야하는 이유이고,
트랜잭션(Transaction)을 이용하는 처리 과정이나, 조인(Join)과 같은 복잡한 쿼리가 필요한 환경에는 적합하지 않습니다.
이유를 설명하자면 RDBMS같은 경우에는 트랜잭션을 이용해서 시스템의 장애가 발생하였을 때 다시 돌아가서 트랜잭션을 하나하나 살펴보면서 장애를 판단하기도하고,
다시 롤백시키기도 하지만 대부분의 NoSQL 차라리 다시 한번 데이터를 저장하고나 다시 불러오는 게 효과적이라는 취지로 만들어졌기 때문입니다.
또한 조인과 같은 복잡한 쿼리의 환경에는 적합하지 않다라는 것도 같은 맥락입니다. NoSQL은 한 테이블에 튜플에 대해서 유일성과 최소성을 만족해야합니다.
그래서 데이터를 다룰 때, 중복된 데이터가 없기 때문에 조인과정에서 원하는 데이터를 뽑아서 사용하지만, DynamoDB는 그냥 원하는 데이터만 가지는 테이블을 만들어서 따로 목적에 의해 사용하면 그만입니다.
또한 RDBMS는 테이블에 데이터를 저장하기 전에, 테이블 구조를 만들어 놓아야 합니다. 또한, 테이블 간의 관계를 Primary Key와 Foreign Key를 이용하여 정의해야합니다.
이것을 데이터베이스 스키마(Schema)라고 합니다.
이 스키마를 통해서 관계형 데이터 베이스가 돌아가기 때문에, 미리 정해진 스키마에 맞는 데이터를 추가해야 하고, 스키마에 맞지 않으면 데이터를 추가할 수 없습니다.
반면, NoSQL인 데이터베이스는 기존의 관계형 데이터베이스와는 달리 스키마가 정해져 있지 않습니다.
따라서, 틀에 맞게 이름에 대해서 스키마를 설정해 놓으면 이름만 넣는 것이 아니고, 다른 데이터를 넣을 수도 있습니다. 이를 가리켜 비정형화 된 데이터 저장이 가능하다고 합니다.
물론 NoSQL을 이용해서도 정형화된 데이터를 저장할 수 있습니다.
정형화된 데이터베이스만 다루는 RDBMS와
비정형화된 데이터베이스도 다루는 NoSQL의 차이점에 대해서 그림에서 보여줍니다.
관계형 데이터베이스의 데이터 구조는 상단에 보면 카테고리가 있어서 ID, 이름, 주소, 전화번호, 사번, 부서, 직급 등 정해진 속성에 맞는 데이터 타입과 데이터 종류가 정해집니다.
혹여서 타입이 다른 데이터를 넣는 다면, 에어를 발생시킵니다. 이게 스키마에 종속된 구조이기 때문입니다.
NoSQL 데이터베이스의 데이터 구조의 오른쪽 아이템을 보겠습니다.
도서관에서 책에 대한 정보를 넣는다고 생각하면 책의 정보가 정형화되지 않아도 상관이 없습니다.
예를 보면, ProductName은 같은데, 그 내부에 다른 Attribute는 두번째 부터 id 101은 ISBN이 있고, id 102는 Vendor가 있습니다. 데이터의 비정형화를 볼 수 있었습니다.
DynamoDB는 리전별로 생성할 수 있으며, 성능과 가용성을 위해 데이터를 3곳의 가용 영역(Availability Zone)에 복제하여 저장합니다. 물론 복제과정은 AWS에서 알아서 해줍니다.
다른 가용 영역이 장애가 발생해서 정지해도 DB는 정지하지 않고 고가용성을 보장합니다. 따라서 데이터베이스의 가용성, 지속성을 모두 제공해주기때문에 사용자가 따로 데이터를 백업할 필요가 없습니다.
DynamoDB는 데이터 저장 용량의 제한이 없습니다. 데이터 용량이 증가하면 DynamoDB가 알아서 스토리지를 늘리고, 클러스터를 확장하여 데이터를 분산합니다.
알아서 확장하여 분산한다는 것은 정말 많은 시간 절약입니다.
물론 분산과 확장과정 속에서 데이터베이스를 다루는 방법에 대해서 알 수 있지만 저라면 그 시간에 사용자를 만나서 서비스에 대해서 보완해나가려고 합니다.
기존 데이터 베이스인 예를 들자면, 제가 사용했던 MongoDB는 테이블의 용량이 커지면서 샤딩이라는 방법을 통해 테이블의 데이터를 여러 서버에 분산해서 저장했습니다.
그래서 어플리케이션 레벨에서 샤딩을 프로그래밍하거나 DB Engine에서 지원하는 샤딩 기능을 이용해서 개발, 운영을 했습니다.
제가 해보니까 이 과정에서는 데이터를 어떻게 분배할 지에 대한 샤딩키도 필요로 하고 추후에 확장할 규모에 대해서 예측해야 하는 경우가 생겨서 데이터 베이스나 서버를 관리하는 직무를 가진 분의 스트레스와 업무가 가중됩니다.
DynamoDB에서는 IaaS서비스로 모든 것을 다 제공해줍니다. 그냥 가져다 쓰시면 됩니다. <= AWS 행사에 가면 가장 많이 듣는 이야기죠...ㅎ
* 샤딩(Sharding) ?
샤딩은 데이터베이스를 분할(파티셔닝하여 저장하는 방법입니다. 서버 한 대에 대용량의 데이터베이스를 저장하기는 쉽지 않으므로 여러 대에 분할하여 저장해야 합니다.
테이블별로 분할하는 방식, 사용자 이름 순, 날짜 순, 지역이름 순 등으로 분할하여 저장하는 방식, 해시키를 기준으로 분할하는 방식 등 다양한 방식이 있습니다.
DynamoDB는 읽기/쓰기 처리량을 직접 지정할 수 있습니다.
트래픽이 증가하여 사용량이 많아지면 처리량을 늘릴 수 있고, 사용량이 적어지면 처리량을 줄일 수 있습니다.
지정한 처리량은 DynamoDB가 Latency를 일정하여 유지하여서 관리하기 때문에 퍼포먼스 측면에서는 걱정하지 않아도 됩니다.
DynamoDB의 모든 데이터는 SSD(Solid State Drive)에 저장됩니다.
14.1 DynamoDB의 데이터 모델
DynmoDB를 사용하기 전에, DynamoDB의 데이터 모델을 먼저 알아보겠습니다.
DynamoDB의 기본개념은 제 글 중에 자세한 개념을 설명한 글이 있습니다. 참고 하시기 바랍니다.
http://interconnection.tistory.com/60
DynamoDB의 기본 데이터 저장 구조는 다음과 같습니다. 간단하게만 소개합니다.
*테이블(Table)
- 테이블은 아이템들의 모음입니다. 들어갈 수 있는 아이템의 개수는 제한이 없습니다.
- 테이블은 기본 키를 반드시 지정해야합니다.
- 리전당 생성할 수 있는 테이브릐 최대 개수는 256개이며 AWS에 요청하여 늘릴 수 있습니다.
* 아이템(Item)
- 아이템은 속성(Attribute)들의 모음입니다. 들어갈 수 있는 속성의 개수는 제한이 없습니다. 단, 아이템의 크기는 속성 이름과 값을 포함해서 64KB입니다.
- 기본 키는 필수로 포함하고 있어야 하며, 복합 키와 기타 속성을 가집니다.
* 속성(Attribute)
- 속성은 키-값(Key-Value) 방식입니다. 키는 문자열이라야 합니다.
이상 기본 데이터 저장 구조에 대한 3가지의 개념이구요.
속성에서 지원하는 값 두 가지 데이터 형식에 대해서 설명하겠습니다.
* 스칼라 데이터 형식(Scalar data types) : 숫자(Number), 문자열(String), 바이너리(Binary)가 있습니다.
- 숫자 : 정수와 실수를 지원하며 실수는 소수점 이하 38자리, 10-128에서 10+126까지 입니다. 숫자는 0을 트림(Trim)합니다.
예) 0.3 ->.3 , 00300 -> 300
- 문자열 : UTF8 형식이며 대소를 비교할 때는 아스키(ASCII) 코드를 기준으로 합니다.
- 바이너리 : 바이너리 데이터는 BASE64 형식으로 인코딩하여 저장하면 됩니다. 대소를 비교할 때는 각 바이트를 부호없는 정수로 취급합니다.
* 다중 값 형식(Multi-valued types) : 스칼라 데이터 형식의 배열 형태입니다.
- 숫자 세트(Numver Set)
- 문자열 세트(String Set)
- 바이너리 세트(Binary Set)
다중 값 형식에 들어가는 값은 중복될 수 없으며 값이 하나라도 들어가 있어야 합니다.
값들은 정렬되지 않으며 정렬 순서도 저장되지 않습니다. 다중 값 형식은 기본 키로 사용할 수 없습니다.
이상 속성에서 지원하는 값 데이터 형식이구요.
속성 값에 대해서 제약에 대해서 몇가지 더 설명하자면,
속성 값은 NULL이나 빈 문자열은 저장할 수 없습니다. 저장할 수 없기때문에 아예 Key가 생기지 않습니다.
DynamoDB에서 검색을 하려면 기본 키(Primary Key)로 인덱스(Index)를 생성해야 합니다.
그리고 이 기본 키는 테이블을 생성할 때 반드시 지정해야 하며, 이 기본 키로 생성되는 인덱스를 테이블 인덱스라고 합니다.
DynamoDB가 지원하는 기본 키 형식은 두 가지입니다.
1) 해시(Hash) 형식 기본 키
- 속성 하나를 기본 키로 사용합니다.
- 기본 키의 값은 스칼라 데이터 형식만 가능합니다. 다중 값 형식은 지원 하지 않습니다.
2) 해시와 범위(Range) 형식 기본 키
- 속성 두 개를 기본 키로 사용합니다.(복합 키)
- 첫 번째 속성은 해시 키본 키로 사용하고, 두 번째 속성은 범위 기본 키로 사용하여 두 가지를 복합적으로 사용하는 방식입니다.
해시 기본 키는 일치(Equal)방식의 검색만 지원하며,
범위 기본 키는 일치, 부등호, 포함, ~로 시작 등의 검색을 지원합니다.
그리고 해시 기본 키 속성 값의 최대 크기는 2048바이트이며,
범위 기본 키 속성 값의 최대 크기는 1024바이트입니다.
DynamoDB는 기본 키로 생성하는 테이블 인덱스 이외에도 보조 인덱스 (Secondary Index)를 생성 할 수 있습니다.
기본 키로 생성한 인덱스 하나만으로는 검색 기능이 부족하기 때문에, 사용자가 원하는 속성으로 보조 인덱스를 생성하여 검색에 활용할 수 있습니다.
이 보조 인덱스는 사용이 빈번하기 때문에 성능을 위해 읽기/쓰기 용량 유닛을 따로 설정할 수 있습니다.
다음은 두가지의 보조 인덱스 입니다.
1) 로컬 보조 인덱스 (Local Secondary Index)
- 해시 키는 테이블 인덱스의 해시 기본 키와 같고,범위 키는 다르게 설정한 것입니다.
- 테이블당 5개까지 생성할 수 있습니다.
- 로컬 보조 인덱스는 테이블을 생성할 때 함께 생성해야 하며, 테이블이 생성된 이후에는 추가, 수정, 삭제를 할 수 없습니다.
- 물론 추후 로컬 보조 인덱스의 추가, 수정, 삭제 기능을 출시 예정에 있다고 알고 있습니다.
-로컬 보조 인덱스는 테이블에 해시 기본 키와 범위 기본 키를 사용할 때만 생성할 수 있습니다.
2) 글로벌 보조 인덱스(Global Secondary Index)
- 해시 키와 범위 키 모두 테이블 인덱스와 다르게 설정한 것입니다.
- 범위 키는 생략할 수 있습니다.
- 테이블당 5개까지 생성할 수 있습니다.
- 글로벌 보조 인덱스는 테이블을 생성할때 함께 생성해야 하며, 테이블이 생성된 이후에는 추가, 수정, 삭제를 할 수 없습니다.
DynamoDB는 데이터를 읽을 때, Eventually Consistent Read와 Strongly Consistent Read를 사용할 수 있습니다.
1) Eventually Consistent Read
- 읽기 처리량(Read Throughput)을 최대화하지만 읽은 데이터가 최근 완료된 쓰기 결과를 반영하지 못했을 수도 있습니다.
- 쓰기가 데이터의 모든 복사본에 반영되는 것은 1초 내에 이루어집니다. 최신 데이터를 얻으려면 짧은 시간 내에 읽기를 반복해야합니다.
2) Strongly Consistent Read
- 최근 완료된 쓰기 결과가 모두 반영된 데이터를 가져옵니다.
두가지의 데이터를 읽는 방식의 차이점은 DynamoDB가 데이터를 기록하고 저장하는 방식이 복사본을 가지고 가용성을 보장해주는데,
이 과정에서 약점이 생긴다는 것입니다. 데이터를 쓰기로 기록하면 복사하는 과정에서 시간이 걸리는데 그 과정에서 빠르게 읽기 요청이 올때,
데이터의 무결성을 보장하진 않는다는 것입니다.
즉, 빈번하고 빠른 데이터의 읽기 쓰기를 하는 경우에는 Strongly Consistent Read를 사용해서 읽으라는 이야기 입니다.
프로비저닝 된 처리량(Provisioned Throughput)은 사용자가 원하는 수치를 지정하면 DynamoDB가 알아서 지정된 수치만큼 처리량을 제공해주는 것입니다.
1) 필요한 읽기 용량 유닛(Read Capacity Units)
- 초당 읽은 아이템 수 x KB 단위 아이템의 크기(근사치 반올림) (Eventually Consistent Read를 사용하는 경우 초당 읽은 아이템 용량은 두배가 됩니다.)
2) 필요한 쓰기 용량 유닛(Write Capacity Units)
- 초당 쓴 아이템 수 x KB 단위 아이템 크기 (근사치 반올림)
예) 512바이트(1KB로 반올림 됨)을 토당 200개 항목을 읽거나 쓰면, 1KB x 200 = 200 유닛
1.5KB(2KB로 반올림 됨)를 초당 200개 항목을 읽거나 쓰면, 2KB x 200 = 400 유닛
Strongly Consistent Read는 1000 읽기 용량 유닛으로 1KB짜리 아이템을 초당 1,000번 읽을 수 있으며,
Eventually Consistent Read는 500 읽기 용량 유닛으로 1KB짜리 아이템을 1,000번 읽을 수 있습니다.
읽기 용량의 유닛 수는 API 호출 수가 아닌 초당 읽은 아이템 수로 결정됩니다.
500유닛을 읽는다고 하면 1KB짜리 아이템을 GetItem으로 500번 호출하는 것과, BatchGetItem으로 한번에 아이템 10개씩 50번 호출하는 것은 동일합니다.
DynamoDB의 데이터 조회 방법은 두 가지입니다. 두 가지 데이터 조회 방법 각각은 한 번에 조회할 수 있는 용량은 1MB입니다.
1) Scan : 조건 없이 모든 데이터를 가져옵니다.
2) Query : 해시(기본)키에 특정 값을 지정하고, 범위 (기본)키에 조건을 지정하여 원하는 데이터를 가져옵니다. 범위 (기본)키에 조건을 지정하는 것은 생략할 수 있습니다.
* DynamoDB의 기술적 제약 및 한계(Limit)에 대해서는 다음 링크를 참조하기 바랍니다.
http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Limits.html
다음 글은 이번 장의 내용이 연계되는 것으로 DynamoDB에 맞는 데이터 구조 설계를 하고 직접 AWS에서 만들어 보겠습니다.
* Reference
1. 확장가능한 NoSQL 분산 데이터 베이스를 제공하는 DynamoDB - http://pyrasis.com/book/TheArtOfAmazonWebServices/Chapter14/01