コネクションプールの仕組みについて
前提知識
まずはWebサーバの実装モデルについておさらいする
ノンブロッキングIOという言葉が曖昧だったので、こちらの記事で内容を確認した
基本的にこの資料を全て読む
DB接続を学ぶ動機
Redisに限らず、MySQL、Memcachedなど、他のサーバ上で動作するデータベースプロセスとWebアプリケーションの接続について考えてみよう。 非常に地味なテーマだ。しかし、システムを運用している立場からすると、システムの安定運用のためには意外と重要な技術ではある。 Webアプリケーションサーバだけでなく、データベースサーバのアーキテクチャも意識することになるため、奥が深い。 WebアプリケーションフレームワークやORMの選定にも影響するため、オペレーションエンジニアだけでなく、アプリケーションエンジニアも意識する必要がある。
ところが、データベースの接続モデルを体系的に勉強しようと試みてもなかなかうまくいかない。 Webサーバアーキテクチャ以上に体系化されたドキュメントが見つからず、特定のデータベースや、特定のクライアント実装、特定のワークロードに限定した話に振り回されがちだった。
まさに
細かい違いはあれど、結局は、アプリケーションサーバからデータベースサーバに対して、接続を維持するかそれとも都度接続するか、接続を維持するならどのように接続を維持するのかという問題でしかない。
これを知りたい
接続の永続化により、データベースがフェイルオーバすると、アプリケーションサーバがフェイルオーバ先に再接続するまで、時間がかかることがある。 これは接続切断の検出などの再接続まわりの実装次第ではある。TCPの接続が切れるまで待たされる可能性もある。 大量のリクエストをさばいている環境だと、一瞬詰まると、システム全体が詰まってしまうこともあり得る。 アプリケーションサーバの再起動が必要な場合もあるだろう。
うんうん
システム全体に影響を与えるくらいなら、クライアント側で上限を設けておいて、多少の接続待ちが起きてもよいことにする。 つまり、通常の常時接続では、単にコネクション数を節約できるというメリットがあり、それに対して、クライアント側でコネクションプーリングを用いていると、一線を超えないようにデータベースサーバの負荷をコントロールできるということだと考えている。
JDBCのドライバ型コネクションプーリング
JDBCのコネクションプーリング(BoneCP、HikariCP など)は、大雑把には、リクエスト処理用のスレッドプール以外に、データベース接続用のスレッドプールを作成して、各スレッドのローカル変数に接続オブジェクトを持たせるような形になっている。
接続数を管理できるとはいっても、ドライバ型の場合、アプリケーションサーバの台数を増やすと、接続数もアプリケーションサーバ数に比例して増える。したがって、プロキシ型は全てのアプリケーションサーバからの接続数を一定に保ちやすい
負荷のピークタイムが存在するシステムの場合、ピークタイムに合わせてプール数を設定していると、ピークタイム以外には余分な接続が開いたままなため、データベース側の接続維持のためのメモリが無駄になるという話もある。 BoneCPなどの一部のコネクションプールの実装は、最小接続数と最大接続数を設定しておき、最小と最大の定義域の範囲内で、接続数を負荷に合わせて動的に変更して、メモリ効率を良くしている。
パラメータチューニング
例えば、最大/最小プール数を等しくした結果、接続維持時間を超えた瞬間、一斉に再接続が発生し、一部のアプリケーションスレッドがプールからコネクションを取り出せずにエラーを吐くということがあった。
怖い
PosgresSQLとMySQL
PostgreSQLは1つの接続に対して、1つのプロセスを生成する。 つまり、マルチプロセスモデルであるため、後述のMySQLと比較して、メモリ消費量は多いといえる。 もちろん、Copy On Write(CoW)が効くはずなので、メモリ消費量は多少は最適化される。 しかし、接続を永続化していれば、徐々にfork元プロセスとの乖離が激しくなり、プロセスあたりのメモリ消費量は増加していく。 PostgreSQLは、接続を受け付ける度にforkするため、接続のオーバヘッドはそれなりに大きい。 大量接続を同時に受け付けると、負荷が跳ね上げることがある。
一方、MySQLは1つの接続に対して、1つのスレッドを生成する。 マルチスレッドモデルであるため、PostgreSQLと比べて、メモリ消費量は抑えられるはずだ。 とはいえ、スレッド生成/破棄にはそれなりのオーバヘッドがある。 MySQLにはThread Cacheの仕組みがあり、接続に使用したスレッドを使い回すことにより、オーバヘッドを抑えている。
MySQL の場合新規接続コストが安いのでリクエストごとに接続してもパフォーマンスにあまり影響がなかったりします
そうなのか