DynamoDBの導入とDynamic DynamoDBを用いたプロビジョニング量自動調整

f:id:vasilyjp:20180927090637j:plain


こんにちはVASILYエンジニアの松本です。VASILYではクローラーの仕組みを大幅に見直した際にDynamoDBの導入を行いました。今回はその導入方法とDynamic DynamoDBを用いた運用方法について話したいと思います。

 

DynamoDBを導入した理由

iQONではクローラーで取得したデータをDynamoDBに保存しています。DynamoDBを導入した理由は以下の通りです。

・ ECサイトごと、さらには商品ごとにクロールするデータの形式が異なるためスキーマレスである必要があったこと。

・ DynamoDBはデータベース容量が増大した際も自動でスケールしてくれるのでメンテナンスコストがかからないこと。

・ 平均レイテンシーは1桁台のミリ秒単位であること。

 

iQONでは1日約80万点のアイテムをクロールしているので、メンテナンスコストがかからず、ある程度のパフォーマンスが担保できることがDynamoDBの魅力でした。DynamoDBに関する説明はこのスライドに詳しく書いてあります。

DynamoDBの導入手順

AWS SDK for Rubyを使ったDynamoDBの利用

まずaws-sdkのgemをインストールします。

gem install aws-sdk

DynamoDBはサーバーにインストールして使うものではなくあくまでサービスなので、開発環境やCircleCIなどのテスト環境ではDynamoDBと互換性のあるDynamoDB Localを使います。
# -*- coding: utf-8 -*-
require 'aws-sdk'
class DynamoDB
@@dynamodb = nil
def self.instance
return @@dynamodb if @@dynamodb
credentials = Aws::Credentials.new('aws_access_key', 'aws_secret_key')
dynamo_config = { region: 'ap-northeast-1', credentials: credentials, }
if Rails.env != 'production' #本番環境以外ではDynamoDB Localを利用
dynamo_config[:endpoint] = "http://localhost:8000"
end
@@dynamodb = Aws::DynamoDB::Client.new(dynamo_config)
end
end
view raw dynamodb.rb hosted with ❤ by GitHub

テーブルを作成

クロールしたアイテムを保存するテーブルを以下のように作成します。AWSコンソール上からでもテーブルの作成は可能ですが、DynamoDB Localにも同様のテーブルを作成したかったのでその方法を記載しました。 DynamoDBは基本的にはスキーマレスなのですが、HASH keyとRANGE keyについてはスキーマを定義する必要があります。DynamoDBを使いこなすためのkeyやインデックス定義の仕方はこの記事が参考になります。

dynamodb = DynamoDB.instance
dynamodb.create_table({
table_name: 'crawled_items',
key_schema: [
{ attribute_name: 'original_url', key_type: 'HASH', },
{ attribute_name: 'taskgroup_id', key_type: 'RANGE', },
],
attribute_definitions: [
{ attribute_name: 'original_url', attribute_type: 'S', },
{ attribute_name: 'taskgroup_id', attribute_type: 'S', },
],
provisioned_throughput: { read_capacity_units: 1, write_capacity_units: 1, },
})
データの書き込みはこんな感じ
record = { original_url: 'http://example.com/item', taskgroup_id: '0001', title: 'sample', price: 1000 }
dynamodb.put_item({ table_name: 'crawled_items', item: record })
HASH keyとRANGE keyの二つをスキーマに定義した場合は二つのkeyで値を取り出す。
records = dynamodb.get_item({ table_name: 'crawled_items', key: {"original_url" => 'http://example.com/item', "taskgroup_id" => '0001'} })
records.item.each do |key, value|
puts "#{key}: #{value}"
end

CircleCIへのDynamoDB Local導入

VASILYではテストツールとしてCircleCIを利用しています。 CircleCIはDynamoDBを標準ではサポートしていないため、テスト時にDynamoDB Localを動かすように設定する必要がありました。 まずはDynamoDBをubuntuに入れるシェルスクリプトを記述。 circleci.sh

#!/bin/bash
set -x
set -e
if [ ! -d ~/dynamodb ];
then
mkdir ~/dynamodb cd ~/dynamodb
wget http://dynamodb-local.s3-website-us-west-2.amazonaws.com/dynamodb_local_latest.tar.gz
tar zxf dynamodb_local_latest.tar.gz
fi
view raw circleci.sh hosted with ❤ by GitHub
dynamodbディレクトリがなければAmazonから最新版を取得して展開するようにしています。 circle.ymlでDynamoDB Localを起動するように指定します。 circle.yml
dependencies:
cache_directories:
- ~/dynamodb pre:
- bash circleci.sh
- cd ~/dynamodb/; java -Xms256m -Xmx256m -Djava.library.path=DynamoDBLocal_lib -jar DynamoDBLocal.jar
background: true
view raw circle.yml hosted with ❤ by GitHub
dependenciesのcache_directoriesに展開済のdynamodbディレクトリをキャッシュするように指定し、次回以降のCircleCIのセットアップの時間を短縮することができます。 あとは、preでDynamoDB Localを起動させればOKです。 参考にした記事

Dynamic DynamoDBを用いたプロビジョニング量自動調整

DynamoDBの利用料金はストレージ容量、転送容量、書き込み・読み込みスループットのプロビジョニング量で決まります。詳しい説明は公式ドキュメントにあります。その中でも、プロビジョニング量の課金が一番料金を左右する部分です。AWSコンソール上でプロビジョニング量は手動で調整できるので、最初はとりあえず余裕を持って設定しました。(赤線がプロビジョニング量、青が実際に発生したスループット)

f:id:vasilyjp:20160301161403p:plain

 しかし、書き込み・読み込みスループットは時間帯や時期によって大きく変動するので、プロビジョニング量を大きめに設定すると無駄な料金が発生してしまい、小さくしてしまうと性能劣化を招く危険性があります。そこで、プロビジョニング量をスループットの増減に応じて自動で調整するDynamic DynamoDBを導入しました。導入の際に参考にしたのはこの記事です。

Dynamic DynamoDBで指定できるオプションについて

DynamoDBはconfigファイルの設定に様々なオプションを設定することができます。オプションが多すぎるので、最低限のものだけ設定しました。 dynamic-dynamodb.conf

[global]
# 認証周りの設定
aws-access-key-id: AWS_ACCESS_KEY
aws-secret-access-key-id: AWS_SECRET_KEY
# リージョンの設定
region: ap-northeast-1
# DynamoDBが自動調節をチェックする頻度(秒)
check-interval: 300
[logging]
log-level: info
log-file: /var/log/dynamic-dynamodb.log
[table: ^crawled_items$]
# # Read provisioning configuration
# # 現在のスループットがプロビジョニング量の何%になったらscale up / scale downするかのしきい値
reads-upper-threshold: 90
reads-lower-threshold: 30
# 自動調整するときに何%プロビジョニング量を増減させるか
increase-reads-with: 50
decrease-reads-with: 50
# %単位でプロビジョニング量を増減させるか、unit単位で増減させるか設定(ここでは%を指定)
increase-reads-unit: percent
decrease-reads-unit: percent
# プロビジョニング量の最大値と最小値の設定
min-provisioned-reads: 1
max-provisioned-reads: 20
# # Write provisioning configuration
# # 現在のスループットがプロビジョニング量の何%になったらscale up / scale downするかのしきい値
writes-upper-threshold: 90
writes-lower-threshold: 30
# 自動調整するときに何%プロビジョニング量を増減させるか
increase-writes-with: 50
decrease-writes-with: 50
# %単位でプロビジョニング量を増減させるか、unit単位で増減させるか設定(ここでは%を指定)
increase-writes-unit: percent
decrease-writes-unit: percent
# プロビジョニング量の最大値と最小値の設定
min-provisioned-writes: 10
max-provisioned-writes: 200
その他のオプションについてはこちらのドキュメントを参照してください。 これらのオプションを設定し、Dynamic-DynamoDBを動作させたところ以下のようにプロビジョニング量がスループットに応じて自動調整されるようになりました。 

f:id:vasilyjp:20160301161416p:plain

まとめ

DynamoDBはフルマネージドサービスなのでメンテナンスコストもかからず、パフォーマンスも高いことが一番の利点です。しかし、部分的にスキーマ定義を行う必要があることから、スキーマレスであるmongodbと全く同じ使い方ができるわけではありません。詳しくはMongoDBとDynamoDBの性能比較記事を参照してください。 ただし、あくまでKVS的な使いかたで利用するのであればメンテナンスコストの低いDBとして幅広く使うことができます。今回紹介したDynamic DynamoDBも併用すれば利用金額も大幅に節約することができます。 VASILYでは今回の事例のように新しい技術を使って課題を解決していけるエンジニアを募集しています。一緒に新しい技術をどんどん取り入れて、ファッション業界にイノベーションを起こしていきましょう。 VASILYのエンジニア募集要項はこちら

カテゴリー