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

2013年12月21日土曜日

Google Appengine の Master/SlaveからHRD移行

久しぶりに仕事ネタです。最近出稼ぎばかりなので。

顧客に使ってもらってるAppengineが何か最近重い気がするので、今更High Replicationに移行することにしました。
そうです。割と最近までMaster/Slaveだったのです。

結論から言うと、移行自体は最近ようやく落ち着きましたが、結構渋いトラブルに見舞われました。

  1. データモデルに一部PolyModelを使ってるのだが、外部レコード参照で仕方なくkey()を使っていた
  2. Migration Toolを使って、稼働中にデータ転送を試してみたが、
    1. コピー自体は一瞬でした。DataStore Staticsticsで見ると、339MB。この程度だと速いみたいですね。
    2. 元サーバのdatastoreをreadonlyにして「ない」場合も一応コピーは出来ますが、Launch Incremental Copyを押せば、何度もリトライしてくれます。
    3. RevertとFinishの意味を勘違いして、Finishを押してしまった。
      1. RevertじゃなくてAbortとか書いてほしい。
      2. Finishは「データ転送を完了ってことにしていいよ」で、次に進んじゃいます。
    4. なんとDNSも書き換わって、旧URLで新URLで接続してくれてしまうことに。
      1. 最悪、remote_apiでデータ運べばいいかと思っていたので泡食いました。
  3. 仕方なく、新URLで確認すると、
    1. データ表示がうまくいかないので、データ移行が失敗してたのかと思ったけどそうではなく、
    2. 前述のキー値が書き換わってないので、旧サーバにデータを取りにいってエラーで落ちてたらしい。
      1. django templateの奥で死んでいたので、シレっと処理はつづく。結果、空表示が続くことに。
      2. ※Model.key()ってワールドユニークだったのね。
      3. ReferencePropertyにしてるカラムは、全て、コピー先でも参照できてます。ちゃんと書き換えてくれてるらしい。
    3. 仕方ないので、スクリプトをグルグル回して、key()の書き変えをすることに。
      1. そしたら今度は、開発初期のゴミデータで、classプロパティが壊れてるレコードがあり、そこで引っかかってスクリプトが回らない。
        1. 厳密にはPolyModelのロードで、変なクラスを探そうとして死ぬ。
      2. 仕方ないので、それ以外を避けて修復。
  4. はー。やっと一段落
  5. ついでにruntimeをpython25からpython27に変えてみようか。
    1. バージョンをずらしてupdate掛けてみたら、なんと旧バージョンが動かなくなった。
    2. ログを確認すると、見たこともないエラーが
      1. AttributeError: class Reference has no attribute '__new__'
      2. python25プログラムから、python27ランタイムを呼んじゃってる気配。
    3. runtimeバージョンは、サーバ全体で共通設定らしい。
8割がた小生のミスです。恥さらしもいいとこですが、他に困ってる人の助けにでもなれば。

とりあえず心に刻んだのは

  • PolyModelは辞めよう。小生には使いこなせない
  • Model.key()を直接扱うのは辞めよう。
  • 同一アプリケーションに、複数バージョンのpython runtimeは混在できない。


2012年9月30日日曜日

appengine python27 threadsafe:true

先日、python2.7環境で「動かしただけ」のappengine アプリケーションを、本格的に threadsafe:trueを試してみました。

例によって、情報は足りてるのですが、英語のドキュメントを読んでも今ひとつ要領を得ません。

早い話がこうです。

  • threadsafe:trueにしたら
    • app.yamlは
      • actionsの拡張子はすべて"app"にしなければならない
      • いや?*.pycじゃね?と思うかも知れませんが、カンケーないらし。
    • 個々の*.pyは
      • import webapp2
      • webapp2.WSGIApplicationの変数名を、必ず"app"にしなければならない
        • yamlの*.appってそういう意味????
      • 直接、深いディレクトリの*.pyを起動することは出来ない。
        • ひょっとして、modulename.modulename.app とか書けばいいのか??

2011年11月23日水曜日

Google AppEngine Minimim Spend、だと?

色々企業努力により、日額料金はだいぶ安くなったので余裕こいてたのですが、
本日の支払い$2。アレ?もっと安くね?

週間の利用料金は、確かに$0.14まで抑えてますが、Charge Sentでいきなり$1.96増えてます。ナニコレ?と思ったら、最低請求金額(Minimum Spend)らしい。先週分は$3.89で、サラっと$2越えてたので気づきませんでした。

言われてみれば、$0.14とかクレジット請求したら元がとれないでしょうから、繰越にするのかと勝手に思っちゃってました。日本のケータイの「無料通話分」を想像してましたが、あれだって別件で固定料金とられてますしね。

するってーと、何かい? $0.4/日ぐらいは使わないと損だってことですかい?
いやまて、それでオーバーした日には、グーグルの思うツボでしょう。
とはいえ、もう10倍はイケますよと言われると、

backendの実験をしてみようかのう。

2011年11月13日日曜日

Datastore Read Operationsだけじゃない

11/08の実施から依然として有料圏内ですが、課金額はだいぶ落ち着いて来ました。

普通に使ってると真っ先にDatastore Read Operationsに引っかかるので、それに目が生きがちですが、標準設定で一番課金額を食うのは、実はFrontend Idle Instancesなんですね。

少なくとも1インスタンスにつき15分相当の金額を取られるので、Instancesの増減を減らす方が、最初は必要でしょう。

それに、どうやらmemcacheが効くのはインスタンス単位らしいのです。故に、各インスタンスがばらばらにキャッシュする上に、都合よく分散しないみたいなので、特定のインスタンスのキャッシュが毎回忘れてるとかになりかねません。

Idle InstancesをAutomatic-1にしちゃったので、Pending Latencyのルールが今ひとつ判らないままですが、課金額は$1未満まで落ち着きました。



この中でmemcacheの効果はどれほどかはちょっと判らないですね。もう一度offにして様子を見るしかなさそうです。問題のRead Operationsが$0になったことは残念ながら一度もないので。

参考までに筆者のケースは
  • 初日 $1.70
  • 2日目 $1.33 あちこちmemcacheを使用&途中からIdle Instancesを最大2に設定
    • Frontend InstancesのBillable Used Hoursが31.92で、$1.28。
  • 3日め $0.60 Idle Instancesを、最大1に設定
    • Frontend InstancesのBillable Used Hoursが13.06で、$0.53。
まとめると
  • limitが小さいのはDatastore Read Operationsで、
    • memcacheにキャッシュするしかない
  • 上昇が早いのはFrontend Instances Hours
    • Perfomance設定のIdle Instancesを減らすしかない
と感じました。

2011年11月12日土曜日

appengine 新課金対策 その2

DataStore Read Operations Quotaを喰らって以来、色々試行錯誤を続けてます。

全体的な課金額を減らすことは出来ていますが。Read Operationsを0に抑えるのはかなり難しいですね。memcacheを使っても減った気がしません。ただこの辺りはユーザの操作のバラツキがかなりあるので、アクセスログを精査する必要があるでしょう。

初日は、サービスが止まってた分もあり正規の運用では無かったと思います。
2日目は、Backendsの実権をしちゃったこともあり、やや高いですね。
3日めから、memcacheで色々節約しようとしてます。



日本時間では現在は土曜日なので、平日と同列に扱ってよいものかどうか?本日分は、$1未満には抑えられそうです。ただしFrontend Instances Hoursの上昇が早いのが気にはなってました。もっと早く調べるべきでした。

ああ、なるほど、これですね。



複数のインスタンスが勝手に立ち上がって処理する。それは良いのですが、その立ち上げの時間も課金額に含むって話らしいのです。どうなのそれ?

http://najeira.blogspot.com/2011/09/google-app-engine.html
http://www.google.com/enterprise/cloud/appengine/pricing.html

ログを見ていて気になってはいたのですよ。memcacheに入ってるデータを引っ張ってるはずなのに、スピンアップに時間が掛かってるケースがある。インスタンスが違ってた訳ですね。

となると、Front Instancesを1つに絞って、cronはBackendsに突っ込むのがどうやら正しい運用、というかグーグル側の想定運用ということになりそうです。

色々試してみると、ファイルを細々とロードしてるページでは、割とアッサリ3つ挙がっちゃうみたいですね。ただし、2つめ以降の出番は少ないようなので、Idle Instances を絞るか、Pending Latencyを下げて、アッサリ落ちるようにするか。

取り急ぎ、Max Idles Instancesとやらを減らしてみました。



Instacesは、待機Auto 、Max 2 にして、本日分は様子見。

2011年11月11日金曜日

appengine 新課金対策その1

Data Read OpsのOverQuotaErrorに引っかかって以来、色々試してますが、

現段階でのbackendsはちょっと失敗でした。単価がfrontより高いし、「動きっぱなし」「課金しっぱなし」っぽいので、cronからの移行ではかなり高く付きます。試したのが夜中だったから、課金枠を増やしてどうにかなりましたが、DeadlineExceedで死んでた分が死ななくなったのもあるようです。

とりあえずFront instance HoursとDatastore Read Opsを減らす方向でmemcacheを使うことにします。


対応前までのQuotaがこんな感じですね。本日分の業務も10時から始まってますが、Frontend Instance Hoursの殆どは、12時間前(昨日22時以前)以前です。

顧客の運用は、「予約制」の「客商売」の「窓口業務」なので、毎日負荷のバラツキが結構あります。それこそがmemcacheを導入せざるを得なかった理由ですね。ブラウザリロードするな、とは言えません。htmlをキャッシュする事も考えましたが、一番負荷を食ってる処理が、「そろそろ来そうな予約者一覧」なので、ある程度動的生成せざるを得ません。

結局、検索部分をメソッドに分離、メソッドの引数と戻り値をmemcacheに保存するデコレータを書いて、あちこちに挟んでみることにします。

これでfrontendとDatastore Read Operationsが減ってくれればかなり助かります。

2011年11月9日水曜日

Datastore Read Operations

Datastore Readを減らす方法は、順次検討していきます。

筆者の顧客から連絡がありました。
appengineでサービスしてる(イントラ用)サーバが昨日から動いてないと言うのです。

画面にpython のexceptionが漏れてたので、それをコピペしてくれてました。
ナニナニ?

 File "/base/python_runtime/python_lib/versions/1/google/appengine/api/datastore.py", line 1700, in Count batch = self.GetBatcher(config=config).next() File "/base/python_runtime/python_lib/versions/1/google/appengine/datastore/datastore_query.py", line 2525, in next return self.next_batch(self.AT_LEAST_ONE) File "/base/python_runtime/python_lib/versions/1/google/appengine/datastore/datastore_query.py", line 2562, in next_batch batch = self.__next_batch.get_result() File "/base/python_runtime/python_lib/versions/1/google/appengine/api/apiproxy_stub_map.py", line 592, in get_result return self.__get_result_hook(self) File "/base/python_runtime/python_lib/versions/1/google/appengine/datastore/datastore_query.py", line 2317, in __query_result_hook self._conn.check_rpc_success(rpc) File "/base/python_runtime/python_lib/versions/1/google/appengine/datastore/datastore_rpc.py", line 1182, in check_rpc_success rpc.check_success() File "/base/python_runtime/python_lib/versions/1/google/appengine/api/apiproxy_stub_map.py", line 558, in check_success self.__rpc.CheckSuccess() File "/base/python_runtime/python_lib/versions/1/google/appengine/api/apiproxy_rpc.py", line 133, in CheckSuccess raise self.exceptionOverQuotaError: The API call datastore_v3.RunQuery() required more quota than is available

QverQuotaErrorですね。アレ今までこんなこと無かったのに。
Dashboardを見ると、StorageのDatastore Read OperationsがLimitedになっちゃってました。0.05 of 0.05 Million Ops。ミリオンオプス???

ちゃんと調べてみると、9月からアナウンスは出てたみたいですね。

appengine.google.comのbiling historyで、「課金体系が変わったら、この位の金額になるよ」的な表示もあったみたいですね。全然気づきませんでした。完全に出遅れてます。



あと13時間でリセットします。って話でしたが、日本時間14時ぐらい?まで使えないのはヤバイので、仕方なく課金設定しました。それにしても0.05 Milion Opsってそんなに簡単に行っちゃうもんなのか?

ちょっと計算してみると、50000 Ops/日 アレ意外と少ない??1分辺り、34Ops。これは油断してると喰らいそうだな。

一応、本サービスで使ってるappspotなので、止まっちゃいましたでは済みません。しかたないので課金することにしました。

Datastore Readを減らす方法は、順次検討していきます。

2010年10月26日火曜日

app engine 新機能色々

筆者はGoogle app engineを非仕事で常用していますが、
オフィシャルブログ追っかけはやってないので、
結構出遅れます。

一つは remote_shell_api
もう一つは datastore_admin

remote_shell_api

データストアの中身を、直接CSV形式でダウンロードできたりとか、
app.yamlに書いて損無しのremote_apiですが、

- url: /remote_api  script: $PYTHON_LIB/google/appengine/ext/remote_api/handler.p
  login: admin

恐らくその全機能をコマンドラインで試行錯誤しながら叩けるという
刺激的なツールです。

+ python2.5 ../google_appengine/remote_api_shell.py アプリケーション名
No handlers could be found for logger "google.appengine.tools.appengine_rpc"
Email: ########Password: App Engine remote_api shellPython 2.5.4 (r254:67916, Jan 20 2010, 21:44:03)
[GCC 4.4.1]The db, users, urlfetch, and memcache modules are imported.
アプリケーション名>

メッセージがチラっと出てる限り、

  • memcache
  • データストア
  • グーグル認証

等々は使えるようです。
まあデータストアだけでも、ご飯3杯。

直ぐに思いつくのは、データストアに対する、ややこしい操作。
datastore viewで1個づつ書き換えるにはどうよ?という操作。
これをスクリプトで一括処理しちまおう。というのは誰でも考えると思います。
しかしスクリプト書いてデプロイ、を繰り返すのはかなり面倒です。

アプリケーション名> class sitedata(db.Model):...
 pass...
アプリケーション名> sitedata.all().count()
16
アプリケーション名> 

こんな感じで、(感覚的には)直接クラウドの「あっち側」をイジれます。
実際には、remote_apiが、20レコード単位っぽい感じで送受信してるので、
スピードは早くはありません。

筆者はこれで、念願の、データストア一括削除ができました。

しかし、流石のグーグル。もっと良い方法があったという。

Datastore Admin

builtins:
- datastore_admin: on

これを書いておくと、datastore adminのメニューから、
「一括削除機能」が使えます。
しかも内部で、Map/Reduceを使って削除するらしい。

データストアに、

  • _AE_MR_MapreduceState
  • _AE_MR_ShardState

が増えたり
MainのLogsに

  • /_ah/mapreduce/worker_callbak
  • /_ah/mapreduce/controller_callbak

がドンドコ増えたりとか
Map/Reduceの一端が垣間見える体験です。

2010年5月6日木曜日

app engine SDK では110過ぎの人の誕生日が扱えない?

app engineが、という、pythonのlinux版は、
datetime型は、1900より過去をサポートしません。

1899年生まれの人の誕生日を、strftimeとかすると、ValueErrorを喰らいます。

また悩ましいのが、strftimeの制限なので、
datetime自体は、1899以前を入れようがコンストラクト出来るのです。

例えば、datastoreに誕生日が入っていて、

SDKの _ah/admin/datastore でdatastoreを眺めようとすると落ちます。
うーん。

検索してて気づいたのですが、1900年って、昔懐かしい2000年問題の一部ですね。
http://ja.wikipedia.org/wiki/2038%E5%B9%B4%E5%95%8F%E9%A1%8C

strftimeの動作は、プラットフォーム依存らしいので、
http://www.python.jp/doc/2.5/lib/strftime-behavior.html#strftime-behavior
SDK的はどうにもならない模様。
と言うか、appspot.comでは、逆に1899年以前でも通ります。
本当に実装依存っぽい。

strftimeの内部で、これくらいやっちゃって欲しい。とも思う。

仕方ないので、パッチを当てるしかなさそう。


ネタが細かすぎて、パッチファイルを無くしそうなので、gistに貼りました。


2010年4月26日月曜日

app engine で、大量のデータを、あっと言う間に、datastoreに入れる方法

ググる限りは、言及しているページが非常に少ないので、
「知る人ぞ知る」化してるっぽいので、書いておきます。

google.appengine.ext.db.Model.put()
google.appengine.ext.db.Model.delete()

datastoreのレコードを更新するときには、
db.Modelのput/deleteを使う場合がほとんどだと思いますが、
これって遅いですよね?

datastoreとの通信は、xml-rpcっぽいので、
ほとんどはプロトコルのオーバーヘッドだと思います。
たとすれば、通信回数を減らせば良い?

そうです。一括書き込み方法があります。
って言うか、ドキュメントを熟読すれば書いてある話なんだけど。

「一つ以上の」って書いてあります。
ハイ。もう判りましたね。

db.Modelをその場でputしないで、
  • list.appendしておく。
  • まとめて、db.put(list) する。

これだけで劇的に速くなります。
もう劇的です。500レコードが2秒で入ります。

「な!」と言っちゃうぐらいです。

ただしこの場合だと、db.Model.putは通らないので、
独自にputをオーバーライドしてる場合だと、
都合が悪いことがあります。

ちなみに筆者は、まったくの別件の研究で、
SDKのソースを眺めていて、本件を発見しました。

2010年4月21日水曜日

appengineで、なんかWarning出た

何気なくログ眺めてたら、

This request caused a new process to be started for your application, and thus caused your application code to be loaded for the first time. This request may thus take longer and use more CPU than a typical request for your application.

こんなWarningが出てました。
最近流行りの、スピンアップ問題について。だとは思いますが。

意訳すると
「毎回プロセスを生成してるので、余計な時間が掛かるかも知れません」

知ってるよ!

494msの奴には出てない。
567msの奴は出てる。

500ms以上で、とかそんな感じでしょうか?

オフィシャルブログには何か書いてあるっぽいですが、
とにかくトートツなので、地球上で混乱しているようです。

Very helpful and useful in many ways (code optimization etc.)
Oh ! just a short commend : could it be a little less verbose ? thus not waisting so much valuable space in logs database etc ?

えええ?やっちゃってからアンケート??
有料Quotaもやってるのに、labs発想はどうかと思う。

そうね。「長すぎ」
何時もの様にURL貼るんでよかったんじゃね?

って言うか、その前に、出力条件を言え。と思います。
そして、500msをしきい値にしてるとしたら、「短すぎ」




2010年4月20日火曜日

appengineの制限は、グーグルにとっても制限

この記事の内容は既に古く、有料に限り(無料分はありますが、どうせ週$2取られるので)、専用インスタンスを無限に動かせるようになってます。
https://developers.google.com/appengine/docs/python/backends/overview?hl=ja

ただし、小生のスタンスは変わってないので、この記事自体は据え置きます。

基本的には、「30秒も要らねえよ」ってスタンスなので、解決方法は書いてません。それを探しに来たかたは悪しからず。

http://code.google.com/intl/ja/appengine/docs/roadmap.html
appengineのロードマップ的には、taskqueueやcronに限り、30秒ルールを撤廃する可能性があるらしいのですが。筆者はあまり困ってません。「悩まされてるデベロッパー」ってJavaで書いているのんじゃないでしょうか?

筆者はJavaは遅い、と思ってます。JSPの、「あー今コンパイルしてるな」なタメ時間もあり得ません。スピンアップ時間の無駄使い。

「スピンアップ終わったら、速いんだよ」とか言わない事を祈ります。そりゃあ当たり前というか。全部遅かったら目も当てられない。多分アナタも使わないでしょう。

ちなみにpythonの「スピンアップ」は2秒ぐらいっぽい。速いと見るか遅いと見るか。

もしくは、Slim3というフレームワークが速いらしいので
使ってみたらどうかと思います。ひょっとしてそれで済む話かもしれません。

そもそも、appengine は、社内で使ってるクラウドの一部を切り売りしているだけ。の筈。グーグルでも30秒ルールに従ってるのです。

datastoreの実装も、「あーこれならGmail作れるな」というものばかり。ラベルは、StringListProperty使ってるんだろうな。とか。

フツーのRDBMだったらリレーション使うところはReferencePropertyで、かなりやっていけます。またはModelクラスのメソッド実装で引っ張ってくるとかね。発想の転換が大事です。

1回のトランザクションで、データを1000個しか取り出せないのもグーグルにとっても同じです。Gmailや、Readerの件数表示が、1000以上は表示できないでしょう?件数も詳細を出さないで、800件ぐらい、とかサボってます。

と言うわけで、30秒撤廃は、グーグル内部のサーバ運営の根幹に関わるのでそうそう簡単では無いでしょう。想像ですが。

まあグーグル自身がやる、って言ってるんで可能性は0ではありませんが。まあ有料Quotaでしょう。

同じく、MapReduceをサポートするかもしれない!とか喜んでいる人が多いですが、何をするつもりなんでしょう?
#db.Model.count()が遅いから。じゃないですよね。

っていうか、
Support for mapping operations across datasets
って書いてあるんだけど、これってMapReduceなの?
違うんじゃね?

仮に使えるようになったとしても、無料はあり得ない。端的に言えば、MapReduce Quotaという項目が増えます。

30秒ルールとは別の意味で、
想定以上のリソースを食いつぶされる可能性がありますからね。

2010年4月16日金曜日

appengineでMapReduce。は無料の間は多分無理

グーグルといえば、appengine。
appengineといえばクラウド。
クラウドといえばMapReduce。

などという、変な3段論法があり、
appengineで頑張ってMapReduce使うぜー、
みたいな風潮がありますが。

正直、判ってねえなあ、としか思えません。
いや承知でやってるなら本人の勝手だけど。

グーグル内部のリソースを消費してもらっちゃ困る訳です。
そうならないような絶妙のサジ加減が、Quotaなのでしょう。
逆に、無料なのは、「勘弁できる負荷」だからでしょうよ。

HTTPで外部を叩くのは多分ありえません。
2秒のタイムアウトがあるので。
しかもこれを撤廃することは無いでしょう

appengineでは、taskqueue経由で、
バックグラウンドプロセスを幾つか動かせますが、
そもそもtaskqueueは「すぐ動く」ことを保証してない上に、
実行した後も、CPUタイム制限があります。DeadlineExceedですね。
実行時間の累積にも制限があります。

Mapはtaskqueueでいいでしょうけど、
Reduceは(taskqueue頼みじゃあ)、何時戻ってくるか判らんでしょう。

Reduceが3秒ぐらいで戻ってくる話なら、タスク1個で良くね?

分散しなくて処理できる分量を、わざわざ分散して、
何が楽しいんだ?的な。

仕事を増やす仕事に絶望した!

サイエンスとしては面白いでしょう。
無料Quotaの範囲内で、ある程度の実装は可能でしょう。
それで、もの凄い処理を動かせるか?っていったら困難。

「可能」と「実用」は違うだろ、って話ね。

筆者は気にしてなかったんですが、
アマゾンでもMapReduceが有るらしいんで、
どうしてもやりたければ、そっちでいいんじゃね?と思う。
http://aws.amazon.com/elasticmapreduce/

2010年4月10日土曜日

appengineの真骨頂は、pythonにあり

日本の、エンタープライズ界隈の方々は強情で、
app engineのdatastoreを難解だと感じている様です。+

JavaのJVMによる、他言語実装、例えばrubyもあり、
http://jruby.org/
app engineでrubyを使う人も居るには居るらしい。
http://code.google.com/p/appengine-jruby/

RDBのJava実装がありまして、
OpenOfficeのBaseでも内蔵してる代物なんですが、
http://hsqldb.org/

これをdatastoreのミドルウエアとして使った人も居ます。
http://www.littlesoft.jp/sql4g/

確かに、RDBMを使えれば、リレーション使いまくりですが、
そもそもJavaは、「固い」言語なので、datastoreの柔軟さが活かせません。

って言うか、そこまでpython使いたくないですか?と聞きたい。

pythonのwsgirefとか、webappは、JavaのServletに近い考え方ですね。
どっちが先だか私は知りません。
しかし、app engineの真骨頂はdatastoreにあります。

RDBに、GUIツールが存在するのは、「管理が面倒臭い」の裏返しです。
Java自身のためのEclipseが存在するのと同義です。

しかし、datastoreのORマッピングなら、ソースを修正するだけです。
pythonなら多重継承すらできます。

いやもう、SQLなんか書いてられませんよ。面倒で。

JavaのJDOとやらからでも、比較的簡潔な記述が書けますが、
http://code.google.com/intl/ja/appengine/docs/java/datastore/dataclasses.html

pythonのそれとは簡潔さが比較になりません。
http://code.google.com/intl/ja/appengine/docs/python/datastore/entitiesandmodels.html

記述量は、5倍以上ですね。
筆者は(python版の切り口に対して)「え?これだけでいいの?」と素直に感動しました。

pythonのアレを強引にJavaで例えるなら、
classのstatic変数の初期化で、カラム名&型の定義をしています。
しかもnewすると、同名の変数が、データカラムとして使えるという。
Javaでそんな記述は不可能です。pythonだからこそ可能です。

しかしこれはpython djangoのORマッピング機能上に実装したものらしいので、
http://docs.djangoproject.com/en/dev/ref/models/instances/
python djangoが、もともとイカしていたといった方が良いでしょう。

datastoreが難解なわけじゃなくて、
JDOのアノーテーションが気持ち悪いのです。
見比べでつくづく思いました。