uehaj's blog

Grな日々 - GroovyとかGrailsとかElmとかRustとかHaskellとかReactとかFregeとかJavaとか -

GAE上でスケールするWebアプリを書くには/サイオステクノロジー松尾さん

本エントリは、エントリ「JJUG CCCいってきました」の一つです。セッションのメモ書きです。もとの発表資料: A-3-1.pdf, A-3-2.pdf

スケールするために

  • 無駄な繰り返しを避ける
    • 繰り返されるクエリ結果はmemcacheでキャッシュする(読み込みデータのための)
  • 大きなリザルトセットは避ける
    • メモリ上で大量のデータのソートやフィルタはしない。小さくとって、小さく処理。

チューニングのために知っておく方がいい数字

  • 書き込みはコスト高い。ほんとの最低でも1ms。データ量に応じさらに悪化。
  • 読み込みは速い。25micro second。1秒に4GBのスループット

EntityとKind

  • 実体は「分散ソートアレイ」と呼ばれるもの。多数のマシン上で実行。
  • EntityはKeyとvalueをもつ。
    • valueは、プロパティのキー+バリューをずらりとシリアライズして突っ込んでいるだけ(たぶん)。検索はindex経由で(indexが張れるのはblob, text以外のデータ型)。
    • keyは(1)Kindのクラス名+ID、(2)文字列型のいずれか。後から変更不可。500バイト制限がある。
  • 関連はRelationプロパティで表現
    • OneToMany, ManyToMany可
    • 癖がある。単純なリレーションではない。

EntityGroup

  • 親子関係
  • 書き込みに関してEntity Group単位で排他制御される。
  • 書き込み排他の実現方法はロック(+解除されるまで待つ)ではなく楽観ロック+自動リトライで実現(root Entiyに最終更新時刻を記録し、書き込み前に取得した値から変化していれば自動リトライ)。コード上は意識しなくていいが、競合が頻発すると遅くなるorタイムアウトを引き起こす。

EntityGroupの落とし穴

  • 大きく作ると遅くなる(EntityGroupに含まれるデータ量が多いと同時アクセスが生じる確率が高まり遅延の確率が高まる)
  • データの利用パターンに合わせて小さくする。
  • Entity Groupをまたがったクエリはロックされない。 (疑問:Entity Groupをまたがるということはクエリ対象が別マシンにまたがる可能性もある?分散クエリになって遅くなる可能性もある?)

カウンタを作ってみよう

  • Memcacheは駄目。1000件しかクエリできない。
  • Entityを使う。しかし頻繁にupdateされると遅い。
    • →「分散カウンタ」。同じEntityGroupに所属しないn個のカウンタを作って、インクリメントする際にはランダムにn個のうち1個を選んで増加。カウント値を得るときにクエリして合計する。

ブログを作ってみよう

  • エントリに関して
    • ページネーションは難しい。EntityのKeyのIDは重複はないが番号が飛ぶ(稠密ではない)のでページングには不適切。
    • エントリをブログ全体の子供にして、ブログに番号を持たせる。
      • → 記事の投稿は頻繁ではないのでOK。
  • コメントに関して
    • エントリと同じ方式だと、炎上したときなどに大量コメントの登録更新が遅延して困る。
    • 「時刻+ユーザ名+コメントID」をキーとしてソートする。コメントIDのカウンタをユーザの子にしてGroup化する。
      • → 同じユーザが頻繁には投稿できないのでOK。

GAEのPython版とJava版の違い。

  • Pythonの方が優れているところ
    • 一年前からやってるから機能的に多い。
      • ランチャがある(MacOS用のみ)
      • ローカル環境の(秘密のURLで見れる)admin画面/APIがある
      • Remote API/一括アップロードAPIがあって、速い。
    • 動的言語の利点として
      • Expandoで動的プロパティ追加サポート。
      • PolymorphicQuery可(親クラスに対してクエリすると子クラスもとれる)
    • 記述量小。
    • 起動速度(ワームアップ)速い
  • Javaの方が優れているところ
    • Embededクラス(インクルード)
    • OwnedRelationを設定するとEntity Groupが設定。親を消すとカスケーディング自動削除(JDOレイヤで実装されているので、低レベルAPIでは対応しない。またadmin画面でも対応しない)
    • 実行速度速い
    • Python版には「トランザクション内ではクエリ不可」という制限があるのでキー取得を外でやる必要があるが、Java版ではJDOで隠蔽されている。
 [感想] 本編もPython系との比較編も大変に面白かった。
       GAEならではの難しさはある、という話だが、
       聞いた限り手に負えそうな感じ(根拠なし)。
       ただ確かに、RDMSチューニングの話で感じるときのある
       「バッドノウハウの集積体/集合体/集大成的感覚」
       に比べて、プログラミング的に
       知的で健康的で面白い、やりたい〜という
       気になる。