マシン性能に異常が見られないパフォーマンス問題(Java製Webアプリ+MySQL)
Java製Webアプリ+MySQL上で発生したパフォーマンス問題についてです。
スレッドダンプの解析には下記を使用しました。
MySQLのJDBCドライバ設定は下記を参考にしました。
負荷分散を行うシステム構成で、APサーバが2台の場合、性能に問題なし。APサーバが1台の場合、性能が悪化するという問題が起こりました。ただし、CPU使用率は限界に達していない。JVMのメモリ量は余裕がある。NW帯域は問題なしという状態。
結論からいうと、DBのコネクションプールの処理でスレッドに対して同期処理を行っていて、多くのスレッドで待ちが発生していたためでした。
単純にスレッドが待っている状態なので、CPUもメモリも問題ないわけです。
この問題にどのように対応したかについての記録です。
1.スレッドダンプを取りました。
2.JDBCドライバの設定をいじり、性能が向上することを確認しました。
スレッドダンプを取る
JDK標準で用意されているjstackコマンドを使用しました。
jstack プロセスID |
スレッドダンプの解析には下記を使用しました。
侍を使うと同期待ちを行っているスレッドがひと目でわかります。また、スタックトレースからDBのコネクションプールを行っている処理で多くのスレッドが同期待ちしていました。
JDBCドライバの設定
JDBCドライバの設定
スレッドダンプを取り、多くのスレッドが同期待ちを起こしていることは確認できました。しかし、それが性能悪化の原因であるかは性能を改善させることで証明するしかありません。
アプリケーションとDBとのやりとりを速めることができれば、各スレッドの処理を速くすることができるので、性能を改善することができると判断しました。
色々調べてみると、DB提供元から用意されているJDBCドライバにパフォーマンスに関わる設定が存在することを知りました。
トランザクション分離レベルの設定を毎回行わない。autocommitの命令を排除するということを行いました。
プロパティ名 | デフォルト値 | 設定値 |
alwaysSendSetIsolation | true | false |
elideSetAutoCommits | false | true |
MySQLのJDBCドライバ設定は下記を参考にしました。
上記設定を行うことで、APサーバ1台でもAPサーバ2台と同等の性能を発揮することができました。
所感
今回の調査をするにあたり、スレッドダンプを取るということを始めて行いました。意外に簡単に取得できるものだということを実感しました。また、スレッドダンプを取ることが原因を突き止めるきっかけにもなったので、今後はスレッドダンプを取るということも初期段階の調査に加えるべきと感じました。
Spring MVC + MirageSQL 環境構築とサンプルづくり
仕事でSeasar2を主に使用してきましたが、Seasar2コミュニティの衰退から今後Seasar2を使っていくのは難しいと判断しました。Seasar2に変わるフレームワークを模索する必要があるなと。
2WaySQLを前提に考えた場合に対象になったライブラリがMirage-SQLです。
GitHub - mirage-sql/mirage: The SQL Centric Database Access Library for Java
ここでは、Spring MVC + MirageSQLという構成で検証してみます。データベースからデータを取得し、画面に表示するという単純なサンプルを作成します。
なお、筆者はSpring framework自体使うのが始めてなので、間違いがあるかもしれません。
Spring MVCのプロジェクトを作成します。
以下を参考に作成しました。非常に分かりやすくまとめられています。
mavenへの依存ライブラリ定義追加
ポイントとしてはspring-jdbcを追加することです。詳細は後ほど。
jstlは画面表示のために使いたかっただけなので、本質的には不要です。
Springのトランザクション管理を使用する必要が有るため、<tx:annotation-driven />が必要です。
以下は、MirageSQL向けの設定内容です。データベースへの設定は適宜変更して下さい。
本内容では、MySQLを使用しています。
Controllerクラス
@RequestMapiingアノテーションによって、「/users」というURLからusersメソッドを実行するという設定が行われています。
データベースから取得した値をViewに渡すためにModelクラスを介する必要があります。
データベースへの問い合わせを行う処理はServiceクラスに持つことにしています。
Serviceクラス
データベースへの問い合わせを行う処理をしています。MirageSQLが関係する部分です。
SqlManagerクラスがMirageSQLで用意されているクラスです。このクラスを介して、データベースへの問い合わせを行うことが可能です。
「dispatcher-servlet.xml」に記述した設定によって、SqlManagerをDIすることが可能になっています。@AutowiredアノテーションでSqlManagerを利用することが可能です。
@Transactionalアノテーションを指定することで、指定されたメソッドの単位でトランザクション管理がなされます。SqlManagerクラスを使用するためにはトランザクション管理内である必要があります。
View(JSP)
データベースから取得したデータをそのまま一覧表示しています。
補足
・SQLファイル
・テーブル構造
テーブル名 users
カラム名 | 型 | 属性 |
username | VARCHAR(32) | 主キー |
mailaddress | VARCHAR(30) |
所感
簡単なサンプルですが、Seasar2と遜色ない形で作れるフレームワークだと思います。DBへの問い合わせ部分についてはS2JDBCの2WaySQLの考え方を踏襲しているようなので、ほぼ違和感なく使えそうです。今回のサンプルを作るにあたってはむしろSpringの部分で苦労しました。
値を画面に渡すやり方がしばらくわかりませんでした。。。
Springも使いこなせれば、楽に書けそうな気がします。基本から勉強してみたいと思います。
今回のサンプルはGitHub上に挙げています。
参考