我正在使用连接到 MySQL 8.0.30 数据库的 Django 4.2。服务器是 nginx ,带有gunicorn(3个工作人员)并使用WSGI。
我正在为需要异步运行的函数运行 asyncio,因为它由异步 API 代理使用,但在这里我只是直接从 View 调用,因此它是直接且短暂的:
from django.db import connection
import asyncio
example_object = asyncio.run(make_query(name))
async def make_query(request, name):
object = await ModelExample.objects.filter(name=name).afirst()
return object
我在 afirst() 查询执行时遇到以下错误:
[4031] 由于不活动,客户端已被服务器断开连接。请参阅 wait_timeout 和 Interactive_timeout 以配置此行为
最初代码工作正常,错误仅在几个小时(可能 8 小时)后开始。我可以通过重新启动(nginx)错误来临时修复它。这是一个低流量网站,因此该功能很可能每天只执行一次。
因为它需要 8 小时不活动,所以复制或调试它并不容易。
我尝试过的:
Django 层:
根据我的理解,Django 总是打开一个连接,执行一个查询,然后关闭一个连接。 这也应该发生在 WSGI 中,但连接空闲表明情况并非如此。 所以我尝试了:
- 在 asyncio.run 之前添加 close_old_connections()
- 在asyncio.run之后添加connection.close()
- 将
CONN_HEALTH_CHECKS
选项设置为True,希望“如果健康检查失败,将重新建立连接而不会导致请求失败” - 在 Django 设置文件中将
CONN_MAX_AGE
从默认的 0 更改为“None”,根据 Django 文档,这意味着无限的持久数据库连接。
没有任何效果。
如果这是 Django 问题,那么我最后的猜测是在使用 MySQL 时“afirst()”(在 Django 4.1 中添加)的错误。
MySQL层:
发现一些报告将此问题归因于 MySQL(也发生在 Wordpress 和 PHP 应用程序中),所以我尝试了:
- 增加 MySQL 配置文件中的 wait_timeout 值和 interactive_timeout 变量。
SHOW VARIABLES
命令显示它们当前确实设置为 31536000。 - Mysql 8.0.32 release notes这里似乎提到了这个问题:
“每当连接因不活动而终止时,线程池插件仅打印一条有关连接超时的通用消息;这通常会使分析此类超时变得比必要的更加困难。新的 INFO_LEVEL 消息清楚地表明连接已超时由于线程池中不活动而被终止,以及用于做出此确定的超时值。(错误#34767607)“
所以我更新了 MySQL,希望能获得更多信息,如果我这样做了,我会告诉你的。
请让我知道您对如何调试此问题的想法、想法或建议! 提前致谢。
最佳答案
为 future 使用 DigitalOcean 时可能遇到相同问题的人解答此问题。
看起来配置 MySQL 的初始方法是正确的,但它实际上并未应用于数据库。如果您使用的是 DigitalOcean,通过 SSH 将配置应用到 Droplet 并不对应于数据库集群中的实际配置。
要解决此问题,您需要使用 DigitalOcean 的 API 来配置数据库。对变量进行以下更改似乎可以解决我的问题:
- connect_timeout 为 60
- interactive_timeout 为 604800
- wait_timeout 为 2147483
- net_read_timeout 为 120
使用此配置,Django 的异步功能应该可以在低流量网站中正常工作。 Ofc 可能会有所不同,具体取决于您的设置和要求。
关于Django/Mysql异步错误 “The client was disconnected by the server because of inactivity”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76567076/