【发布时间】:2019-11-14 21:10:26
【问题描述】:
为了测试,我将MYSQL(RDS)参数修改如下;
wait_timeout = 40(默认为 28800)
max_allowed_packet = 1GB(最大值 - 只是为了确保问题不是由小数据包引起的)
net_read_timeout = 10
interactive_timeout 不变
然后在没有设置pool_pre_ping 选项的情况下测试我的应用程序(默认为 False),让应用程序保持非活动状态 40 秒,尝试登录,然后我得到了
Nov 14 20:05:20 ip-172-31-33-52 gunicorn[16962]: Traceback (most recent call last):
Nov 14 20:05:20 ip-172-31-33-52 gunicorn[16962]: File "/var/www/api_server/venv/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 1193, in _execute_context
Nov 14 20:05:20 ip-172-31-33-52 gunicorn[16962]: context)
Nov 14 20:05:20 ip-172-31-33-52 gunicorn[16962]: File "/var/www/api_server/venv/lib/python3.6/site-packages/sqlalchemy/engine/default.py", line 507, in do_execute
Nov 14 20:05:20 ip-172-31-33-52 gunicorn[16962]: cursor.execute(statement, parameters)
Nov 14 20:05:20 ip-172-31-33-52 gunicorn[16962]: File "/var/www/api_server/venv/lib/python3.6/site-packages/MySQLdb/cursors.py", line 206, in execute
Nov 14 20:05:20 ip-172-31-33-52 gunicorn[16962]: res = self._query(query)
Nov 14 20:05:20 ip-172-31-33-52 gunicorn[16962]: File "/var/www/api_server/venv/lib/python3.6/site-packages/MySQLdb/cursors.py", line 312, in _query
Nov 14 20:05:20 ip-172-31-33-52 gunicorn[16962]: db.query(q)
Nov 14 20:05:20 ip-172-31-33-52 gunicorn[16962]: File "/var/www/api_server/venv/lib/python3.6/site-packages/MySQLdb/connections.py", line 224, in query
Nov 14 20:05:20 ip-172-31-33-52 gunicorn[16962]: _mysql.connection.query(self, query)
Nov 14 20:05:20 ip-172-31-33-52 gunicorn[16962]: MySQLdb._exceptions.OperationalError: (2013, 'Lost connection to MySQL server during query')
像这样添加pool_pre_ping(使用flask_sqlalchamy 2.4.1版);
import os
from flask import Flask
from flask_sqlalchemy import SQLAlchemy as _BaseSQLAlchemy
class SQLAlchemy(_BaseSQLAlchemy):
def apply_pool_defaults(self, app, options):
super(SQLAlchemy, self).apply_pool_defaults(app, options)
options["pool_pre_ping"] = True
# options["pool_recycle"] = 30
# options["pool_timeout"] = 35
db = SQLAlchemy()
class DevConfig():
SQLALCHEMY_ENGINE_OPTIONS = {'pool_recycle': 280, 'pool_timeout': 100, 'pool_pre_ping': True} # These configs doesn't get applied in engine configs :/
DEBUG = True
# SERVER_NAME = '127.0.0.1:5000'
SQLALCHEMY_DATABASE_URI = os.getenv('SQLALCHEMY_DATABASE_URI_DEV')
SQLALCHEMY_TRACK_MODIFICATIONS = False
config = dict(
dev=DevConfig,
)
app = Flask(__name__, instance_relative_config=True)
app.config.from_object(config['dev'])
# INIT DATABASE
db.init_app(app)
with app.app_context():
db.create_all()
-----------run.py
app.run(host='127.0.0.1', port=5000)
有了这个,现在 webapp 可以在 MySQL 服务器关闭之前的连接之后获得新的连接。当我在服务器关闭数据库后立即访问数据库时它总是工作正常(最多尝试 50 秒后)......但是当我长时间保持连接不活动时(没有注意到,但 ~ >10-15 分钟),再次我看到同样的错误。
根据文档(尤其是Dealing with disconnects 部分),pool_pre_ping 选项应该在后台仪式中处理这种情况吗?或者我需要在 MySQL 服务器中更改任何其他超时变量吗?
【问题讨论】:
-
你的 MySQL 连接器是什么?
-
忽略连接和池问题,您的程序应该运行多长时间?小时?天?它会闲置几个小时吗?或者至少不接触 MySQL,但希望连接保持完整?你有任何“交易”吗?您是否完全使用
autocommit=ON? -
这是一个后端服务器,需要 24/7 运行。是的,现在我们预计会有数小时和数天的空闲时间。我认为每次 mysql 连接后都没有任何未关闭的事务。如何检查 autocommit=ON ?
-
嗨@AnumSheraz,你找到解决方案了吗?我遇到了同样的问题。我尝试过使用 SQLALCHEMY_POOL_RECYCLE = 45 和 SQLALCHEMY_ENGINE_OPTIONS = {'pool_pre_ping': True},但没有成功。我从 flask_sqlalchemy (def create_engine) 调试了 init 文件,似乎这个处理 sqlalchemy.create_engine 与所有自定义配置,但仍然不知道为什么不起作用。任何帮助都会很棒。问候。附言我正在使用 Flask-SQLAlchemy==2.4.1
-
这里一样,无法弄清楚如何重新连接到数据库,但在 PostgreSQL 上,同样的问题,10-20 分钟后,得到
OperationalError并且无法重新连接。尝试为此编写一个测试以在连接丢失时模拟OperationalError,但由于某种原因无法手动执行。很高兴知道如何使用 flask-sqlalchemy 来做到这一点。
标签: python mysql flask flask-sqlalchemy connection-pooling