使用 HAproxy 时的 Flask-SQLAlchemy "MySQL server has gone away"

Flask-SQLAlchemy "MySQL server has gone away" when using HAproxy

我使用 Flask 构建了一个小型 python REST 服务,Flask-SQLAlchemy 用于与 MySQL 数据库通信。

如果我直接连接到 MySQL 服务器,一切都很好,完全没有问题。如果我使用 HAproxy(处理 HA/failover,虽然在这个开发环境中只有一个数据库服务器)然后如果应用程序没有足够频繁地与数据库通信,我会不断收到 MySQL server has gone away 错误。

我的 HAproxy 客户端超时设置为 50 秒,所以我认为发生的情况是它切断了流,但应用程序不知道并尝试使用无效连接。

在使用 HAproxy 等服务时是否应该使用设置?

它似乎也不会自动重新连接,但如果我手动发出请求,我会得到 Can't reconnect until invalid transaction is rolled back,这很奇怪,因为它只是我正在拨打的 select() 电话,所以我不认为这是我遗漏的 commit() - 或者我应该在每个基于 ORM 的查询之后调用 commit() 吗?

为了用答案整理这个问题,我将 post 我(认为我)做了什么来解决这些问题。

问题一:HAproxy

  • 将 HAproxy 客户端超时值(全局或在前端定义中)增加到比 MySQL 设置为重置的值更长的值(参见此 interesting and related SF 问题)
  • 或者在 Flask 的 app.config 中设置 SQLALCHEMY_POOL_RECYCLE = 30(在我的例子中,30 小于 HAproxy 客户端超时),这样当数据库初始化时,它会在 HAproxy 切断之前提取这些设置并回收连接他们本身。类似于 this issue on SO.

问题二:Can't reconnect until invalid transaction is rolled back

我相信我通过调整数据库初始化和跨各种模块导入的方式解决了这个问题。我现在基本上有一个模块,它只包含:

  from flask.ext.sqlalchemy import SQLAlchemy
  db = SQLAlchemy()

然后在我的主要 application factory 我只是:

  from common.database import db
  db.init_app(app)

此外,因为我想轻松地自动加载 table 结构,所以我在应用程序上下文中初始化了元数据绑定,我认为正是它干净地处理了 commit() issue/error 我正在获取,因为我相信数据库会话现在在每次请求后都被正确终止。

 with app.app_context():
    # Setup DB binding
    db.metadata.bind = db.engine