リクエストごとに一意なIDの生成方法

911 views
Skip to first unread message

k2junior

unread,
Jul 30, 2009, 10:58:16 AM7/30/09
to Google-App-Engine-Japan
初めて投稿させて頂きます。
近藤と申します。

最近、課題を抱えていまして、相談させて頂きたいと思います。

Google App Engineの利点を活かすため、スケーラビリティを確保できるアプリの実装をしたいので、Sessionを使わないような方式
を考えています。
その場合に、2重送信の抑止機能をSessionを使わないで実装をしたいですが、その制御のためにどうしてもリクエストごとに一意となるIDが必要と
いう結論になりました。

しかし、Google App Engineでは自動的にサーバ数が増減するので、単純にAtomicIntegerを使ってカウンターを実装すると
IDが重複してしまうのではないかという懸念があります。
また、リクエストごとにBigTableのカウンターを作れば実装はできますが、BigTableがボトルネックになりそうです。

クラウド上で一意となるリクエストのIDを生成する方式のアイデアをお持ちの方はいらっしゃらないでしょうか?
実行中のマシン名を取得する方法があれば何とかなりそうなのですが。。。

atusi nakamura

unread,
Jul 30, 2009, 12:51:11 PM7/30/09
to google-app-...@googlegroups.com
a2cです。こんばんは

昔DataStoreを使ってカウンターを作って見たのですが一意にするのがムズカシかったです。
そこで、似たような感じでメモキャッシュを使ってカウントアップさせながらIDを
作ってうまく言った記憶があります。

今回の場合、連番である必要がなければ、適当に空データを作って
そのKeyを使うというので行けるのではないでしょうか?

--
atusi nakamura
at...@a2c.biz



2009/07/30 23:58 に k2junior<k2.ju...@gmail.com> さんは書きました:

k2junior

unread,
Jul 30, 2009, 1:20:57 PM7/30/09
to Google-App-Engine-Japan
こんばんは。近藤です。

>今回の場合、連番である必要がなければ、適当に空データを作って
>そのKeyを使うというので行けるのではないでしょうか?
確かに連番である必要はないですね。なるほど。
適当にIDを生成する戦略であれば、例えば、ログインが前提になりますが、「ログインID+時刻」をリクエストIDにすれば、ほぼ一意性を保てますね。
同じユーザから1ミリ秒以内にリクエストが飛んでくると重複しますが、発生する可能性は限りなく0に近いかと。

Shinichiroh Takezaki [Virtual Technology]

unread,
Jul 30, 2009, 2:28:54 PM7/30/09
to google-app-...@googlegroups.com
竹嵜です、こんばんは。

 私のサンプル(http://blog.virtual-tech.net/2009/07/google-app-engine-restfulcrudservlet.html)はAJAXなんで、あまり参考にならんかもしれませんが、一応、やっていることを説明させていただきますね。
 まず、受け取ったリクエストパラメータには、アプリのPKが入っていることが前提なんですが、Insertの前にそのPKで検索を試みて、登録されていなければinsertするというようなことをしています。これで必ず1つだけ登録されることが保証されます。ただ、検索はすごく速いので問題ないのですがInsertは遅いのでちょっと問題です。Memcacheなどでなんとかやりたい気もしますが、私はまだできていません。
 アプリのPK作成では、ユーザIDやタイムスタンプなどと組み合わせれば、どのタイミングで作成しても問題ないと思いますが、クライアント側で送信する都度PKが変わってしまうと登録成功になってしまうので、送信ボタンを押すタイミングで生成するのではなく、画面に表示されたタイミングなどで生成するのがよいのではないかと思います。

         // 1. クライアントから受け取ったXML(JSON)をオブジェクトに変換
JdoUtils jdoUtils = new JdoUtils();
Invoice invoice = (Invoice) getEntity(req, MODEL_PACKAGE);

try {

jdoUtils.getInvoiceByKey(invoice);
// 2. すでに登録されている場合エラー
Status status = new Status();
status.code = HttpStatus.SC_CONFLICT;
status.message = "PK already exists.";
doResponse(resp, status, toXml, MODEL_PACKAGE);
} catch (JDOObjectNotFoundException e) {
// 3. 登録されていなければinsert
jdoUtils.insert(invoice);
doResponse(resp, invoice, toXml, MODEL_PACKAGE, HttpStatus.SC_CREATED);


2009/07/31 2:20 に k2junior<k2.ju...@gmail.com> さんは書きました:

--
_/ 有限会社バーチャルテクノロジー 竹嵜 伸一郎
_/  Virtual Technology, Ready to Cloud
_/ http://www.virtual-tech.net/

Hideaki Kiko

unread,
Jul 30, 2009, 8:40:10 PM7/30/09
to google-app-...@googlegroups.com
こんにちは、木香です。

> 確かに連番である必要はないですね。なるほど。
> 適当にIDを生成する戦略であれば、例えば、ログインが前提になりますが、
>「ログインID+時刻」をリクエストIDにすれば、ほぼ一意性を保てますね。

連番の必要がなく、ユニークなIDの生成であれば、
uuid を利用するのはいかがでしょうか?

http://www.python.jp/doc/release/lib/module-uuid.html

uuid.uuid4() でランダムなIDを生成可能です。

k2junior

unread,
Aug 2, 2009, 7:50:13 AM8/2/09
to Google-App-Engine-Japan
こんばんは、近藤です。
ご教授、ありがとうございます。

>竹嵜さんへ
2重送信抑止は、私も前のリクエストIDをhiddenに保存しておいて、
そのIDをBigTableに保存することで実現するつもりでした。この方式しかないのかなと思っています。

画面に表示されたタイミングで空データのエンティティを登録する方式もありかなと考えていたのですが、
データの整合性を保証していないエンティティを登録してしまうことになるので、
データの整合性保証のロジックをどうやって確保するか、という課題が残っています。

>木香さんへ
UUIDというものがあるのですね。知りませんでした。
JavaにもRFC 4122 の実装のjava.util.UUIDがあったので、
Google App Engine上での挙動を探ってみます。


Reply all
Reply to author
Forward
0 new messages