Google App Engine SDKの開発サーバーのデータストアはtmpディレクトリにデータを保存するため、マシンを再起動するとデータの中身が全部消えてしまいます。毎回テストデータを用意するのが面倒なので、本番サーバーからデータを移してくるための方法を調べてみました。すると
bulkloader.py
というユーティリティを使うと、簡単に本番サーバーのデータをダウンロードして保存し後からリストアすることができることがわかりました。ということで早速試してみます。
参考にしたのは以下のサイト。
http://code.google.com/intl/en/appengine/docs/python/tools/uploadingdata.html※2010/01/31追記:--db_filenameオプションの使い方を掲載しました。
■前準備app.yamlに以下の設定を追加してから、
appcfg.py update
で本番デプロイを行います。
- url: /remote_api
script: $PYTHON_LIB/google/appengine/ext/remote_api/handler.py
login: admin
これだけで準備ばっちりです。余談ですが、
app-engine-patchを使うと、最初からこの設定がapp.yamlに含まれています。
■使用方法本番サーバーからローカルにデータをダンプするときは以下のコマンドを実行します。
bulkloader.py --dump --kind=<kind> --url=http://<appname>.appspot.com/remote_api --filename=<data-filename>
たとえば私のアプリからhon_heroという名前のModelのデータをダンプしたいときには、
bulkloader.py --dump --kind=hon_hero --url=http://akisutesama.appspot.com/remote_api --filename=hon_hero.dump
などとするとうまくいきます。
ダンプしたデータを本番サーバーにリストアするときは以下のコマンドを実行します。
bulkloader.py --restore --kind=<kind> --url=http://<appname>.appspot.com/remote_api --filename=<data-filename>
--dumpが--restoreになっただけです。本番障害でデータが失われたときにリストアするためのコマンドなので、実行すると本番サーバーのデータがすべてダンプした地点のデータに置き換えられます。ご利用の際には細心の注意を!
ダンプしたデータをローカルサーバーに入れるときは以下のコマンドを実行します。
bulkloader.py --restore --kind=<kind> --url=http://localhost:8080/remote_api --filename=<data-filename> --app_id=<appname>
本番だけではなくてローカルサーバーにもリストアができます。ローカルサーバーにリストアする際の注意点として、
- dev_appserver.pyでアプリケーションが動いている必要があります。
- --urlオプションをローカルホストに書き直す必要があります。
- --app_idオプションで、自分のアプリケーションのapp_idを指定してやる必要があります。
これでローカルテストがだいぶ楽になりました。
同様にして、本番からデータをダンプしてローカルに入れるだけでなく、ローカルからデータをダンプして本番に入れることもできます。新しく実装した箇所に最初からデータを入れたい場合などに使えると思います。
■log, progress, resultを賢く使うbulkloader.pyを実行すると、デフォルトでは以下のような名前のファイルが自動的に生成されると思います。
bulkloader-log-20091211_145622.log
bulkloader-progress-20091211_145622.sql3
bulkloader-result-20091211_145622.sql3
これらはそれぞれ「ログファイル」「現在どのエンティティまでダンプされたかを格納するデータベース」「実際にダンプした内容を格納するデータベース」となっており、上手く使えば2回目以降のダンプ実行時間を劇的に短くすることができます。
ログファイルを指定する際には--log_fileオプションを、データベースを指定する際には--db_filenameと--result_db_filenameを、それぞれ指定してください。たとえば、以下のようなシェルスクリプトを用意しておくと便利です。
#!/bin/sh
# 前回の実行結果が残っているとエラーになる(上書きしてくれない)ので、まずいったん消す
if [ -e hon_hero.dump ]; then
rm hon_hero.dump
fi
# bulkloader.pyを実行する
# db_filenameとresult_db_filenameは一緒のファイルを指定してもかまいません。
# (その場合は、一つのsqlite3データベースに一緒に格納されます)
# db_filenameとresult_db_filenameは、db_fileやresult_db_fileのように短縮して書いても動作するみたいです
bulkloader.py --dump \
--url=http://akisutesama.appspot.com/remote_api \
--kind=hon_hero \
--filename=hon_hero.dump \
--log_file=bulkloader-log-hon_hero.log \
--db_file=bulkloader-progress-hon_hero.sql3 \
--result_db_file=bulkloader-progress-hon_hero.sql3
こうすることで、2回目以降はbulkloader-progress-hon_hero.sql3の中身とリモートのdatastoreの中身を比較して、追加更新のあったもののみをダウンロードし、それ以外はローカルに保存してあるデータベースの中身を利用するので、劇的に処理が速くなります。結果はこちら。
[INFO ] Connecting to akisutesama.appspot.com/remote_api
[INFO ] Have 2610 entities, 2610 previously transferred
[INFO ] 2610 entities (974 bytes) transferred in 0.4 seconds
1回目のロードには130秒かかったのですが、2回目はすべてローカルに保存されているデータを使ったので、なんと0.4秒で済んでいます。
こうしてダンプしたデータをローカルサーバーでリストアするときは、たとえば以下のようなシェルスクリプトを使います。
#!/bin/sh
# --db_fileと--result_db_fileには先ほどのダンプ時に指定したものとは別のファイルが必要になります
# (先ほどのデータベースはappspot.com用として設定されるので、localhostで使用するとエラーになってしまいます)
# --db_fileと--result_db_fileには特別な名前としてskipを指定することができます
# この名前を使用するとデータベースへの書き込み/読み込みを行いません
bulkloader.py --restore \
--url=http://localhost:8000/remote_api \
--app_id=akisutesama \
--kind=hon_hero \
--filename=hon_hero.dump \
--log_file=bulkloader-log-restore.log \
--db_file=skip \
--result_db_file=skip
■注意点appspot.com以外のサーバー(たとえばlocalhostなど)からデータをdumpしたりrestoreしたりする際には、必ず--app_idオプションを指定する必要があります。これを忘れていて詰まりました><
もし特定の条件を満たすデータのみをダウンロードしたいという場合などは、設定ファイルをPythonで書く必要がありますが、
appcfg.py download_data
を使うと良いと思います。