DynamoDB의 Write Capacity를 낮춰서 DynamoDB 비용 줄이기

안녕하세요. RecoPick팀의 김성민입니다.

저희 팀은 모바일 혹은 웹 사이트에 자바스크립트를 추가해서 사용자의 행동 기록을 수집한 후, 사용자 로그를 분석해서 사용자의 취향에 맞게 제품을 추천해 주는 서비스를 SaaS(Software as a Service) 형태로 제공해주는 시스템을 개발 및 운영하고 있습니다. 11번가, 텐바이텐, 레진코믹스, 한겨레, 조선일보다양한 e-commerce 사이트에 추천 서비스를 제공 중입니다.

추천 서비스를 제공하는 데 필요한 사용자 로그 및 분석 결과를 저장하기 위해, 저희 팀은 HBase와 DynamoDB 를 사용하고 있습니다.

이번 블로그 포스팅에서는 저희 팀에서 DynamoDB 사용 요금을 줄이기 위해서 DynamoDB의 Write Capacity를 어떤 식으로 조정했는지 공유하고자 합니다.

DynamoDB의 장점은 다른 NoSQL(abase, Cassandra, MongoDB 등등)에 비해서 관리 비용이 거의 zero에 가깝다는 것입니다. 사용자가 특별한 설정을 할 필요도 없고, Read/Write 성능 향상을 위해서 여러 가지 복잡한 설정 옵션을 고려할 필요가 없이,  AWS 관리 console에서 몇 번의 클릭만으로 쉽게 관리할 수 있습니다.

하지만 단점은 Read/Write Capacity 에 따라서 사용 요금이 큰 편차를 보인다는 것입니다.

Case-1 Case-2 Case-3
Indexed Data Storage Dataset Size (GB) 1 1 1
Provisioned Throughput Capacity Item Size (All attributes) (KB) 64 64 64
Number of items read per second (Reads/Second) 0 100 0
 Number of items written per second (Writes/Second) 250 250 500
Data Transfer Data Transfer Out (GB/Month) 10 10 10
Data Transfer In (GB/Month) 10 10 10
Estimate of your Monthly Bill ($)  9,848.24 9,938.68 19,654.49

표 1. DynamoDB의 월평균 예상 사용 요금

위의 표는 초당 Write 횟수에 따라서 DynamoDB의 월평균 예상 사용 요금이 비례하고 있음을 보여줍니다.

위 표처럼, 초당 Write 회수가 250 Writes/Second에서 500 Writes/Second로 증가하면, 비용이 거의 2배로 오르게 됩니다.

반면에 Read 회수에 따라서는 DynamoDB의 비용이 크게 변화되지 않습니다. 
결국, 초당 Write 횟수, 즉 Write Capacity 설정이 DynamoDB의 사용 비용에 큰 영향을 줍니다.

하지만 현실적으로 적절한 Write Capacity 값을 찾기는 쉽지 않습니다.

예를 들어, 아래 그래프와 같이 Write operation이 발생할 경우, 다음 중 가장 적합한 Write Capacity는 얼마일까요?
(1) 100 ~ 250
(2) 250 ~ 500
(3) 750 ~ 1,500
(4) 1,500 ~

정확한 정답은 없지만, 아래 그래프를 보면, Write 회수가 평균 750 Writes/Second이고, 최대 1,500 Writes/Second이므로 Write Capacity 대략 750 ~ 1,500 정도가 되어야 할 것입니다.

DynamoDB Write Capacity 그래프

그림1. DynamoDB Write Capacity 그래프 

즉, DynamoDB에서는 Write 횟수가 갑자기 증가하는 것을 대비해서 예측 가능한 최대 Write Capacity 만큼 설정해야 합니다. 결국, 순간 최대 Write 횟수에 의해서 DynamoDB의 사용 요금이 큰 영향을 미칠 수밖에 없습니다.

만약, Write Capacity를 낮게 하게 되면, Write 회수가 순식간에 증가할 경우, Write operation이 실패하기 때문에, 데이터를 안전하게 보관할 수 없게 됩니다.

그렇다면, 어떻게 Write Capacity를 낮추면서, 순간적으로 Write operation이 증가할 경우에도 Write operation의 실패 없이 데이터를 안전하게 보관할 수 있을까요?

여러 가지 방법이 있을 수 있겠지만, 대략 아래와 같은 2가지 방법을 생각해 볼 수 있습니다.

  1. Write 회수의 증감에 따라서, Dynamo DB의 Write Capacity를 자동으로 조절해 주는 방법 
  2. Write 회수 자체를 항상 일정한 수준으로 유지하는 방법

1번의 경우, DynamoDB의 Write Capacity 조정 횟수 및 조정 폭이 제한적이고, 변경된 Write Capacity가 DynamoDB에 적용되는데 일정 시간이 걸리기 때문에, 온라인 트랜잭션 처리(OLTP) 시에는 적합하지 않을 수도 있습니다.

2번째 방법은 Write operation의 속도 지연이 없이 Write 회수 자체를 항상 일정한 수준으로 유지해야 한다는 점이 어렵습니다. Write operation을 수행하는 쪽에서는 DynamoDB의 Write Capacity에 상관없이 항상 원하는 수준으로 빠르게 Write operation을 수행할 수 있도록 해야 합니다.

저희 팀의 경우, Write operation을 수행하는 쪽이 될 수 있는 대로 DynamoDB의 Write Capacity에 의존하지 않고, 최대한 Write throughput을 낼 수 있게 하려고 1번보다는 2번 방법으로 DynamoDB의 Write Capacity를 낮추도록 했습니다.

Write 회수 자체를 일정한 수준으로 유지하기 위해서 저희가 생각한 방식은 Producer-Consumer 패턴으로 Write operation을 처리하는 것입니다. 즉, 기존에는 DynamoDB에 바로 Write operation을 수행했지만, DynamoDB에 Write 을 수행하는 Producer와 DynamoDB 사이에 Queue를 도입해서 Producer는 Queue에 Write를 하고, Consumer가 Queue에서 DynamoDB에 Write 할 데이터를 꺼내와서 Write operation을 수행하는 것입니다.

기존 방식은 Producer의 Write 회수와 속도가 DynamoDB의 Write Capacity를 결정했지만, Producer-Consumer 패턴에서는 Queue의 대기 시간Consumer의 처리 속도 조절해서 DynamoDB의 Write Capacity를 최소화할 수 있습니다.
그래서, Producer는 기존처럼 빠르게 Write를 수행하고, Consumer가 DynamoDB에 일정한 속도로 DynamoDB에 Write를 하게 함으로써, 항상 Write 회수가 일정한 수준으로 유지될 수 있도록 하는 것입니다.

Producer-Consumer 패턴 적용 전

(a) Producer-Consumer 패턴 적용 전

Producer-Consumer 패턴 적용 후

(b) Producer-Consumer 패턴 적용 후

그림 2. DynamoDB Write Operation 방식

하지만 Producer-Consumer 패턴을 구현할 때, 다음과 같은 2가지 점이 만족하여야 합니다.

  1. Queue나 Consumer에서 장애가 발생하더라도 Write operation이 자동으로 수행되어야 함
  2. Producer의 Write 횟수가 갑자기 증가하더라도 Producer의 Write Throughput을 떨어뜨리지 않을 정도로 Queue가 동작해야 함

위의 2가지 조건을 모두 충족 시키는 Kafka와 Storm을 사용하였습니다.

Kafka는 분산 Queue이기 때문에, 장애 발생 시, 자동으로 fail over가 가능하고, 확장성이 뛰어나기 때문에, 장비만 추가함으로써, Write throughput을 높일 수 있습니다.

Consumer로는 Storm을 사용하였는데, 역시 Kafka와 마찬가지로 장애 발생 시 자동으로 fail over가 가능할 뿐만 아니라, Hadoop과 다르게 실시간 streaming 처리가 가능하므로 Storm을 선택했습니다.

물론, Kafka와 Storm 대신 Amazon SQS와 Kinesis를 사용할 수도 있었지만, 저희 팀에서는 Kafka와 Storm을 사용하면서 이미 성능 검증을 마쳤기 때문에, Kafka와 Storm을 주저 없이 선택할 수 있었습니다.

Producer-Consumer 패턴에 사용할 Queue와 Consumer로 Kafka와 Storm을 선택한 후, 실제 어떻게 DynamoDB의 Write Capacity를 조정하기 위해서 아래와 같이 모델링 작업을 했습니다.

  1. DynamoDB Write operation 횟수 /  sec = 평균 Producer의 총 Write 횟수 / Queue 대기 시간 (sec)
  2. Queue 대기 시간 = Consumer의 프로세스 1개의 평균 처리 속도 x Consumer의 프로세스 개수

저희 팀의 요구 사항은 Producer의 초당 Write 횟수와 관계없이 Dynamo DB의 초당 write 횟수를 조정하고 싶었기 때문에, 위의 식 (1)에서 평균 Producer의 총 Write 횟수는 고정값으로 하고 Queue 대기 시간을 변동 값으로 해서 초당 Dynamo DB Write 횟수를 원하는 수준으로 낮출 수 있도록 Queue 대기 시간을 추정했습니다. Queue 대기 시간은 위의 식 (2)에서 처람 Consumer의 처리 속도가 일정할 경우, Consumer 프로세스의 개수에 좌우됩니다. 따라서 Consumer로 사용한 Storm 프로세스의 평균 속도를 측정한 후, Dynamo DB Write Capacity를 낮추기 위해 추정한 Queue 대기 시간에 맞도록 프로세스 개수를 조정했습니다.

이런 방식으로  DynamoDB의 Write Capacity를 1/3 수준으로 낮출 수 있었습니다.

DynamoDB Write Operation 방식 변경 후, Write Capacity 그래프

그림 3.  DynamoDB Write Operation 방식 변경 후, Write Capacity 그래프

요약 하자면, Kafka와 Storm을 이용해서 Producer Consumer 패턴으로 DynamoDB의 write operation 방식을 변경해서, write capacity를 1/3로 줄일 수 있었습니다.

참고로 Kafka와 Storm을 이용한 Producer Consumer 패턴의 다른 응용으로는 뉴스나 트위터와 같은 스트리밍 데이터의 트래픽을 regulation 하는데 사용 가능합니다. 혹은 slide share와 같이 사용자가 데이터를 올리는 경우에도 응용 가능합니다.

[참고 사항]

스크립트 한 줄로 고품질의 추천 서비스를 제공하는 RecoPick 팀에서 추천 시스템을 개발하고 있습니다. 검색 기술 및 대용량 데이터 분산 처리와 NoSQL에 관심이 많은 s/w engineer 입니다.

공유하기