EatSmartシステム部ブログ

ウェブサイトの開発や運営に関する情報です。

Zabbix から Spring Boot アプリケーションのデータベース接続状況を取得する

イートスマートでは、Zabbixで各サーバやコンテナのリソースを管理し、必要に応じてアラートを飛ばしています。 先日、データベースの接続数が増えてきたのでコンテナごとに接続数を把握しようと思い、Zabbixのテンプレートを使い以下の2つの項目を監視するようにしました。

jmx["Catalina:class=javax.sql.DataSource,context=/,host=localhost,name=\"database\",type=DataSource",numActive]
jmx["Catalina:class=javax.sql.DataSource,context=/,host=localhost,name=\"database\",type=DataSource",numIdle]

それぞれ接続数とアイドル数です。 Tomcatを利用するアプリケーションは問題なく取得出来ましたが、Spring Bootを利用するアプリケーション(以降Spring Bootアプリ)で取得出来ませんでした。 Spring Bootアプリに必要となった設定をまとめます。Spring Bootのバージョンは少し古く1.5.2となります。

データベス接続情報

spring:
  profiles: stg
  datasource:
    driverClassName: org.postgresql.Driver
    url: jdbc:postgresql://xxxx.xxxx.xxxx:5432/xxxx
    username: xxxx
    password: xxxx
    jmx-enabled: true

新たに spring.datasource.jmx-enabled: true という設定が必要になりました。 application.ymlへは、以下のように追加しました。

起動オプション

java -Dcom.sun.management.jmxremote \
  -Dcom.sun.management.jmxremote.port=[JMXポート番号] \
  -Dcom.sun.management.jmxremote.authenticate=false \
  -Dcom.sun.management.jmxremote.ssl=false \
  -Dcom.sun.management.jmxremote.rmi.port=[JMXポート番号] \
  -Djava.rmi.server.hostname=[ホストIPアドレス] \
  ....

アプリケーション起動時に、JMXで利用するポート番号等の設定を追加しました。 ホストのIPアドレスを指定しているのは、Dockerコンテナで起動する場合にポートフォワードでは動かないためです。 そのたりは以下に書いています。

eatsmart.hatenablog.com

動作確認

上記の設定を行い起動すると、ログに以下のようにMBeanの登録情報が出力されます。

2019-11-19 16:22:31.077  INFO 15636 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2019-11-19 16:22:31.079  INFO 15636 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Bean with name 'dataSourceMBean' has been autodetected for JMX exposure
2019-11-19 16:22:31.084  INFO 15636 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Located MBean 'dataSourceMBean': registering with JMX server as MBean [org.apache.tomcat.jdbc.pool.jmx:name=dataSourceMBean,type=ConnectionPool]

この情報をもとに接続します。接続には、javaから手軽に利用できる jmxterm を利用します。

docs.cyclopsgroup.org

java -jar jmxterm-1.0.0-uber.jar
$>open xxx.xxx.xxx.xxx:12345
#Connection to xxx.xxx.xxx.xxx:12345 is opened
$>info -b org.apache.tomcat.jdbc.pool.jmx:name=dataSourceMBean,type=ConnectionPool
#mbean = org.apache.tomcat.jdbc.pool.jmx:name=dataSourceMBean,type=ConnectionPool
#class name = org.apache.tomcat.jdbc.pool.jmx.ConnectionPool
# attributes
  %0   - AbandonWhenPercentageFull (int, rw)
  %1   - AccessToUnderlyingConnectionAllowed (boolean, rw)
  %2   - Active (int, r)
  %3   - AlternateUsernameAllowed (boolean, rw)
  %4   - BorrowedCount (long, r)
  %5   - CommitOnReturn (boolean, rw)
  %6   - ConnectionProperties (java.lang.String, rw)
  %7   - CreatedCount (long, r)
  %8   - DataSource (java.lang.Object, rw)
  %9   - DataSourceJNDI (java.lang.String, rw)
  %10  - DbProperties (java.util.Properties, rw)
  %11  - DefaultAutoCommit (java.lang.Boolean, rw)
  %12  - DefaultCatalog (java.lang.String, rw)
  %13  - DefaultReadOnly (java.lang.Boolean, rw)
  %14  - DefaultTransactionIsolation (int, rw)
  %15  - DriverClassName (java.lang.String, rw)
  %16  - FairQueue (boolean, rw)
  %17  - Idle (int, r)
  %18  - IgnoreExceptionOnPreLoad (boolean, rw)
  %19  - InitSQL (java.lang.String, rw)
  %20  - InitialSize (int, rw)
  %21  - JdbcInterceptors (java.lang.String, rw)
  %22  - JdbcInterceptorsAsArray ([Lorg.apache.tomcat.jdbc.pool.PoolProperties$InterceptorDefinition;, r)
  %23  - JmxEnabled (boolean, rw)
  %24  - LogAbandoned (boolean, rw)
  %25  - LogValidationErrors (boolean, rw)
  %26  - MaxActive (int, rw)
  %27  - MaxAge (long, rw)
  %28  - MaxIdle (int, rw)
  %29  - MaxWait (int, rw)
  %30  - MinEvictableIdleTimeMillis (int, rw)
  %31  - MinIdle (int, rw)
  %32  - Name (java.lang.String, rw)
  %33  - NumActive (int, r)
  %34  - NumIdle (int, r)
  %35  - NumTestsPerEvictionRun (int, rw)
  %36  - Password (java.lang.String, rw)
  %37  - PoolName (java.lang.String, r)
  %38  - PoolSweeperEnabled (boolean, r)
  %39  - PropagateInterruptState (boolean, rw)
  %40  - ReconnectedCount (long, r)
  %41  - ReleasedCount (long, r)
  %42  - ReleasedIdleCount (long, r)
  %43  - RemoveAbandoned (boolean, rw)
  %44  - RemoveAbandonedCount (long, r)
  %45  - RemoveAbandonedTimeout (int, rw)
  %46  - ReturnedCount (long, r)
  %47  - RollbackOnReturn (boolean, rw)
  %48  - Size (int, r)
  %49  - SuspectTimeout (int, rw)
  %50  - TestOnBorrow (boolean, rw)
  %51  - TestOnConnect (boolean, rw)
  %52  - TestOnReturn (boolean, rw)
  %53  - TestWhileIdle (boolean, rw)
  %54  - TimeBetweenEvictionRunsMillis (int, rw)
  %55  - Url (java.lang.String, rw)
  %56  - UseDisposableConnectionFacade (boolean, rw)
  %57  - UseEquals (boolean, rw)
  %58  - UseLock (boolean, rw)
  %59  - Username (java.lang.String, rw)
  %60  - ValidationInterval (long, rw)
  %61  - ValidationQuery (java.lang.String, rw)
  %62  - ValidationQueryTimeout (int, rw)
  %63  - Validator (org.apache.tomcat.jdbc.pool.Validator, rw)
  %64  - ValidatorClassName (java.lang.String, rw)
  %65  - WaitCount (int, r)
# operations
  %0   - void checkAbandoned()
  %1   - void checkIdle()
  %2   - java.lang.Boolean isDefaultAutoCommit()
  %3   - java.lang.Boolean isDefaultReadOnly()
  %4   - void purge()
  %5   - void purgeOnReturn()
  %6   - void resetStats()
  %7   - void testIdle()
# notifications
  %0   - javax.management.Notification(INIT FAILED,CONNECTION FAILED,CONNECTION ABANDONED,SLOW QUERY,FAILED QUERY,SUSPECT CONNECTION ABANDONED,POOL EMPTY,SUSPECT CONNECTION RETURNED)

この出力内容から、今回必要なものが NumActive と NumIdle ということがわかったので、Spring Bootアプリ用のテンプレートを作成し、以下の2つの項目を監視するようにしました。

jmx["org.apache.tomcat.jdbc.pool.jmx:name=dataSourceMBean,type=ConnectionPool",NumActive]
jmx["org.apache.tomcat.jdbc.pool.jmx:name=dataSourceMBean,type=ConnectionPool",NumActive]

まとめ

以上の作業で、イートスマートで利用しているコンテナのデータベース接続数を把握することが出来るようになりました。 実際の利用状況と照らし合わせ、コンテナの最小アイドル数が多かったので、減らすことで問題への対処を行うことが出来ました。