山下寛人オフィシャルブログ

オイシックス株式会社 執行役員 システム本部長 山下寛人の公式ブログです。

サーバーサイドJavaでHibernateを使ったらクラスタ構成必須

いろいろ考えた結果このような結論に至りました。

オイシックスではECサイト以外の社内システムなどもJava webアプリケーションなのですが、たまにメモリが爆発的に使われてアプリケーションが動かなくなることがあります。なぜそうなるかというと大量にDBからデータを読み込んでしまうからです。

ではなぜ大量にDBから読み込んでしまうのか。例えば検索条件をユーザーが指定して検索する画面で何も条件を指定せず検索して、全データフェッチになってしまう。データ量がだんだん増えて多くなってしまう、などいくつかパターンがあります。いずれにしてもクエリの実行前に件数をカウントして一定以上だったらエラーにするとか、scrollableを指定して実行するといった方法で対処できます。Hibernateでなく素のJDBC ResultSetを使うという手もあります。その後Listなどにデータを格納したら同じことになりますが。

一方これを未然に防止しようとするとなかなか難しいものがあります。こういうルールを100%徹底させることが難しいです。またテスト環境では本番よりデータのレコード数が少ないのでテストでは問題が顕在化しないということもあります。本番でもだんだんデータが増えたり何かの事情で突然データが増えることもあります。

プログラマがミスしたり予期しないことが起こってもシステム全体を止めないようにしたい。このケースだとあるスレッドが一定以上のメモリを使ったらそのスレッドを強制的に止めてしまえばよいです。PHPではそういうことができた気がします。しかし!どうやらJavaではそういうことはできなさそうです。

そうなるとスレッド単位でなくクラスタ構成にしてJVM単位でやるしかありません。メモリ不足でレスポンスが返らなくなったらロードバランサーから切り離します。手動で止まったJVMを再起動するか、自動で再起動してもいいかもしれません。

やればできますしコストもすごくかかるわけではないですが、もうちょっとスマートなやり方はないもんですかね。