こんにちは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 |
テーブルを作成
クロールしたアイテムを保存するテーブルを以下のように作成します。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 }) |
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 |
dependencies: | |
cache_directories: | |
- ~/dynamodb pre: | |
- bash circleci.sh | |
- cd ~/dynamodb/; java -Xms256m -Xmx256m -Djava.library.path=DynamoDBLocal_lib -jar DynamoDBLocal.jar | |
background: true |
Dynamic DynamoDBを用いたプロビジョニング量自動調整
DynamoDBの利用料金はストレージ容量、転送容量、書き込み・読み込みスループットのプロビジョニング量で決まります。詳しい説明は公式ドキュメントにあります。その中でも、プロビジョニング量の課金が一番料金を左右する部分です。AWSコンソール上でプロビジョニング量は手動で調整できるので、最初はとりあえず余裕を持って設定しました。(赤線がプロビジョニング量、青が実際に発生したスループット)
しかし、書き込み・読み込みスループットは時間帯や時期によって大きく変動するので、プロビジョニング量を大きめに設定すると無駄な料金が発生してしまい、小さくしてしまうと性能劣化を招く危険性があります。そこで、プロビジョニング量をスループットの増減に応じて自動で調整する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 |
まとめ
DynamoDBはフルマネージドサービスなのでメンテナンスコストもかからず、パフォーマンスも高いことが一番の利点です。しかし、部分的にスキーマ定義を行う必要があることから、スキーマレスであるmongodbと全く同じ使い方ができるわけではありません。詳しくはMongoDBとDynamoDBの性能比較記事を参照してください。 ただし、あくまでKVS的な使いかたで利用するのであればメンテナンスコストの低いDBとして幅広く使うことができます。今回紹介したDynamic DynamoDBも併用すれば利用金額も大幅に節約することができます。 VASILYでは今回の事例のように新しい技術を使って課題を解決していけるエンジニアを募集しています。一緒に新しい技術をどんどん取り入れて、ファッション業界にイノベーションを起こしていきましょう。 VASILYのエンジニア募集要項はこちら