ラベル GAE の投稿を表示しています。 すべての投稿を表示
ラベル GAE の投稿を表示しています。 すべての投稿を表示

2012年12月22日土曜日

[GAE/J] Datastore(M/S->HRD)の切り替えで対応したこと

2012/08/24 GAEからM/S利用者へ向けてHRDへの移行を推奨メールが送信されました。
大喜利部というアプリののサーバサイドを移行したときの体験記を書いていますので、よければこちらを参照してください。

基本的に移行後に困ったことは以下の2点です。

1.Blobkeyが変わってしまう

これに関しての解決方法は別途記事で記載済みです。下を参考にしてください。
GAE M/SからHRDへ移行時のBlobkey振り替え対応

2.インデックスの遅延が発生する

これは非常に困りました。
JavaのJDOを利用したデータベース設計としているのですが、この場合、①Query発行してデータ一覧取得するとたまに取得できないことがあります。②また更新されるまで若干遅延があり得るので情報の信頼性もかけてしまいます。
これの解決は以下の方法を取りました。
①これはどうしようもないので、登録直後の一覧取得の際には、極力、更新が追いつかない場合があることをユーザに知らせるようなメッセージを表示するようにしました。
②信頼性を確保するために、LowLevelAPIを利用します。LowLevelAPIのgetは遅延が発生しないとのことです。

導入初期はかなり混乱しましたが、これらの対応により今は障害発生せず沈静化しています。困った場合は試してみてください。

2012年12月8日土曜日

[GAE/J] 登録エラー

背景

GAE/Jで登録時に以下のエラーとなる。
JDOによりデータベース設計してます。
Uncaught exception from servlet java.lang.IllegalStateException: Primary key for type Title is of unexpected type java.lang.Integer (must be String, Long, or com.google.appengine.api.datastore.Key) at com.google.appengine.datanucleus.DatastoreFieldManager.exceptionForUnexpectedKeyType(DatastoreFieldManager.java:162) at com.google.appengine.datanucleus.StoreFieldManager.storePrimaryKey(StoreFieldManager.java:481) at com.google.appengine.datanucleus.StoreFieldManager.storeObjectField(StoreFieldManager.java:179) at org.datanucleus.state.AbstractStateManager.providedObjectField(AbstractStateManager.java:1447)

原因

プライマリーキーとしてInteger型は受け入れられない模様。
Long型に変更したら解決しました。


2012年11月30日金曜日

[GAE/J] DataStore更新時のConcurrentModificationException エラー


背景

アプリ「大喜利部」のユーザ情報の更新ロジックを追加したところ、更新が成功するときと、失敗する時があった。
成功/失敗の切り分けが難しく、原因も特定できずに、ハマりにハマって4時間以上も時間を費やしてしまったので、メモをとっておくことに。

エラー

Google App Engine のログを参照したところ、commitのタイミングで「ConcurrentModificationException」エラーが発生してました。

java.util.ConcurrentModificationException: too much contention on these datastore entities. please try again.

原因に辿り着くまで

「ConcurrentModificationException」エラーは以下が原因で発生します。
 (1)Datastoreの楽観的ロックが失敗した場合
 (2)複数のリクエストが同じエンティティを並行して「get~put」した場合

アプリ「大喜利部」ではAPIを作成して、XMLによる通信を行い、データのGET/POSTをしているわけですが、単純なファイルの更新なので、デッドロックしているような個所は見当たらない。
よって(1)の可能性はないため、考えられる可能性としては(2)。

HTMLファイルに更新するformを作成してみて、アクセスしてみる。
この場合、問題なく更新されるので、更新プログラムは問題ないはずと判断し、クライアント(APIの使用側)を疑うことに。

ユーザ情報更新ロジックに問題はなさそうだけど、なんどやっても成功と失敗を繰り返す。
ソースをデバッグ実行するとほぼ成功する。(このへんでかなり混乱しました)
悩みに悩んだ挙句、更新を非同期で行っていることに気づき、続きのロジックを読み込むと、その流れでユーザ情報を再取得していました。
Google App Engine の DataStore 更新は JDO で行っているのですが、更新を非同期でputし、更新中の情報を同時にgetしていたということになります。
まさに(2)の状態(同じエンティティをput-get)であったわけです。

対処方法

更新を同期処理に変更することで、「ConcurrentModificationException」エラーは起こらなくなりました。
※今回の場合はユーザ情報の更新なので、基本は1人しか更新と取得はしないですが、複数の人が更新するエンティティの場合は、失敗時にリトライするなどの工夫が必要です。

参考





2012年11月18日日曜日

[GAE/J] DatastoreのM/SからHRDへの移行 体験記


[Google App Engine(GAE)] のDatastore を [Master/Slave Datastore(M/S)] から [High Replication Datastore(HRD)] への移行した時の体験を記録しておきます。
対象としたサービスは大喜利部のサーバサイドプログラムです。

背景

2012/08/24 GAEからM/S利用者へ向けてHRDへの移行を推奨メールが送信されました。
要約すると、M/Sは廃止します。ツールを用意したので、HRDへの移行をお勧めします。
といった内容です。
また、GAEの管理サイトでは以下のような画面が表示されるようになり、移行を決意しました。


対象アプリのデータ量は目安として、大きなKindは以下の2つ。
 お題Kind 200万レコード
 ボケKind 3万レコード
 他にも15 Kind 程 存在します。

事前準備

2012/11/10 00:00〜開始しました。(この記事を書きながらなので、目安程度に考えてください)
事前準備としてサーバメンテナンスをお知らせしてありましが。
アプリに大してもメンテナンス中には操作できなくなるように細工をしてあり、その細工を開始します。

サーバの複製をしていきます。
管理ツールメニュー(左側)の[Administration]-[Application Settings]を開きます。
下の方に[Duplicate Application Settings]がありますので、複製を開始していきます。

複製アプリ名を[New Application Identifier]に入力し、[Check Availability]で使用できる名称かチェックし、[Duplicate Application...]を選択します。
My Applications へ移動し、HRDのアプリが複製されました。

複製アプリに現行アプリをデプロイ

複製アプリに、現アプリをデプロイします。
[appengine-web.xml]ファイルの[application]タグの名称を更新してデプロイを実行。(このとき私はversionを1に戻しました)

(ここまでの完了時間 11/18 00:50)※これを書きながらなので非常に時間がかかっています。

[Datastore Indexes]が、インデックスが[Serving]に変わるまで待ちます。
インデックスは25ほどありますが、全て0Entityなので、結構すぐ終わります。
(完了したのが、11/18 01:00 <約10分かかりました>)

データの移行

ツールを使ってデータを移行していきます。
現行サーバの管理ツールメニュー(左側)の[Administration]-[Application Settings]を開き、[Migrate Application]-[View Migrate Tool...]を選択します。

[Desination Application]でMigrationするデータベースを選択し、[Start Migration]を選択して、移行を開始していきます。(メールに通知するかのチェックボックスがあります)
[All blobs and references to those blobs will automatically be migrated. However, any serialized references to blobs must bemigrated manually.]の一文が気になりますが、後で対応します。


ステップは以下の通りです。
1.Catch up
2.Copy
3.Waiting    (このステップではここまで進むことになります)
4.Sync
5.Read-only
6.Catch up
7.Sync
8.Alias

移行を開始したのは、11/18 01:30です。
進行状況は[Administration]-[Application Settings]を開き、[Migrate Application]-[View Migrate Tool...]と進むと進行画面を再度見ることができます。

[3.Waiting]になり完了メールが来たのが、11/18 02:30 で約1時間かかりました。

現行アプリをRead-onlyにする

現行アプリをRead-onlyにします。(このステップでは[8.Alias]まで進みます)
[Activete Read-only]実行できますが、[Launch Incremental Copy]を実行すると、移行中の増減などの取りこぼしを防げるようになります。

[Launch Incremental Copy]を押して、開始します。(11/18 02:45 開始)
更新がほとんどなかったので、10分程度で終了。

続けてActivate Read-only をクリックし、読み取り専用にします。(11/18 02:55 開始)
11/18 03:10 <15分程度>で完了しました。
Syncしてるので、再同期してると思いますので、[Launch Incremental Copy]は不要かもしれません。

完了!

最後に[Finish Migration]して、移行を完了します。

比較的簡単に完了できました。
後はアプリで確認などしていきます。
[Billing Setting]がクリアされていますので、再度設定してください。

気になったこと

移行後、[Datastore Viewer]を参照してもデータがない場合がありました。
移行直後は時間がインデックスが更新されるまでに時間がかかるのかな?
アプリで普通に参照はできるのに、[Datastore Viewer]では参照できない状態にありますした。
時間が立った今は、1秒もすればインデックスとして適用され表示されますが、始め混乱しました。
皆様も混乱しないようにしてください。


もう一つ困ったことが。
[Blob]を利用している場合、新旧で[Blob key]が変わっています。これの対策もする必要があります。
詳細は別記載しましたので、下の記事を参照ください。

[GAE/J] M/SからHRDへ移行時のBlobkey振り替え対応

背景

[Google App Engine(GAE)] のDatastore を [Master/Slave Datastore(M/S)] から [High Replication Datastore(HRD)] への移行しました。
対象としたサービスは大喜利部のサーバサイドプログラムなのですが、Blobを使用しています。

移行した際、Blobkeyは振り直しされるようで、移行後は旧DatastoreのBlobkeyをデータベースに保持するようにしていると、移行後に参照できなくなてしまいます。

[GAE]では[Python]で使用できる、[BlobMigrationRecord]クラスが用意されており、
[.get_new_blob_key(old_key)]というメソッドが用意されているのですが、Javaではこのクラスがなく、以下の方法で回避したので、記録しておきます。
The BlobMigrationRecord Class

解決方法

あまり記載がなく苦労したのですが、どうやら移行した際のBlobKeyの新旧のBlobkeyは「__BlobMigration__」というKindで管理されているようです。

よって、管理ツールの[Datastore Viewer]でSelect分を実行すると新旧の紐付けが分かるということになります。
[ SELECT * FROM __BlobMigration__ ]

つまり、これらを紐づけるようにすれば良い訳です。

[BlobMigrationRecord Class] get_new_blob_key() method for Java

Pythonと同じような[BlobMigrationRecord]の[get_new_blob_key()]メソッドと同じことができるJava版を作ってみましたので掲載しておきます。
自由に使っていただいて問題ないです。
(「いいね」とか「+1」とか「コメント」とかもらえると喜びます)

eclipse4.2インストール 体験記

背景

eclipse3.7を利用していたのだが、なぜか起動すると、システムエラーに。
仕方がないので、この際なので最新バージョン(4.2)を導入することにしました。

eclipse ダウンロード

下のページで[Eclipse IDE for Java Developers]をダウンロード。
Eclipse Downloads

解凍し、eclipse起動まで問題なく動作。

Plugin インストール

とりあえず、直近で必要なPluginは[Google App Engine]だけなので、下のページの通りに、インストールを実施。
Google Plugin for Eclipse 4.2(Juno)
以下のプラグインをインストールする訳だが、
http://dl.google.com/eclipse/plugin/4.2Android関連のダウンロードが過去の経験上分かっていたので、[Google App Engine]に必要な内容だけに絞りインストールしました。(他はまた時間があるときにインストールしようと考えています)
・Google App Engine Tool for Android
・SDKs
   Google Web Toolkit SDK
   Google App Engine SDK

なんなくインストールが完了しました。

[Google App Engine]へデプロイ

既存の[Google App Engine]アプリを開いたときにバージョンがあがったためだと思いますが、[App Engine SDK]へのパスが外れていたので、設定し直しました。

いざ、デプロイしようとすると以下のようなエラーが。

どうやら、appengine-web.xml に<threadsafe>タグ(マルチスレッドとするか)がなかったためにエラーとなっていました。

これで、デプロイすると、無事配置ができました。

参考