Anu*_*raz 42 python mysql connection-pooling flask flask-sqlalchemy
为了测试,我将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')
Run Code Online (Sandbox Code Playgroud)
添加了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)
Run Code Online (Sandbox Code Playgroud)
有了这个,即使在 MySQL 服务器关闭了以前的连接之后,webapp 现在也设法获得新的连接。当我在服务器关闭数据库后立即访问数据库时,它总是正常工作(最多尝试 50 秒后)...我看到同样的错误。
根据文档,(尤其是处理断开连接部分),该pool_pre_ping选项应该在后台仪式中处理这种情况吗?或者我需要在 MySQL 服务器中更改任何其他超时变量吗?
小智 5
我进行了以下设置:
SQLALCHEMY_ENGINE_OPTIONS = {
'pool_size': 10,
'pool_recycle': 60,
'pool_pre_ping': True
}
Run Code Online (Sandbox Code Playgroud)
最近几个月已经停止下跌了...
让我们检查一下手册。来自Flask-SQLAlchemy
配置文档:
\n\n某些数据库后端可能会施加不同的非活动连接超时,这会干扰 Flask-SQLAlchemy\xe2\x80\x99s 连接池。
\n默认情况下,MariaDB 配置为 600 秒超时。这\n通常很难调试,只有生产环境的例外\n例如
\n\n\n\n
2013: Lost connection to MySQL server during query.如果您使用的后端(或预配置的数据库即服务)\n具有较低的连接超时,建议您将\n设置
\nSQLALCHEMY_POOL_RECYCLE为小于后端\xe2\x80\x99s 超时的值。
问题中引用的脚本显示其 MySQL 之间的差异
timeout-configs ( wait_timeout, net_read_timeout) 及其 SQLAlchemy
( pool_recycle, pool_timeout) 和 Flask-SQLAlchemy
超时 ( SQLALCHEMY_POOL_RECYCLE, SQLALCHEMY_POOL_TIMEOUT)。
当您注意到可能会发生变化的重复信息时,请考虑用不太可能发生变化的抽象内容来替换它。这就是软件开发的“不要重复自己”(DRY)原则。
\n我们可以通过使用DevConfig帮助器类来协调应用程序中的数据库连接配置常量来实现此抽象。通过这种方法,我们将配置分配给静态属性并引用它们,以便不存在冲突的超时期望。这是一个实现:
import os\nfrom flask import Flask\nfrom flask_sqlalchemy import SQLAlchemy as _BaseSQLAlchemy\n\n# Coordinate DevConfig with SQLAlchemy and Flask-SQLAlchemy (don\'t repeat yourself!)\n\nclass DevConfig():\n SQLALCHEMY_POOL_RECYCLE = 35 # value less than backend\xe2\x80\x99s timeout\n SQLALCHEMY_POOL_TIMEOUT = 7 # value less than backend\xe2\x80\x99s timeout\n SQLALCHEMY_PRE_PING = True\n SQLALCHEMY_ENGINE_OPTIONS = {\'pool_recycle\': SQLALCHEMY_POOL_RECYCLE, \'pool_timeout\': SQLALCHEMY_POOL_TIMEOUT, \'pool_pre_ping\': SQLALCHEMY_PRE_PING}\n DEBUG = True\n # SERVER_NAME = \'127.0.0.1:5000\'\n SQLALCHEMY_DATABASE_URI = os.getenv(\'SQLALCHEMY_DATABASE_URI_DEV\')\n SQLALCHEMY_TRACK_MODIFICATIONS = False\n\nclass SQLAlchemy(_BaseSQLAlchemy):\n def apply_pool_defaults(self, app, options):\n super(SQLAlchemy, self).apply_pool_defaults(app, options)\n options["pool_pre_ping"] = DevConfig.SQLALCHEMY_PRE_PING\n# options["pool_recycle"] = 30\n# options["pool_timeout"] = 35\n\ndb = SQLAlchemy()\n\nconfig = dict(\n dev=DevConfig,\n)\n\napp = Flask(__name__, instance_relative_config=True)\napp.config.from_object(config[\'dev\'])\n\n# INIT DATABASE\ndb.init_app(app)\nwith app.app_context():\n db.create_all()\nRun Code Online (Sandbox Code Playgroud)\n如果您愿意,您可以检查我所做的更改的差异: diffchecker.com/Q1e85Hhc
\n如果您想了解有关软件设计原理的更多信息,请查看上面链接的维基百科页面上的参考资料。
\n