マニアックすぎる話ですが(^^;)
ひとことで言うと、「これまでは、リクエスト処理時間が長めで、同時接続数が非常に多いサービスをJavaで作る場合はマニアックな方法を使うか、我慢して高いHWコストを払わなければいけなかったが、これからはプログラマが親しんだJavaEEを使ってHW効率のいい実装ができるようになった」ということになります。
じゃぁ「リクエスト処理時間が長めで、同時接続数が非常に多い」って具体的にどんな基準よって話なのですが、僕の超独断と偏見に基づく、超ざっくりな基準はコレです:
- ビジネスロジック(コンテナからリクエストを受け取ってから、レスポンスをコンテナに渡すまで)部の実行時間が、3-5秒以上
- 実行時間が長くなる原因が、ビジネスロジック内で行うIO(ディスク・ネットワーク)
- ピーク同時接続数が500-1000以上
一応経験に基づいた値ではありますが、当然こんな画一的な基準を提示するのは無謀と言ってもいいくらいなので、ご了承お願いいたします(^^;) さらに、新しいアプリか既存アプリかによって次のようなことを考える必要があります:
- 新しいアプリの場合
- そもそもそういうリクエスト処理時間・同時接続数になるのは適切なのか?
- 本当に、従来の方式で実装したら問題が出ると予測されるか?
- そもそも同期のインターフェースにすることは適切?メッセージキューなどの非同期型インターフェースの方が適切だということはないか?
- 使えなくなってしまうフレームワークなどが出るが、それを補う案はあるか?
- JavaEEとはいえ、従来のプログラミングモデルとはかなり違ってしまうが、それにうまく適応できそうなチームか?
- 枯れた技術から新しい技術へ移行する以上、安定性などの面でリスクがあるが、それを凌ぐメリットがあるか?
- 既存アプリの場合
- 症状の原因は、本当にこの特定の並行性能問題か?
- Connection RefusedやRead timeout、異常に処理時間が長いなどの問題がクライアント側で確かに出ていて、サーバ側の問題に間違いない
- 負荷バランサのせいだったりすることも。。
- 異常ではない
- 外部のWebサービスなど外部のサービスに異常が生じて、異常にリクエスト処理時間が長くなっていることも
インフラの異常ではない?サーバ仮想化を使っている場合、仮想マシンを上げすぎて性能が極端に低下しているなどということはないか?(実話(^^;)ネットワーク・DB・ストレージは?他のプロセスがサーバのリソースを圧迫していないか?
バグではない?クライアント側が異常にリクエストを繰り返しているということはないか?サーバ側のバグで余計な処理をしていたり、DB処理が無駄に長く掛かっていることはないか?メモリリークではないか?など
- ビジネスロジック部の実行時間が確かに長い
- コンテナによっては統計を出してくれるかも。プロファイラでスレッドの状況を見るのが一番良いでしょう。
- 「ビジネスロジック部は短いが同時接続数が非常に多い」というシチュエーションなら、NIOコネクタの使用で解決される可能性も。最近のメジャーなコンテナならまず使えるはず
- 単にコンテナの設定が悪いわけではない
- ドキュメントを参考にチューニングしても症状が持続するかチェックする。実は誰かがデフォルトの設定に余計なことをして問題が起きていることも往々にしてある
- スレッドリソースが確かにビジネスロジック部で浪費されている。具体的には、多くのWorkerスレッドがビジネスロジック内で待ち状態か?
- たくさんのWorkerスレッドが実行可能状態の場合は、コンテキストスイッチスラッシングが起きている可能性があり、むしろmax-threadsを下げると解決する可能性も
- これもコンテナによっては統計を出してくれるかもしれませんが、僕はスレッドダンプを打ち出して集計してます(^^;)
- 設計やデータ量・処理量などから考えて、多くのWorkerスレッドが待ち状態におかれるということが確かにありそうなことか?
- Connection RefusedやRead timeout、異常に処理時間が長いなどの問題がクライアント側で確かに出ていて、サーバ側の問題に間違いない
- 以下の選択肢を全て検討したが、ざっくりとした改造コストとテンビンにかけても、なお改造の方が良い可能性がある
- もっといいハードウェアを買う
- 最も容易だが、金がかかる上すぐに限界が訪れやすい
- HWを足して、負荷バランスする
- まともな高可用性を備えたアプリなら簡単にできるはずだが、コストパフォーマンスがかなり悪くなる場合も。サーバは当然のことながら、負荷バランサでもコストがかかることがある
- 他のところやビジネスロジックで最適化などを行い、Workerスレッドが待ちになる時間・リクエスト処理時間を減らす
- どのくらい「贅肉」があるかによる。基本的に、アプリ・外部サービスが新しかったり、今回ほどの性能要件でテストされたことがなかったり、担当したチームの能力が低かった場合などは、「必要なインデックスが張られていない」などの「削ぎやすい贅肉」が見つかる可能性が高い。そうでない場合は効果の予測が困難
- もっといいハードウェアを買う
- 「新しいアプリ」編のチェック項目全て
- 症状の原因は、本当にこの特定の並行性能問題か?
ここまで検討しても、なお「非同期処理」がベストの選択肢であると考えられるなら、真剣に検討してみる価値がありそうです。次回は、実際にServlet 3.0でのWebサービスを作ってみます(あくまで予定ですが(^^;))