psycopg2.OperationalError:SSL SYSCALL 错误:在 Flask/SQLAclemy/Celery + PostgreSQL 应用程序上检测到 EOF

Gre*_*reg 6 python postgresql sqlalchemy celery flask

我有一个用 Flask+SQLALchemy+Celery 编写的应用程序,RabbitMQ 作为代理,数据库是 PostgreSQL (PostgreSQL 10.11 (Ubuntu 10.11-1.pgdg16.04+1) on x86_64-pc-linux-gnu,由 gcc 编译( Ubuntu 5.4.0-6ubuntu1~16.04.12)5.4.0 20160609,64位)。数据库托管在 DigitalOcean(1 个 CPU、2Gb RAM)中。所有应用程序工作人员(flask 或 celery)都在 Supervisor 中启动。

在我连接数据库的项目中,我使用flask_sqlalchemy包,如下所示:

from flask_sqlalchemy import SQLAlchemy
from flask import Flask

# Init 
app = Flask(__name__)

# Create the connection to database
db = SQLAlchemy(app)
Run Code Online (Sandbox Code Playgroud)

我在 Flask 应用程序中编写了一些登录,对其进行了测试,然后将其复制到 Celery 项目(其中数据库连接是相同的)。现在我的示例芹菜任务如下所示:

@celery.task(name='example_task', queue='default')
def example_task(payload):
    """ Some logic here """
    data = ExampleModel.query.filter(ExampleModel.id == payload["id"]).first()

    """ Some another app logic """
    db.session.add(SecondModel(payload))
    db.session.commit()
    
    return {"success": True}
Run Code Online (Sandbox Code Playgroud)

问题是当我在笔记本电脑上运行应用程序时,一切正常,没有错误。当我将我的应用程序上传到 VPS 上并且没有太多用户时,一切都还好。但一段时间后,当有 30 多个用户同时调用此 example_task 时,有时在从数据库中选择一些数据的非常简单的查询中开始定期出现错误:

  File "/venv/lib/python3.6/site-packages/sqlalchemy/engine/base.py", line 1193, in _execute_context
    context)
  File "/venv/lib/python3.6/site-packages/sqlalchemy/engine/default.py", line 509, in do_execute
    cursor.execute(statement, parameters)
psycopg2.OperationalError: SSL SYSCALL error: EOF detected

The above exception was the direct cause of the following exception:

sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) SSL SYSCALL error: EOF detected
 [SQL: 'SELECT example_model.id AS example_model_id, example_model.key AS example_model_key
 \nFROM example_model \nWHERE example_model.id = %(id_1)s \n LIMIT %(param_1)s'] [parameters: {'id_1': 2, 'param_1': 1}] (Background on this error at: http://sqlalche.me/e/e3q8)
Run Code Online (Sandbox Code Playgroud)

有时,但非常罕见,我在日志中看到此错误:

psycopg2.OperationalError: SSL error: decryption failed or bad record mac
Run Code Online (Sandbox Code Playgroud)

我编写了一个示例异常装饰器来处理错误(例如任何错误,而不仅仅是 SQLAlchemy 错误),在它捕获错误后,我执行 db.session.rollback()

def exception_log(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except Exception as err:
            # Do the rollback
            db.session.rollback()

            # Call function again
            return func(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

但这对我没有帮助,因为是的,它重新加载了数据库的连接,然后功能工作正常,但是应用程序开始工作得越来越慢,在某些时候我应该在主管中重新加载工作人员。我在 PostgreSQL 中看到很多空闲连接,我将空闲事务超时设置为 5 分钟,但没有帮助。

SET SESSION idle_in_transaction_session_timeout = '5min';
Run Code Online (Sandbox Code Playgroud)

我不知道下一步该做什么,因为现在唯一有帮助的解决方案是每当我看到应用程序运行速度越来越慢时,就在主管中重新加载应用程序工作人员。

ssh*_*how 12

我在使用托管 Postgres 数据库服务时遇到了同样的问题,似乎时不时就会断开连接。

\n
\n

psycopg2.OperationalError:SSL SYSCALL 错误:检测到 EOF

\n
\n

值得庆幸的是,SQLAlchemy 似乎有一些标志可以帮助解决这个问题。

\n

传递pre_ping=Truecreate_engine,它将检查所有池连接,然后再将它们用于实际查询。

\n
\n

悲观方法是指在每次连接池检出开始时对 SQL 连接发出测试语句,以测试数据库连接是否仍然可行。通常,这是一个简单的语句,例如 \xe2\x80\x9cSELECT 1\xe2\x80\x9d,但也可以使用一些特定于 DBAPI 的方法来测试连接的活跃性。

\n
\n
engine = create_engine("mysql+pymysql://user:pw@host/db", pool_pre_ping=True)\n
Run Code Online (Sandbox Code Playgroud)\n

https://docs.sqlalchemy.org/en/13/core/pooling.html#disconnect-handling-pessimistic

\n