経緯
私は、LGTM画像を簡単に作成できるサービス「LGTMoon」を公開しています。
この LGTMoon は Heroku *1 で動いています。DBには Heroku PostgreSQL を使っています。 Heroku PostgreSQL は、接続できるコネクション数が20に制限されています。*2
アクセスが集中したり、重い処理が重なると、このコネクション制限に引っかかり、画像が表示されないなど、問題が起こることがありました。
コネクション数が20と制限されているのであれば、それに合わせてアプリ側でコネクションプールを張ったほうがいいんじゃないかと思いました。
今回は、 Scala, Play, Slick で、コネクションプールを使う方法をまとめます。
環境
- Scala 2.11
- Play Framework 2.5
- Slick 3.2 (play-slick ではなくただのSlickです)
コネクションプールとは
通常アプリケーションからDBに接続する場合は
- APIにリクエストが来る
- コネクションを確立させて
- クエリを流して結果を取得
- コネクションを切る
という手順になります。
しかし、コネクションが20個埋まっている場合、「2. コネクション確立」で失敗になってしまい、エラーになってしまいます。
一方、コネクションプールを利用すると
- アプリ起動時にあらかじめコネクションを20個つくっておく
- APIリクエストが来る
- 空いてるコネクションを探す
- クエリを流して結果を取得
という手順になります。あらかじめアプリ起動時にコネクションを20個張ってしまうわけです。
各APIリクエスト時にm毎回コネクションを張る必要がなくなるので、コネクション確立のオーバーヘッドがなくなり、パフォーマンスが向上します。
コネクションプールを張ってなかったときの接続方法
conf/application.conf
の設定
# Database pg_database = { url = "jdbc:postgresql://localhost/lgtmoon?user=postgres&password=postgres" driver = org.postgresql.Driver connectionPool = disable keepAliveConnection = true }
DB接続部分
Database.forConfig("pg_database")...
コネクションプールの利用
connectionPool の設定を enabled に変更するだけでは動きません。コネクションプールを利用するライブラリを設定し、コネクション数などのの設定を追加する必要があります。
configの書き換え
以下のように書き換えます
https://github.com/yoshikyoto/lgtmoon/commit/95bfaa605d2c24c035759d53282cb1aae630052b
pg_database = { url = "jdbc:postgresql://localhost/lgtmoon?user=postgres&password=postgres" driver = org.postgresql.Driver connectionPool = HikariCP properties = { # HikariCP の設定 maximumPoolSize = 20 minimumIdle = 10 } keepAliveConnection = true }
今回はHikari CPというコネクションプールのライブラリを利用します。Slickで利用できるコネクションプールライブラリはいくつかあるのですが、Hikari CPが一般的で最も広く利用されているようです。
maximumPoolSizeはその名の通りコネクションの最大数です。Heroku PostgreSQLのコネクションの最大値である20を設定します。
minimumIdle は 10 にしていますが、基本的には maximumPoolSize と同じ値にしたほうがいいとのことです。後ほど20に変更しようと思っています。
minimumIdleはアプリケーションにあまりリクエストが来ていないときのminimumのコネクション数ですが、常に上限いっぱいまで接続しておいたほうがパフォーマンスが良いためです。
Hikari CPライブラリの導入
build.sbtに以下を書きます。
https://github.com/yoshikyoto/lgtmoon/commit/95bfaa605d2c24c035759d53282cb1aae630052b
libraryDependencies ++= Seq( ... "com.typesafe.slick" %% "slick" % "3.2.3", ... "com.typesafe.slick" %% "slick-hikaricp" % "3.2.3" )
もともと slick の 3.2.3 を使っていましたので、それに合わせて slick-hikaricp 3.2.3 を導入します。
これだけでコネクションプールの導入は完了です。