我们有一个 Django 应用程序,它必须定期使用第三方 API 来为一组用户获取大量数据。这些任务执行得很好并且完成了它们的目的。但是一段时间后,我们开始从 postgres 收到太多的连接错误
FATAL:抱歉,已经有太多客户了
信息
该项目是 dockerized 并且所有组件都在单独的容器中运行,包括应用程序和数据库(postgres)。周期性任务由 Dramatiq 执行并由 periodiq 调度。我们还使用 redis 作为系统代理。
我尝试了各种解决方法来使其停止,但它们都没有奏效,包括 SO 中提出的各种解决方案。
尝试 1
我在每次任务执行connection.closes()
之前和之后都使用过,以确保工作人员没有打开任何幽灵连接。
尝试 2
添加任务限制器以限制给定时间的活动连接数并防止数据库不堪重负。虽然这个解决方案显然没有服务于我们实现的实际范围,但它降低了任务执行的性能它对解决问题没有帮助。
尝试 3
增加 Postgres 的池限制。正如这里所建议的,我添加了一个自定义配置文件以增加可用池。这产生了效果,但它只是推迟了错误的显示,并没有避免这种情况按预期发生。我什至达到了 10K 连接的非常高的限制(默认为 10)。我在这里发布配置文件以防万一。
注意该应用程序在具有 24 个内核和 128GB RAM 的服务器上运行,并且在执行任务时使用的资源不超过 1%。
max_connections = 100000
shared_buffers = 64GB
尝试 4
我已将pgpool插入到项目中,以便对数据库的请求进行排队。这可以防止数据库不堪重负,但它不是一个实用的解决方案,因为它导致数据库连接永远等待并且这使得数据库也可用。
尝试 5
使用CONN_MAX_AGE=0
参数来防止 Django 创建持久连接。那也没有任何影响。
尝试 6
尝试使任务在原子连接块上运行。这似乎也没有帮助。
我认为在 Dramatiq 工作程序上以并行线程执行任务的方式导致连接保持打开但空闲。我尝试从 Dramatiq 和 periodiq 容器手动关闭连接,但这在修复连接池问题方面几乎没有效果。
我尝试了在 SO 上找到的所有变体。
# Command 1
connection.close
# Command 2
for c in connections.all():
c.close()
# Command 3
close_old_connections()