LoginSignup
10
4

More than 3 years have passed since last update.

Python + MySQL でコネクションプーリング

Posted at

Python で MySQL とのコネクションプーリングを行う方法と、そのハマりどころについて。

mysql-connector-python の MySQLConnectionPool の問題

まず、MySQL 公式の Python クライアント mysql-connector-python で単純にコネクションを作成する場合は以下のように書ける。

import mysql.connector

cnx = mysql.connector.connect(host="...", user="...", password="...", database="...")

この mysql-connector-python には MySQLConnectionPool というクラスが用意されており、これを使うと簡単にコネクションプーリングができる。1

from mysql.connector.pooling import MySQLConnectionPool

cnxpool = MySQLConnectionPool(host="...", user="...", password="...", database="...", pool_size=10)

cnx = cnxpool.get_connection()

cnx.close()  # 実際にはコネクションは切断されず、コネクションプールにリリースされる

めでたしめでたし・・・とはいかない。

試しに以下のコードを実行してみる。

from mysql.connector.pooling import MySQLConnectionPool

cnxpool = MySQLConnectionPool(host="...", user="...", password="...", database="...", pool_size=3)

cnxpool.get_connection()
cnxpool.get_connection()
cnxpool.get_connection()
cnxpool.get_connection()  #=> PoolError: Failed getting connection; pool exhausted

MySQLConnectionPool はプールのコネクションが枯渇した場合、例外を投げる仕様となっている。

このシンプルな仕様は嫌いではないのだけど、実際に Web アプリケーションなどで利用する際は「他のコネクションがリリースされるまで待つ」ような挙動であってくれたほうが嬉しいケースが多い。そうでないと、リクエスト処理の並列数が少しでもプールサイズを上回っただけでエラーが発生してしまう。

SQLAlchemy の QueuePool を使った解決策

この問題は、SQLAlchemy の QueuePool を使うと解決できる。2

from sqlalchemy.pool import QueuePool

cnxpool = QueuePool(lambda: mysql.connector.connect(host="...", user="...", password="...", database="..."), pool_size=10)

cnx = cnxpool.connect()

QueuePool の第一引数は「DB API に対応したコネクションオブジェクト」を返す関数ならなんでもいいらしい。汎用的ですごい。

SQLAlchemy というモジュール自体は ORM だが、今回は ORM 部分を全く使わずに QueuePool という仕組みだけを利用している。

10
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
4