带有 Peewee 连接池的 Django MySQL 断开连接
Django with Peewee Connection Pooling MySQL disconnect
我 运行 在 Python 3.6 中使用 Peewee 构建一个 Django 项目,并试图找出连接池的问题所在。我在开发服务器上不断收到以下错误(出于某种原因,我在本地计算机上从未遇到过此问题):
Lost connection to MySQL server during query
重现步骤是可靠的,并且是:
- 在实例上重新启动 Apache。
- 转到我的 Django 页面并按下触发数据库操作的按钮。
- 工作正常。
- 正好等待 10 分钟(我已经进行了足够的测试以获得确切的数字)。
- 按另一个按钮触发另一个数据库操作。
- 获取上面的丢失连接错误。
代码的结构使得我将所有数据库操作都放在一个独立的 Python 模块中,该模块被导入到 Django 模块中。
在主 class 构造函数中,我将数据库设置为:
from playhouse.pool import PooledMySQLDatabase
def __init__(self, host, database, user, password, stale_timeout=300):
self.mysql_db = PooledMySQLDatabase(host=host, database=database, user=user, password=password, stale_timeout=stale_timeout)
db_proxy.initialize(self.mysql_db)
每个需要调用数据库的调用都是这样完成的:
def get_user_by_id(self, user_id):
db_proxy.connect(reuse_if_open=True)
user = (User.get(User.user_id == user_id))
db_proxy.close()
return {'id': user.user_id, 'first_name': user.first_name, 'last_name': user.last_name, 'email': user.email }
我查看了 MySQL 实例上的 wait_timeout
值,它的值为 3600,所以这似乎不是问题所在(我还是尝试更改它只是为了看看)。
关于我在这里可能做错了什么有什么想法吗?
更新:
我发现 MySQL 的 /etc/my.cnf
配置文件将 wait-timeout
值设置为 600,这与我遇到的情况相符。我不知道为什么当我在 MySQL 数据库(returns 3600)上 运行SHOW VARIABLES LIKE 'wait_timeout';
时这个值没有显示,但看起来问题可能来了来自等待超时。
考虑到这一点,我尝试将过时超时设置为 60,假设如果它小于等待超时,它可能会解决问题,但没有任何区别。
您需要确保正确地回收连接——这意味着当请求开始时您打开连接,当响应被传递时您关闭连接。池没有回收 conn 很可能是因为你永远不会把它放回池中,所以它看起来仍然 "in use"。这可以使用中间件轻松完成,并在此处进行了描述:
http://docs.peewee-orm.com/en/latest/peewee/database.html#django
在尝试了 许多 个想法后,我终于想出了一个适用于我的案例的修复程序。这并不理想,但确实有效。 This post on Connection pooling 为我指明了正确的方向。
我创建了一个 Django 中间件 class 并将其配置为 Django 中间件列表中的第一个。
from peewee import OperationalError
from playhouse.pool import PooledMySQLDatabase
database = PooledMySQLDatabase(None)
class PeeweeConnectionMiddleware(object):
CONN_FAILURE_CODES = [ 2006, 2013, ]
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if database.database: # Is DB initialized?
response = None
try:
database.connect(reuse_if_open=True)
with database.atomic() as transaction:
try:
response = self.get_response(request)
except:
transaction.rollback()
raise
except OperationalError as exception:
if exception.args[0] in self.CONN_FAILURE_CODES:
database.close_all()
database.connect()
response = None
with database.atomic() as transaction:
try:
response = self.get_response(request)
except:
transaction.rollback()
raise
else:
raise
finally:
if not database.is_closed():
database.close()
return response
else:
return self.get_response(request)
我 运行 在 Python 3.6 中使用 Peewee 构建一个 Django 项目,并试图找出连接池的问题所在。我在开发服务器上不断收到以下错误(出于某种原因,我在本地计算机上从未遇到过此问题):
Lost connection to MySQL server during query
重现步骤是可靠的,并且是:
- 在实例上重新启动 Apache。
- 转到我的 Django 页面并按下触发数据库操作的按钮。
- 工作正常。
- 正好等待 10 分钟(我已经进行了足够的测试以获得确切的数字)。
- 按另一个按钮触发另一个数据库操作。
- 获取上面的丢失连接错误。
代码的结构使得我将所有数据库操作都放在一个独立的 Python 模块中,该模块被导入到 Django 模块中。
在主 class 构造函数中,我将数据库设置为:
from playhouse.pool import PooledMySQLDatabase
def __init__(self, host, database, user, password, stale_timeout=300):
self.mysql_db = PooledMySQLDatabase(host=host, database=database, user=user, password=password, stale_timeout=stale_timeout)
db_proxy.initialize(self.mysql_db)
每个需要调用数据库的调用都是这样完成的:
def get_user_by_id(self, user_id):
db_proxy.connect(reuse_if_open=True)
user = (User.get(User.user_id == user_id))
db_proxy.close()
return {'id': user.user_id, 'first_name': user.first_name, 'last_name': user.last_name, 'email': user.email }
我查看了 MySQL 实例上的 wait_timeout
值,它的值为 3600,所以这似乎不是问题所在(我还是尝试更改它只是为了看看)。
关于我在这里可能做错了什么有什么想法吗?
更新:
我发现 MySQL 的 /etc/my.cnf
配置文件将 wait-timeout
值设置为 600,这与我遇到的情况相符。我不知道为什么当我在 MySQL 数据库(returns 3600)上 运行SHOW VARIABLES LIKE 'wait_timeout';
时这个值没有显示,但看起来问题可能来了来自等待超时。
考虑到这一点,我尝试将过时超时设置为 60,假设如果它小于等待超时,它可能会解决问题,但没有任何区别。
您需要确保正确地回收连接——这意味着当请求开始时您打开连接,当响应被传递时您关闭连接。池没有回收 conn 很可能是因为你永远不会把它放回池中,所以它看起来仍然 "in use"。这可以使用中间件轻松完成,并在此处进行了描述:
http://docs.peewee-orm.com/en/latest/peewee/database.html#django
在尝试了 许多 个想法后,我终于想出了一个适用于我的案例的修复程序。这并不理想,但确实有效。 This post on Connection pooling 为我指明了正确的方向。
我创建了一个 Django 中间件 class 并将其配置为 Django 中间件列表中的第一个。
from peewee import OperationalError
from playhouse.pool import PooledMySQLDatabase
database = PooledMySQLDatabase(None)
class PeeweeConnectionMiddleware(object):
CONN_FAILURE_CODES = [ 2006, 2013, ]
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if database.database: # Is DB initialized?
response = None
try:
database.connect(reuse_if_open=True)
with database.atomic() as transaction:
try:
response = self.get_response(request)
except:
transaction.rollback()
raise
except OperationalError as exception:
if exception.args[0] in self.CONN_FAILURE_CODES:
database.close_all()
database.connect()
response = None
with database.atomic() as transaction:
try:
response = self.get_response(request)
except:
transaction.rollback()
raise
else:
raise
finally:
if not database.is_closed():
database.close()
return response
else:
return self.get_response(request)