使用django和sqlalchemy的连接池
django-conn-pool的Python项目详细描述
Django Conn游泳池
使用django(>;2.0.0)和sqlalchemy(>;=1.2.7)的mysql连接池。
为什么
如果设置中没有设置CONN_MAX_AGE
,django将为每个请求建立一个新的mysql连接,并在请求后关闭它。
因此,如果要处理的连接太多,它将建立太多的连接,直到mysql max_connections
用完为止。
然后,mysql将返回错误:ERROR 1040 (08004): Too many connections
。
对于一个健壮的django项目,有必要维护一个连接池。
原理
Reference: MySQL Connection Pooling with Django and SQLAlchemy
使用sqlalchemy queuepool从连接池创建mysqldb数据库get_new_connection
。
所以我们只需要自定义一个由连接池管理的数据库,并从连接池中获取新的连接。
pip install mysqlclient
pip install SQLAlchemy
核心代码:
import MySQLdb as Database
import sqlalchemy.pool as pool
from sqlalchemy.pool import QueuePool
from django.db.backends.mysql.base import DatabaseWrapper as _DatabaseWrapper
Database = pool.manage(Database, poolclass=QueuePool, **settings.SQLALCHEMY_QUEUEPOOL)
class DatabaseWrapper(_DatabaseWrapper):
def get_new_connection(self, conn_params):
# return a mysql connection
databases = settings.DATABASES
alias = None
for _alias in databases:
if databases[_alias]['NAME'] == conn_params['db']:
alias = _alias
break
client_flag = conn_params['client_flag']
conn_params = databases[alias]
return Database.connect(
host=conn_params['HOST'],
port=conn_params['PORT'],
user=conn_params['USER'],
db=conn_params['NAME'],
passwd=conn_params['PASSWORD'],
use_unicode=True,
charset='utf8',
client_flag=client_flag,
sql_mode='STRICT_TRANS_TABLES',
)
使用量
pip install django-conn-pool
settings.py
# http://docs.sqlalchemy.org/en/latest/core/pooling.html#sqlalchemy.pool.QueuePool
# http://docs.sqlalchemy.org/en/latest/core/pooling.html#sqlalchemy.pool.Pool.params
SQLALCHEMY_QUEUEPOOL = {
'pool_size': 10,
'max_overflow': 10,
'timeout': 5,
'recycle': 119,
}
DATABASES = {
'default': {
'ENGINE': 'django_conn_pool.mysql',
'HOST': '127.0.0.1',
'NAME': 'xxx',
'USER': 'xxx',
'PASSWORD': 'xxx',
'PORT': 3306,
},
'other': {
'ENGINE': 'django_conn_pool.mysql',
'HOST': '127.0.0.1',
'NAME': 'xxx',
'USER': 'xxx',
'PASSWORD': 'xxx',
'PORT': 3306,
},
}
测试
如果python manage.py runserver
可以,现在可以使用负载测试实用程序Siege进行测试。
siege -r 2 -c 1000 -d 0 http://xxx # siege --help
您可以将mysql进程列表计数与之前的进行比较,它应该可以工作。
顺便说一句,如果在请求过程中没有得到连接,那么应该得到一个sqlalchemy.exc.TimeoutError:
异常。