FinagleのConnectionPool

すぐに忘れるので参照できるように雑にまとめ

Clients — Finagle 6.44.0 documentation とかを見るとすべて書いてあるので、基本的には公式を見たほうが良いです。 実装を読んだものも含んでいるのでfinagle 6.45以外で成り立つかは不明です。

種類について

以下の4種類がある。

  • Buffering Pool
  • Watermark Pool
  • Caching Pool
  • SingletonPool

Buffering Pool

finagle/BufferingPool.scala at finagle-6.45.0 · twitter/finagle · GitHub

bufferSizeを1以上にするとONになるデフォルトはOFF。 Watermarkの方が小回りがきくので基本的には使わなくてよいはず・・?

Watermark Pool

finagle/WatermarkPool.scala at finagle-6.45.0 · twitter/finagle · GitHub

low(デフォルト0), high(デフォルト Int.MaxValue)maxWaiters(デフォルト Int.MaxValue)の3つを設定して使う。

基本的にはlow ~ highの区間でコネクションを保持するもの。 最初のコネクションは0個なので常にこの区間にあるわけではなく、コネクションを作るときにlow個まではコネクションを保持し、それ以上は保持しないという動作。

high個以上のリクエストについてはそもそもコネクションを作らずwaitersキューに入れるという動作になっている。 このときlowを超えた分は基本的に随時connectしたりcloseしたりされるがwaiterが居る場合はcloseせずに使いまわす。 また、waitersキューに入れる際にキューサイズがmaxWaitersを超えていたらキューには追加せずTooManyWaitersExceptionが発生するようになっている。

Caching Pool

finagle/CachingPool.scala at finagle-6.45.0 · twitter/finagle · GitHub

WatermarkPoolだけだとlowを超えた瞬間に接続したり切断したりが繰り返されてしまう。 これを防ぐためにidleTimeに従って時間ベースでコネクションをキャッシュするのがCachingPool。 idleTimeというだけあって、コネクションが活用されている間はevictionされないようになっている。 ただし、idleTimeは目安であって実際には[ttl, ttl * 2)のレンジでevictされる様子

キャッシュされる個数はhigh - low個になっている。 デフォルトだとLong.MaxValueナノ秒キャッシュされるので、適宜調節しても良いかもしれない。

Singleton Pool

finagle/SingletonPool.scala at finagle-6.45.0 · twitter/finagle · GitHub

コネクションプールと言いつつ一つのコネクションのみを保持するプール ThriftMuxはコネクションを多重化しているのでプールいらないよねという事情により存在する。

使われ方

DefaultPoolを見ると、BufferPool/WatermarkPool/CachingPoolは組み合わせて利用するようになっている模様。 BufferPool(defaultオフ) => WatermarkPool => CachingPool のように順番にキャッシュ判定などがされるようになっている。(SingletonPoolは別枠)

どの条件で使われるかについては現状だと以下のようになっている

プール名 ONになる条件 備考
BufferPool bufferSize > 0 defaultでは0で、基本的に変える必要はなさそう。
WatermarkPool true 常に有効になっている
CachingPool idleTime > 0.seconds && high > low defaultだとLong.MaxValueナノ秒保持される

役立つmetrics

Metrics — Finagle 6.44.0 documentation を見るのが良い。 pool_waiterspool_num_waited を見ると待機キューが使われているかどうかなどを把握できる。 ちなみに pool_cached はキャッシュされているコネクションの数を表すが、現在使われているコネクションはこの中には入らないようなのでサーバーに負荷がかかっている状態では0になったりするっぽい。(cachからgetするとdequeからpopされるためsizeが減る)