Dynamic DynamoDB を使ってみた

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

Amazon DynamoDB はとても便利で使い易いサービスですが、
テーブルへの書き込みや読み込みの容量に伴って、スループットを調整する必要があります。
今のところ AWS ではこの調整を自動でやってくれる(オートスケールの)機能はありませんが、
オープンソースで提供されているツールでこれを実現することができます。
そのうちの一つがこの記事で紹介する Dynamic DynamoDB です。

インストールと初期設定

インストールは CloudFormation テンプレート *1 を使って行うことも出来ますが、今回は手動でインストールしてみました。
Dynamic DynamoDB は Python 製なので、pip で簡単にインストールできます。
OS は Amazon Linux(Amazon Linux AMI 2014.03) で試しました。

# easy_install pip
# pip install dynamic-dynamodb
# dynamic-dynamodb --version
Dynamic DynamoDB version: 1.18.3

必要なディレクトリを作成。

# mkdir /etc/dynamic-dynamodb && cd /etc/dynamic-dynamodb
# mkdir logs

起動スクリプトを作成。

/etc/rc.d/init.d/dynamic-dynamodb

#!/usr/bin/env bash
### BEGIN INIT INFO
# Provides:        dynamic-dynamodb
# Required-Start:  $remote_fs $syslog
# Required-Stop:   $remote_fs $syslog
# Default-Start:   2 3 4 5
# Default-Stop:    0 1 6
# Short-Description: Automatic scaling for AWS DynamoDB
# Description:     Dynamic DynamoDB provides automatic scaling for AWS DynamoDB
### END INIT INFO

NAME=dynamicdynamodb
DAEMON=/usr/bin/dynamic-dynamodb
DRY_RUN=$2
DAEMON_START_ARGS="--config /etc/dynamic-dynamodb/dynamic-dynamodb.conf --daemon start"
DAEMON_STOP_ARGS="--config /etc/dynamic-dynamodb/dynamic-dynamodb.conf --daemon stop"
SCRIPTNAME=/etc/init.d/$NAME
SERVICE_LOG_FILE=/etc/dynamic-dynamodb/logs/service.log

if [ "$DRY_RUN" == "--dry-run" ]; then
   DAEMON_START_ARGS="--config /etc/dynamic-dynamodb/dynamic-dynamodb.conf --dry-run --daemon start"
   DAEMON_STOP_ARGS="--config /etc/dynamic-dynamodb/dynamic-dynamodb.conf --dry-run --daemon stop"
elif [ "$2" != "" ]; then
   echo "$2"
   echo "Second parameter has to be --dry-run and is used only when running start/restart/force-reload commands"
   exit 1
fi

# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 1

. /etc/rc.d/init.d/functions

log(){
    timenow=`date +%Y-%m-%dT%H:%M:%S.%N`
    echo "$timenow: $1"
    echo "$timenow: $1" >> $SERVICE_LOG_FILE
}

error_exit(){
  log "$1"
  exit 1
}


do_start()
{
   log "do_start:Starting $NAME"
   daemon $DAEMON $DAEMON_START_ARGS  || error_exit "Failed in starting $NAME service"
}

do_stop()
{
   log "do_stop:Stopping $NAME"
   daemon $DAEMON $DAEMON_STOP_ARGS || error_exit "Failed in stopping $NAME service"
}


case "$1" in
  start)
  do_start
  ;;
  stop)
  do_stop
  ;;
  status)
  status "$DAEMON" "$NAME" && exit 0 || exit $?
  ;;
  restart|force-reload)
  do_stop
  do_start
    #*)
  ;;
  *)
  echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
  exit 3
  ;;
esac

:
# chmod 755 dynamic-dynamodb
# chkconfig --add dynamic-dynamodb

続いて config ファイルの設定です。

/etc/dynamic-dynamodb/dynamic-dynamodb.conf

[global]
# AWS access keys (EC2 に IAM ロールを指定しているため使用しない)
# aws-access-key-id: AWS_ACCESS_KEY
# aws-secret-access-key-id: AWS_SECRET_KEY

# AWS region to use
region: ap-northeast-1

# How often should Dynamic DynamoDB monitor changes (in seconds)
check-interval: 300

# Circuit breaker configuration
# No provisioning updates will be made unless this URL returns
# a HTTP 200 OK status code
#circuit-breaker-url: http://my.service.com/v1/is_up
#circuit-breaker-timeout: 500

[logging]
# Log level [debug|info|warning|error]
log-level: info

# Log file (comment out to get only console output)
log-file: /var/log/dynamic-dynamodb.log

# External Python logging configuration file
# Overrides both log-level and log-file
# log-config-file: /path/to/logging.conf

[table: ^sequences$]
#
# Read provisioning configuration
#

# Thresholds for trigging throughput alarm to send notification (%)
reads-upper-alarm-threshold: 80
reads-lower-alarm-threshold: 30

# Enable or disable reads autoscaling
enable-reads-autoscaling = true

# Thresholds for scaling up or down the provisioning (%)
reads-upper-threshold: 80
reads-lower-threshold: 30

# How many percent should Dynamic DynamoDB increase/decrease provisioning with (%)
increase-reads-with: 50
decrease-reads-with: 50

# Units to increase or decrease reads with, must be either percent or units
increase-reads-unit: percent
decrease-reads-unit: percent

# Maximum and minimum read provisioning
# Dynamic DynamoDB will not provision any more or less reads than this
min-provisioned-reads: 1
max-provisioned-reads: 100

#
# Write provisioning configuration
#

# Threshold for trigging throughput alarm to send notification (%)
writes-upper-alarm-threshold: 80
writes-lower-alarm-threshold: 30

# Enable or disable writes autoscaling
enable-writes-autoscaling = true

# Thresholds for scaling up or down the provisioning (%)
writes-upper-threshold: 80
writes-lower-threshold: 30

# How many percent should Dynamic DynamoDB increase/decrease provisioning with (%)
increase-writes-with: 50
decrease-writes-with: 50

# Units to increase or decrease writes with, must be either percent or units
increase-writes-unit: percent
decrease-writes-unit: percent

# Maximum and minimum write provisioning
# Dynamic DynamoDB will not provision any more or less writes than this
min-provisioned-writes: 1
max-provisioned-writes: 100

#
# Maintenance windows (in UTC)
#
#maintenance-windows: 22:00-23:59,00:00-06:00

#
# Simple Notification Service configuration
#

# Topic ARN to publish notifications to
#
sns-topic-arn: arn:aws:sns:ap-northeast-x:xxxxxxxxx:dynamodb_alert

# Message types to send as SNS notifications
#
# Comma separated list. Currently supported values:
# - scale-up                    Get notifications when the table is scaled up
# - scale-down                  Get notifications when the table is scaled down
# - high-throughput-alarm       Get notifications when exceed high throughput threshold
# - low-throughput-alarm        Get notifications when below low throughput threshold
#
sns-message-types: scale-up, scale-down, high-throughput-alarm, low-throughput-alarm

#
# Other settings
#

# Allow down scaling when at 0% consumed reads
#allow-scaling-down-reads-on-0-percent: true
#allow-scaling-down-writes-on-0-percent: true

# Restrict scale down to only happen when BOTH reads AND writes are in need
# of scaling down. Set this to "true" to minimize down scaling.
#always-decrease-rw-together: true

非常に分かり易いパラメータとなっています。

上記の設定値をざっくりと説明すると…、
sequences というテーブル名に対して、300 秒おきにチェックを実施。

Read, Write ともに..

  • スループットが 80% を上回ったら、SNS のアラートを送信。
  • スループットが 30% を下回ったら、SNS のアラートを送信。
  • 増減値は現在のスループットの 50% ごと。
  • スループット下限値は 1、スケールダウンの際に SNS のアラートを送信。
  • スループットの上限値は 100、スケールアップの際に SNS のアラートを送信。

という感じです。

起動

設定が済んだら起動してみます。

# service dynamic-dynamodb start

オートスケールを確認してみる

スループットが上がった時のログを確認してみます。

# tail -f /var/log/dynamic-dynamodb.log
2014-09-09 15:14:40,837 - dynamic-dynamodb - INFO - sequences - Changing provisioning to 5 read units and 12 write units
2014-09-09 15:14:40,891 - dynamic-dynamodb - INFO - sequences - Updating provisioning to 5 reads and 12 writes
2014-09-09 15:14:40,945 - dynamic-dynamodb - INFO - Sent SNS notification to arn:aws:sns:ap-northeast-x:xxxxxx:dynamodb

SNS からのメールも受信されてますね!

140917-0002

まとめ

非常に簡単なステップで DynamoDB のオートスケールを実現することが出来ました。
リクエストの増減が激しいユースケースや、そうじゃない場合でも、最初に設定する閾値がどれぐらいが妥当なのか測定する目的としても有用なんじゃないかと思います。
最後に、スケールダウンについては 1日4回まで しかできないのでその点は気をつけましょう!

脚注