Spring Boot 1.3.x の Web アプリを 1.4.x へバージョンアップする ( その22 )( application.properties に記述する `spring.datasource.tomcat.~` の設定を見直す )
概要
記事一覧はこちらです。
Spring Boot 1.3.x の Web アプリを 1.4.x へバージョンアップする ( その21 )( Log4jdbc Spring Boot Starter を入れてみる ) の続きです。
- 今回の手順で確認できるのは以下の内容です。
参照したサイト・書籍
The Tomcat JDBC Connection Pool
https://tomcat.apache.org/tomcat-8.5-doc/jdbc-pool.htmlTomcat JDBC Connection Poolの存在を忘れてました
http://qiita.com/uzresk/items/d9e1b46014809094b10dTomcat JDBC Connection Pool configuration for production and development
http://www.codingpedia.org/ama/tomcat-jdbc-connection-pool-configuration-for-production-and-development/Commons DBCPを超えるTomcat JDBC Poolとは
http://www.atmarkit.co.jp/ait/articles/1111/07/news212.html
目次
- jconsole で Tomcat JDBC Connection Pool の状況を確認する
- initialSize, maxActive, maxIdle, minIdle
- testOnBorrow, validationQuery, validationQueryTimeout
- removeAbandoned, removeAbandonedTimeout
- ここまでの設定が反映されているか jconsole で確認する
- SlowQueryReport を使用してスロークエリーをログに出力する
- 次回は。。。
手順
jconsole で Tomcat JDBC Connection Pool の状況を確認する
今の設定での Tomcat JDBC Connection Pool の他の設定項目の値を確認するために jconsole で MBean の値を見ようとしたのですが、以外に時間がかかりました。結論としては、
- application.properties に設定する
spring.datasource.jmx-enabled
はデフォルト値が false なので true にする必要があります。またこの設定はspring.datasource.tomcat.jmx-enabled
という名前にしてはいけません。IntelliJ IDEA で補完表示されるのですが設定しても全く意味がありません。 - Log4jdbc Spring Boot Starter の AutoConfiguration が有効な場合、Tomcat JDBC Connection Pool の MBean インターフェースが登録されず、jconsole に表示されません。
まず Spring Boot Reference Guide の Appendix A. Common application properties を見ると spring.datasource.jmx-enabled=false
と記述されています。デフォルト値が false なので true にします。
src/main/resources/application.properties に設定を追加します。spring.datasource.~
の設定は spring.datasource.tomcat.~
に変更していたので、最初 spring.datasource.tomcat.jmx-enabled=true
と書きました。IntelliJ IDEA でも以下のように補完表示されます。
しかし、この設定だけ書いた状態では jconsole に Tomcat JDBC Connection Pool らしき情報が表示されません。
コマンドプロンプトを起動後、jconsole コマンドを実行します ( jconsole は C:\Java\jdk1.8.0_121\bin の下にあります )。
ローカル・プロセス一覧から ksbysample-webapp-lending を選択します。
メイン画面が表示されたら「MBeans」タブをクリックし MBean 一覧を表示しますが、画面左側のツリーに Tomcat JDBC Connection Pool らしき情報が表示されません。
MBean インターフェイスを登録している場所を探したら org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration の中の TomcatDataSourceJmxConfiguration#dataSourceMBean でした。以下のようにブレークポイントを設定して IntelliJ IDEA から debug 実行したところ、ブレークポイントで停止しませんでした。。。
TomcatDataSourceJmxConfiguration クラスに付いているアノテーションを見ると @ConditionalOnProperty(prefix = "spring.datasource", name = "jmx-enabled")
と書かれていました。ここで jmx-enabled は spring.datasource.jmx-enabled=true
と記述しないといけないことに気づきます。
src/main/resources/application.properties に記述する設定を spring.datasource.jmx-enabled=true
に変更したのですが、やはり jconsole に表示されません。今度は debug 実行すると上で設定した TomcatDataSourceJmxConfiguration#dataSourceMBean のブレークポイントで止まるのですが、if (dataSource instanceof DataSourceProxy)
の条件を満たしていないのか if 文の中の処理が実行されません。
再度 debug 実行して dataSource がどうなっているのか見てみたところ、DataSourceProxy クラスのインスタンスではなく log4jdbc が提供する DataSourceSpy クラスのインスタンスになっていました。if 文の中の処理が実行されないはずです。
Log4jdbc Spring Boot Starter を無効にするために src/main/resources/application.properties に spring.autoconfigure.exclude=com.integralblue.log4jdbc.spring.Log4jdbcAutoConfiguration
を書いて debug 実行したところ、今度は TomcatDataSourceJmxConfiguration#dataSourceMBean の if 文の中の処理が実行されました。
jconsole にも org.apache.tomcat.jdbc.pool.jmx
という名前で Tomcat JDBC Connection Pool の情報が表示されました。これで現在の設定値が確認できます。
デフォルトの設定が書かれているクラスがどれか確認してみたところ org.apache.tomcat.jdbc.pool.PoolProperties でした。これを探すのに IntelliJ IDEA 2017.1 から新しくなった Find in Path を使いましたが、以前のツリー表示と違い1画面内でヒットしたソースが確認できてレスポンスもよく、使い勝手が非常に良くなっています。
initialSize, maxActive, maxIdle, minIdle
DB とのコネクション数を設定します。以下の方針で設定します。
- initialSize, minIdle のデフォルト値は 10 ですが、product プロファイル以外では 1 にします。product プロファイルではデフォルト値の 10 にします。
- maxActive, maxIdle はデフォルト値の 100 のままにします。
- initialSize, maxActive, maxIdle, minIdle は application.properties, application-product.properties に明記することにします。
■application.properties
spring.datasource.tomcat.initialSize=1 spring.datasource.tomcat.maxActive=100 spring.datasource.tomcat.maxIdle=100 spring.datasource.tomcat.minIdle=1
■application-product.properties
spring.datasource.tomcat.initialSize=10 spring.datasource.tomcat.maxActive=100 spring.datasource.tomcat.maxIdle=100 spring.datasource.tomcat.minIdle=10
testOnBorrow, validationQuery, validationQueryTimeout
プールからコネクションを取得する時に有効性が検証されるようにします。この設定は application.properties にのみ設定します。
■application.properties
spring.datasource.tomcat.testOnBorrow=true spring.datasource.tomcat.validationQuery=select 1 spring.datasource.tomcat.validationQueryTimeout=5
removeAbandoned, removeAbandonedTimeout
クローズ漏れのコネクションが自動検知されるようにします。
- application.properties にのみ設定します。
- removeAbandonedTimeout のデフォルト値は 60秒ですが、30秒にします。
■application.properties
spring.datasource.tomcat.removeAbandoned=true spring.datasource.tomcat.removeAbandonedTimeout=30
ここまでの設定が反映されているか jconsole で確認する
application.properties に spring.autoconfigure.exclude=com.integralblue.log4jdbc.spring.Log4jdbcAutoConfiguration
を追加してから develop プロファイルで Tomcat を起動した後、jconsole で確認します。
全ての設定が反映されていることが確認できます。
SlowQueryReport を使用してスロークエリーをログに出力する
Tomcat JDBC Connection Pool にはスロークエリーを検知する仕組みがあるようなので試してみます。スロークエリーを検知したら専用のログファイルに出力させてみます。
src/main/resources の下の application.properties を リンク先のその1の内容 に変更します。
src/main/resources の下の application-product.properties を リンク先のその1の内容 に変更します。
src/main/resources の下の logback-product.xml を リンク先の内容 に変更します。
clean タスク → Rebuild Project → build タスクを実行して ksbysample-webapp-lending-1.4.5-RELEASE.jar を作成します。
C:\project-springboot\ksbysample-webapp-lending\build\libs\ksbysample-webapp-lending-1.4.5-RELEASE.jar を C:\webapps\ksbysample-webapp-lending\lib の下へコピーします。
C:\webapps\ksbysample-webapp-lending\bat\webapp_startup.bat の中の
set WEBAPP_JAR=ksbysample-webapp-lending-1.4.5-RELEASE.jar
に変更します。webapp_startup.bat を実行します。
slow-query.log が作成されます。
ログインして検索対象図書館登録画面から図書館を登録すると、slow-query.log に以下のように出力されました。
Ctrl+C を押して webapp_startup.bat を停止します。
スロークエリーに出力される条件は 5秒に変更しておきます。src/main/resources の下の application.properties を リンク先のその2の内容 に変更します。
次回は。。。
application.properties の最終形、application-product.properties の最終形を記載します。
次回は、
- ログイン画面で何も入力せずに「ログイン」ボタンをクリックすると “500 Internal Server Error” になることに気付いたので、修正します。
- Spring Security 関連で修正した方がよい箇所があれば見直します。
- その後で jar ファイルを作成して動作確認して終わりに向かう予定です。
ソースコード
application.properties
■その1
spring.datasource.tomcat.jdbc-interceptors=SlowQueryReport(threshold=0)
spring.datasource.tomcat.jdbc-interceptors=SlowQueryReport(threshold=0)
を追加します。まずは全てのクエリーをログに出力したいので、スロークエリーの基準は 0 ミリ秒 ( threshold=0 ) にします。
■その2
spring.datasource.tomcat.jdbc-interceptors=SlowQueryReport(threshold=5000)
■最終形
doma.dialect=org.seasar.doma.jdbc.dialect.PostgresDialect spring.datasource.tomcat.url=jdbc:postgresql://localhost/ksbylending spring.datasource.tomcat.username=ksbylending_user spring.datasource.tomcat.password=xxxxxxxx spring.datasource.tomcat.driverClassName=org.postgresql.Driver spring.datasource.tomcat.initialSize=1 spring.datasource.tomcat.maxActive=100 spring.datasource.tomcat.maxIdle=100 spring.datasource.tomcat.minIdle=1 spring.datasource.tomcat.testOnBorrow=true spring.datasource.tomcat.validationQuery=select 1 spring.datasource.tomcat.validationQueryTimeout=5 spring.datasource.tomcat.removeAbandoned=true spring.datasource.tomcat.removeAbandonedTimeout=30 spring.datasource.tomcat.jdbc-interceptors=SlowQueryReport(threshold=5000) # spring.datasource.jmx-enabled は spring.datasource.tomcat.jmx-enabled と書かないこと。 # spring.datasource.tomcat.jmx-enabled だと機能しない。 spring.datasource.jmx-enabled=true spring.session.store-type=redis spring.freemarker.cache=true spring.freemarker.charset=UTF-8 spring.freemarker.enabled=false spring.freemarker.prefer-file-system-access=false
application-product.properties
■その1
server.tomcat.basedir=C:/webapps/ksbysample-webapp-lending logging.file=${server.tomcat.basedir}/logs/ksbysample-webapp-lending.log slowquery.logging.file=${server.tomcat.basedir}/logs/slow-query.log
slowquery.logging.file=${server.tomcat.basedir}/logs/slow-query.log
を追加します。
■最終形
server.tomcat.basedir=C:/webapps/ksbysample-webapp-lending logging.file=${server.tomcat.basedir}/logs/ksbysample-webapp-lending.log slowquery.logging.file=${server.tomcat.basedir}/logs/slow-query.log spring.autoconfigure.exclude=com.integralblue.log4jdbc.spring.Log4jdbcAutoConfiguration spring.datasource.tomcat.initialSize=10 spring.datasource.tomcat.maxActive=100 spring.datasource.tomcat.maxIdle=100 spring.datasource.tomcat.minIdle=10 spring.mail.host=localhost spring.mail.port=25 spring.rabbitmq.host=localhost spring.rabbitmq.port=5672 spring.redis.sentinel.master=mymaster spring.redis.sentinel.nodes=localhost:6381,localhost:6382,localhost:6383
logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?> <configuration> <include resource="org/springframework/boot/logging/logback/defaults.xml"/> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>${CONSOLE_LOG_PATTERN}</pattern> <charset>UTF-8</charset> </encoder> </appender> <if condition='"${spring.profiles.active}" == "product"'> <then> <property name="LOG_FILE" value="${LOG_FILE}"/> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <encoder> <pattern>${FILE_LOG_PATTERN}</pattern> </encoder> <file>${LOG_FILE}</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${LOG_FILE}.%d{yyyy-MM-dd}</fileNamePattern> <maxHistory>30</maxHistory> </rollingPolicy> </appender> </then> </if> <!-- SlowQueryReport用ログファイル --> <if condition='"${spring.profiles.active}" == "product" && "${slowquery.logging.file}" != ""'> <then> <springProperty scope="context" name="slowQueryLogFile" source="slowquery.logging.file"/> <appender name="SLOWQUERY_LOG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <encoder> <pattern>${FILE_LOG_PATTERN}</pattern> </encoder> <file>${slowQueryLogFile}</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${slowQueryLogFile}.%d{yyyy-MM-dd}</fileNamePattern> <maxHistory>30</maxHistory> </rollingPolicy> </appender> </then> </if> <if condition='"${spring.profiles.active}" == "develop"'> <then> <include resource="logback-develop.xml"/> </then> </if> <if condition='"${spring.profiles.active}" == "unittest"'> <then> <include resource="logback-unittest.xml"/> </then> </if> <if condition='"${spring.profiles.active}" == "product"'> <then> <include resource="logback-product.xml"/> </then> </if> </configuration>
<!-- SlowQueryReport用ログファイル --><if condition=...> ... </if>
を追加します。<if condition='...'>
の中で AND 条件を記述する場合には&&
と書きます。
logback-product.xml
<?xml version="1.0" encoding="UTF-8"?> <included> <root level="INFO"> <appender-ref ref="FILE"/> </root> <!-- Doma 2 --> <logger name="org.seasar.doma" level="ERROR"/> <!-- Tomcat JDBC Connection Pool SlowQueryReport interceptor --> <if condition='"${slowquery.logging.file}" != ""'> <then> <logger name="org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReport" level="INFO"> <appender-ref ref="SLOWQUERY_LOG_FILE"/> </logger> </then> </if> </included>
<!-- Tomcat JDBC Connection Pool SlowQueryReport interceptor --><if condition=...> ... </if>
を追加します。
履歴
2017/04/20
初版発行。