害 关于 Flask-SQLAlchemy"数据库连接不可用的“问题困扰了好久,再详细发一下,求教如何解决

2019-11-24 17:46:32 +08:00
 Raul7

首先,介绍下我的项目:Flask+Flask-SQLAlchemy,相关配置如下:

# config.py
MYSQL_URL = 'mysql+mysqlconnector://xxx/db_name'
DEBUG = True
SQLALCHEMY_ECHO = True
SQLALCHEMY_DATABASE_URI = MYSQL_URL
SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_POOL_RECYCLE = 3000
SQLALCHEMY_ENCODING = "utf8mb4"
# application.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
......
self.config.from_pyfile('config.py')
db.init_app(self)

我现在的功能是:前面的功能一切正常,数据库增删改查也正常,随后进入一个扫描过程,是一个第三方的扫描工具,扫描完成后生成一串数据量很大的扫描结果( json 串),然后我循环这个 json 串,拿出里面的 ip ( ip 数量很多),然后在循环里根据 ip 查询其 id,就这个过程报异常:

(mysql.connector.errors.OperationalError) MySQL Connection not available

大概代码如下:

 for result in nminfo['scan'].values():
 	if result['status']['state'] == "up":
 		ip = result['addresses']['ipv4']
        host_os = "xxx"
	# 位置 1
        host_assets_id = db.session.query(HostAsset.host_id).filter(HostAsset.host_ip == ip).first()
        if host_assets_id:
            query_host_id = host_assets_id[0]
            # 位置 2
            HostAsset.query.filter_by(host_id=query_host_id).update({'host_os': host_os})
            HostAssetsHistory.query.filter_by(host_id=query_host_id,                     task_stream_id=self.task_stream_id).update({'host_os': host_os})
            db.session.commit()
        else:
            pass

这个扫描过程,当这个扫描数据比较少的时候,扫描完成的时间就比较短。经过测试,扫描时间短的时候,不会报异常,程序正常跑完。但是当这个扫描的数据量大的时候,待扫描完成,查询数据库就报如上异常。

很奇怪,感觉是不是:扫描时间长,扫描过程与数据库没有交互,自动与数据库断开连接了?

我的 mysql 相关配置如下图:

3646 次点击
所在节点    Python
15 条回复
CallMeReznov
2019-11-24 21:48:56 +08:00
你的 close 呢?
Raul7
2019-11-24 22:57:52 +08:00
@CallMeReznov 没有 close Flask-SQLAlchemy 不是自动 close 的吗?
vZexc0m
2019-11-25 09:07:30 +08:00
试试把 ip 全部循环之后用 IN 进行查询呢!条件允许的话可以添加上索引。
Eds1995
2019-11-25 09:43:54 +08:00
加这个参数
SQLALCHEMY_ENGINE_OPTIONS = {
"pool_pre_ping": True,
"pool_recycle": 300,
}
Eds1995
2019-11-25 09:45:04 +08:00
增加 idle_timeout 时间
lbfeng
2019-11-25 09:55:09 +08:00
neoblackcap
2019-11-25 10:03:32 +08:00
request 对象泄露了被,没有被正确析构,所以导致数据库连接没有正确返回连接池
Raul7
2019-11-25 10:48:24 +08:00
@neoblackcap 老哥 你说的这个是什么意思?如何解决呢?
Raul7
2019-11-25 10:49:16 +08:00
@lbfeng 是的 问题类似 但是网上的方法我都试了下 都不行
Latin
2019-11-25 11:29:51 +08:00
SQLALCHEMY_TRACK_MODIFICATIONS = False
SQLALCHEMY_RECORD_QUERIES = True
SQLALCHEMY_POOL_SIZE = 1024
SQLALCHEMY_POOL_TIMEOUT = 90
SQLALCHEMY_POOL_RECYCLE = 3
SQLALCHEMY_MAX_OVERFLOW = 1024
这个配置服务跑了一年也没挂过 自己看下文档调下配置
Ccob
2019-11-25 11:36:11 +08:00
neoblackcap
2019-11-25 14:35:56 +08:00
@Raul7 你资源泄露了,Flask-SQLAlchemy 将 scoped_session 绑在 request 对象上,request 对象的生命周期结束了,那么就会调用对应的钩子函数,对 scoped_session 对象进行析构。那么数据库连接自然就会返回连接池。
你会出现这样的情况,要不就是 request 对象没有被正确结束,比如抛异常了,没有处理。或者你进行的任务实在是太长了,你的 request 对象一直没有析构(比如你在 celery 里面用了,但是 session 却又是用 request 绑定的)

你可以自己先排查一遍看看,反正绝大多数情况都应该是资源泄露引起的。
lolizeppelin
2019-11-25 17:33:30 +08:00
在 pool 代码里加日志

从 pool 里取出 connection 的时候打印一条
还回去的时候打印一条

这不就知道哪次没还回去了么?

打日志打日志打日志
Raul7
2019-11-25 18:09:11 +08:00
@neoblackcap @lolizeppelin get 谢谢老哥们
我今天在扫描过程结束以后,db.session.close()了一下,然后程序正常了。哭了
linlance
2019-11-29 11:15:10 +08:00
哎,我都放弃 Flask 了,太多小插件需要自己弄了,简洁优美,但是弄完了,最后也快变成个 Django 了,耦合度还高。。
我转 Django 了,有个个人项目,开发了两年了,还没第一版出来。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/622658

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX