Django ORM 在 Postgres DB 上留下空闲连接

Posted

技术标签:

【中文标题】Django ORM 在 Postgres DB 上留下空闲连接【英文标题】:Django ORM leaves idle connections on Postgres DB 【发布时间】:2017-09-01 22:04:54 【问题描述】:

最近由于数据库连接错误,我的Django应用经常崩溃:

OperationalError: FATAL:  sorry, too many clients already

当我进入应用程序数据库时,我看到确实有近 100 个打开的连接,都具有相同的查询(由 Django ORM 执行)并且都处于 idle 状态。

我一直在手动执行SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE state = 'idle';,但我对为什么会发生这种情况感到困惑。任何人都可以了解这里发生的事情吗?

我的 Django 数据库设置没有偏离默认设置(我没有定义 CONN_MAX_AGE 或任何类似性质的东西)。

是什么原因造成的?我没有做任何高级 Django 查询。这可以通过 Django 设置或一些 PostgreSQL 配置来解决吗?任何建议表示赞赏。

【问题讨论】:

试着把它放到 django IRC 频道 你使用的是哪个 Django 版本? @raiderrobert on Django 1.10.5 【参考方案1】:

如果您尚未定义 CONN_MAX_AGE 并且您没有使用任何第三方池程序 - 那么这一定是您的代码或您正在使用的库中的某个问题。 Django 默认打开和关闭每个请求的数据库连接。您在pg_stat_activity 中看到空闲连接这一事实并不意味着存在死锁,而是意味着某些东西已经打开了这些连接并且没有关闭它。

我首先要确定这些连接是否真的来自 Django,例如重新启动应用程序并查看它如何影响pg_stat_activity。如果您确认,然后检查您是否没有混合任何异步或多处理代码,从而留下悬空的线程/进程。

【讨论】:

【参考方案2】:

显然你没有断开连接。在查询完成后使用db.close_connection() 会有所帮助。另外,如果我把CONN_MAX_AGE 做对了一些短值可能会有所帮助。并考虑使用一些会话池,例如 pgbouncer 用于 django 连接。这样,如果您有太多连接,它将等待(或重用以前的,取决于配置),而不是因错误而中止执行...

更新:解释我为什么提出它

from docs

每个线程都维护自己的连接,你的数据库必须支持 至少与工作线程一样多的同时连接数。

所以如果你有更多的线程然后 postgres max_connections,你会得到提到的错误。如果 CONN_MAX_AGE 没有通过,每个线程都可以重用连接。您的设置为 0,因此应在查询完成后关闭连接,但您会看到 100 个空闲连接。所以他们没有关闭。大量的连接意味着它们也没有被重用(逻辑:如果你有 100 个并行查询,它们不会都是空闲的,如果你有这么多,它们不会被重用 - 打开新的)。所以我认为 django 并没有像承诺的那样关闭它们 - 所以 CONN_MAX_AGE 设置为 0 在你的代码中不起作用。所以我建议使用db.close_connection() 来强制断开连接并将 CONN_MAX_AGE 设置为一些小的值可以改变行为。

【讨论】:

我理解连接池的概念,但这个应用程序还没有达到需要引入 3rd 方库来优化数据库使用的规模。我也不喜欢超越 Django 来管理查询的想法(即手动调用 db.close_connection())。 关于CONN_MAX_AGE:您知道是否有特定原因将该值设置为非默认值是必要的,以及为什么在这种情况下它可能是解决方案? 我编辑并解释了为什么我认为将 CONN_MAX_AGE 设置为较小的值会有所帮助。 BTW 连接池从 1.9 开始工作 - 你有更高版本吗?【参考方案3】:

最好的猜测没有更多细节,但如果是同一个查询,而且它们都是空闲的,感觉就像你在做某种异步编程,你遇到了死锁,特别是你的死锁正在显现自身在 db 连接中变得饱和。

【讨论】:

我明白了,谢谢你的提示。我将研究如何检测死锁,看看是否发生了这种情况。 我在我的应用程序中遇到了同样的问题。我尝试将多线程更改为非多线程方法,从而解决了问题。所以我正在寻找以异步方式(Postgresql DB)插入/更新数据库记录的方法。 @glifchits 你有什么发现或好的解决方案吗?

以上是关于Django ORM 在 Postgres DB 上留下空闲连接的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 django ORM 在 postgres 中仅选择日期部分

惯用/快速 Django ORM 检查 mysql/postgres 上是不是存在

django中所有URL的编程错误,postgres在db中找不到表?

在 django 的 postgres db 中将 json 保存为数组

尝试使用 django 从 postgres DB 中按顺序获取下一个值

Django 测试因 InternalError 失败:没有这样的保存点。 DB:Postgres,通过 mysql