Pattern for Offline Concurrency Control
- 並列性の問題は、可能な限りトランザクションシステムに委ねよ
-
複数のシステムトランザクションをまたぐような並列制御を自前で行うのは、ほの暗い水の底に自らを沈めるようなもの
- おっかないサメやクラゲやピラニア等がいっぱい
- ビジネストランザクションとシステムトランザクションとのミスマッチにより、やむを得ないこともある
- そういうときのためのパターンを以下に提示する
-
使わずに済むならそれに越したことはない!
- ビジネストランザクションが1リクエスト、1システムトランザクションに収まるなら、そうせよ
- スケーラビリティを犠牲にしてlong transactionを許容できるなら、そうせよ
- これから紹介するパターンは、上記のいずれも不可能な場合にやむを得ず使用するもの
- 並列性はやっかい
- 下記のパターンは開始点にすぎない。終着点ではないし特効薬でもない
Optimistic Offline Lock
-
まずこれを検討せよ
- 実装が楽
- liveness高い
-
制限
-
失敗する場合、ビジネストランザクションのcommitを試みるまでわからない
- 遅すぎて困るケースがある
- ユーザの信頼失墜
-
Pessimistic Offline Lock
- 失敗が早くわかる
- liveness低い
Coarse-Grained Lock
- 並列性をオブジェクトのグループとして扱う
Implicit Lock
-
ロックをプログラマに明示的に行わせない
-
抜け漏れによる不具合を防ぐ
- 見つけづらい不具合
-
選定
-
並列性について、純粋に技術的な決定事項だという共通認識がある
- 要件定義確定後に行うもの
- 否
-
UXに密接に関わる
- Optimistic
- Pessimistic
- Pessimistic Offline Lockを採用するなら、ドメインについての聞き込みが重要
- Coarse-Grained Lockも同様にドメイン知識が必要
困難
- 並列性絡みの不具合は再現が困難
- 詳しい人の助けを仰げ
- Further Readingに文献をしるす
Application Server Concurrency
- ここまで: 共通データに対して、並列した複数セッションの話
- ここから: アプリケーションサーバ(apacheとか)自体の並列性の話
- トランザクションとかは関係なくなる
-
マルチスレッドプログラミング
-
ロックと同期ブロックを明示的に書くやつ
- 大変
-
容易に不具合が入る
- 見つけづらい
-
再現困難
- 99%は元気に動いてしまう、とか
- 明示的にやるのは可能な限りやめよう
-
-
分類
- process-per-session
- process-per-request
- thread-per-request
-
process-per-session
- プロセスは独立したメモリを割り当てられるので安心
-
process-per-request
-
process-per-sessionよりも高効率
- メモリ的に
- セッション(含ビジネスロジック)よりも粒度の細かい、リクエストにプロセスを対応付ける
- プロセスは複数のセッションからのリクエストを処理できる
-
プロセスをプールすることで、少ないプロセスで多くのセッションをさばける
- 【補】GoFのComposite Pattern / Flyweight Pattern における葉ノードみたいな気持ち
- プロセスは、リクエストを処理するにあたり獲得したリソースを適切に解放すること
- スケーラビリティ高い
- 例: Apache mod-perl
-
-
thread-per-request
- もっと高効率
- プロセスと異なりスレッド間でリソースは分離されない
-
どれ使う
-
process-per-request
- thread-per-requestほど効率はよくない
- が、同様のスケーラビリティ
-
高い堅牢性
- 何かしくじってもプロセス内で収まる
-
経験の浅いチームではこれを選ぶと良い
- マルチスレッドに苦しまないですむ
- 不具合修正コストや人件費が浮く
- ハードウェアにコストをかけられる
- thread-per-requestとprocess-per-requestとでちゃんとパフォーマンス比較する人はまずいない
-
-
スレッド固有フィールドをサポートする環境の存在
-
COM
- single-threaded apartment
-
J2EE
- Enterprise Java Beans
-
-
thread-per-requestを採用する場合は、マルチスレッド問題を無視できる領域を分離せよ
-
スレッドがリクエストの処理を開始したら、スレッドにオブジェクトを作らせて、他のスレッドから見えないところにおく
- staticとかは駄目
-
-
オブジェクトの生成は高コストなのでは?大丈夫?
- 仮想マシンやメモリ管理戦略依存
- 今日日のマシンでは速い
- 並列処理のバグの多くを回避できる
- staticメンバやグローバル変数を避けろ
- singletonも同じ理由で避けろ
-
グローバルメモリが必要ならRegistryを使え
- a well-knowy object that other objects can use to find common objects and services
- Registry自体はグローバルオブジェクト
- static変数っぽく使えるけどthread-specificな領域
-
例外: 生成するのがすごく高コストなオブジェクト
-
例: DBコネクション
- プールする
-