開発環境をローカルで構築すると、ネットワークのない環境でも開発ができるので非常に便利です。特に昨年は飛行機に乗る機会がとても多く、僕の乗っていた便はまだ機内インターネット接続サービスの恩恵は受けられない便ばかりだったので、飛行機の中でも開発を続けるためには、開発環境とドキュメントをローカルに入れておくのはとても重要でした。VagrantとDashにはとてもお世話になりました。
さて最近DynamoDBを使ってサービス作っています。AWSのサービスは非常に便利でよいですが、DynamoDBはElastiCacheやRDSみたいにローカルにMemcachedやRedis、MySQL、PostgreSQLなど入れておけば代用できるわけでもないので、どうすんだろ、と思いました。
もう1点DynamoDBの問題として、DynamoDBの課金体系は保存容量以外に毎秒何回読み込みと書き込みができるかに対してお金を支払いますが、無料枠は、合計書き込み5回/秒、読み込み10回/秒までです。でもDynamoDBではグローバルセカンダリインデックスを用意すると、それぞれにつき少なくとも書き込み、読み込み1ずつ割り当てなければならないので、1つのテーブルが1回/秒で済まないケースもあって、本当にお試しでもない限り、無料枠をすぐ使い切っちゃいます。といっても、月数百円とかですむのですが、油断してて料金発生するのも怖い。
で、DynamoDBの互換のシステムをローカルで構築できる物があればいいのになって思って調べたら、Amazonが公式にDynamoDB Localなるものを公開していて、これを使ったらものすごく簡単にそれができてしまいました。
紹介記事は2013年9月ですがリンクは最新版を指すようになっていてダウンロードされたのは2014年1月8日版でした。2013年12月に発表されたグローバルセカンダリインデックスにも対応。Javaで書かれているのでjarファイルを実行すればサービスが起動してしまう。ポート番号はデフォルトが8000ですが、8000なんてなにか他のものと容易に衝突しそうなんでそこはは変えました。
1 |
java -Djava.library.path=. -jar DynamoDBLocal.jar --port 8088 |
それで、次はアクセスをしてみるのですが、開発はPythonを使うことが多いのでbotoを使いました。botoってconnectionの際にhostとportを指定できるようになってるんですね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
from boto.dynamodb2.layer1 import DynamoDBConnection from boto.dynamodb2.table import Table from boto.dynamodb2.items import Item from boto.dynamodb2.fields import HashKey, RangeKey, GlobalAllIndex import boto.dynamodb2.types import hashlib import datetime conn = DynamoDBConnection( aws_access_key_id='123456', aws_secret_access_key='123456', host='localhost', port=8088, is_secure=False) table_name = 'testtable' tables = conn.list_tables() if table_name not in tables['TableNames']: Table.create(table_name , schema=[ HashKey('id', data_type=boto.dynamodb2.types.STRING), RangeKey('time', data_type=boto.dynamodb2.types.NUMBER) ] , throughput={'read': 1, 'write': 1} , global_indexes=[ GlobalAllIndex('groupIndex', parts=[HashKey('grp',data_type=boto.dynamodb2.types.STRING), RangeKey('time', data_type=boto.dynamodb2.types.NUMBER)], throughput={'read': 1, 'write': 1})] , connection=conn ) time = int(datetime.datetime.now().strftime('%s')) m = hashlib.md5() m.update(str(time)) id = m.hexdigest() table = Table(table_name, connection=conn) item = Item(table, data={ 'id' : id, 'time': time, 'grp' : id+"-foobar" }) item.save() results = table.query(grp__eq=id+"-foobar", index='groupIndex') for res in results: print res['id'], res['time'] |
実際のDynamoDBのようにコンソールが用意されていてテーブル作成できるわけではありませんが、そもそもきちんとテーブル定義はコードとして残しておいたほうがいいですね。
AWSのブログ記事に以下の様なことが書かれています。
- スループットの指定は無視される。スループット以上にアクセスすることはできてしまう。
- アクセスキーとリージョンはDBファイル名を生成するときにだけ関係ある
- シークレットキーは無視される
- テスト用なので、プロダクション作らないほうがいいよ
ということで、これでとりあえずお金の心配も、ネットワークの心配もせずにDynamoDBで開発ができるようになりました。