埋头工作
专职养娃

Django出现“Too many connections”错误 mysql数据库出现too many connections导致django项目错误

一、错误原因

这个错误是mysql数据库上报的,django的ORM在进行数据库连接时,数据库连接数超过阈值,导致各种请求都会失败,具体的效果会是

  1. 所有的请求都会是500错误
  2. django内置admin页面打开也显示too many connections错误
  3. 归根结底就是django的数据库连接配置和mysql的配置配合的问题

二、初步排查

一般普通的django项目的连接数很难会出现这种问题,如果真的出现问题,最大的可能性就是你的django项目代码存在缺陷,比如,明明你可以进行批量操作的语句,非要做单条执行;又或者你在每一个请求开始的时候都进行了大量的update操作等等。我们可以按照下面的方式进行排查

1、登录mysql数据库查看连接情况 show processlist;

show processlist;

查看哪些连接时间过长,并且info语句的内容基本相同,通过sql语句反向推测出django的ORM语句,定位到具体的代码段进行优化。

2、登录mysql查看mysql数据库的最大连接数

  • 查看mysql数据库配置连接数 max_connections
    mysql> show variables like '%conn%';
    +-----------------------------------------------+--------------------+
    | Variable_name                                 | Value              |
    +-----------------------------------------------+--------------------+
    | character_set_connection                      | utf8mb4            |
    | collation_connection                          | utf8mb4_0900_ai_ci |
    | connect_timeout                               | 10                 |
    | disconnect_on_expired_password                | ON                 |
    | init_connect                                  |                    |
    | max_connect_errors                            | 100                |
    | max_connections                               | 500                |
    | max_user_connections                          | 0                  |
    | mysqlx_connect_timeout                        | 30                 |
    | mysqlx_max_connections                        | 100                |
    | performance_schema_session_connect_attrs_size | 512                |
    +-----------------------------------------------+--------------------+
    11 rows in set (0.11 sec)
  • 查看使用数
    mysql> show global status like '%conn%';
    +-------------------------------------------------------+---------------------+
    | Variable_name                                         | Value               |
    +-------------------------------------------------------+---------------------+
    | Aborted_connects                                      | 0                   |
    | Connection_errors_accept                              | 0                   |
    | Connection_errors_internal                            | 0                   |
    | Connection_errors_max_connections                     | 0                   |
    | Connection_errors_peer_address                        | 0                   |
    | Connection_errors_select                              | 0                   |
    | Connection_errors_tcpwrap                             | 0                   |
    | Connections                                           | 915                 |
    | Locked_connects                                       | 0                   |
    | Max_used_connections                                  | 73                  |
    | Max_used_connections_time                             | 2022-07-11 10:14:36 |
    | Mysqlx_connection_accept_errors                       | 0                   |
    | Mysqlx_connection_errors                              | 0                   |
    | Mysqlx_connections_accepted                           | 0                   |
    | Mysqlx_connections_closed                             | 0                   |
    | Mysqlx_connections_rejected                           | 0                   |
    | Performance_schema_session_connect_attrs_longest_seen | 126                 |
    | Performance_schema_session_connect_attrs_lost         | 0                   |
    | Ssl_client_connects                                   | 0                   |
    | Ssl_connect_renegotiates                              | 0                   |
    | Ssl_finished_connects                                 | 0                   |
    | Threads_connected                                     | 32                  |
    +-------------------------------------------------------+---------------------+
    22 rows in set (0.15 sec)

    三、优化处理

    1、优化代码

    将django定位到的代码段进行ORM操作优化,将for循环类的操作全都改成批量操作

    2、修改mysql配置文件

  • 临时修改,具体数值自己根据服务器的性能决定,数据库重启后失效
    set GLOBAL max_connections=1000; # 总的最大连接数
    set GLOBAL max_user_connections=500; # 每个账号最大的连接数
    set GLOBAL wait_timeout=500; # 最大空闲时间,会强制释放sleep的链接
    set GLOBAL interactive_timeout=500; # 最大检测时间
  • 永久修改,修改配置文件
    • 查看配置文件路径ps aux|grep mysql|grep ‘my.cnf’ 和 mysql –help|grep ‘my.cnf’
    • 修改配置文件
    • 重启mysql服务
      //查看配置文件的路径
      [root@api etc]# ps aux|grep mysql|grep 'my.cnf'
      //如果没有输出,就查看默认路径配置
      [root@api etc]# mysql --help|grep 'my.cnf' 
                    order of preference, my.cnf, $MYSQL_TCP_PORT,
      /etc/my.cnf /etc/mysql/my.cnf /usr/etc/my.cnf ~/.my.cnf 
      [root@api etc]# vi /etc/my.cnf
      //在[mysqld]下增加配置
      max_connections=500
      max_user_connections=500
      wait_timeout=600
      interactive_timeout=600
      //保存,重启
      [root@api etc]systemctl restart mysqld
      [root@api etc]systemctl status mysqld

      3、django数据库配置和mysql配合

      django的数据库配置中除了数据库连接的信息之外,还提供了一个额外的参数——"CONN_MAX_AGE"

      默认: 0
      一个数据库连接的寿命,以秒为整数。使用 0 在每次请求结束时关闭数据库连接——这是 Django 的历史行为,使用 None 则是无限的持久连接。
      链接

通俗讲就是一个django和mysql的连接的最大空闲时间,那么对应数据库中的配置就是 wait_timeout 和 interactive_timeout两个参数。

正确的值配置方式应该是
wait_timeout>=interactive_timeout>django中的CON_MAX_AGE

4、修改django的最大连接数配置(其他论坛帖子的解释,没有把问题将清楚,可以参考一下)

在数据库中,有一个参数 CONN_MAX_AGE , 它用来配置 Django 跟数据库的持久化连接。这一项的默认值是0。 Django 中数据库连接的逻辑是,每一个请求结束都会关闭当前的数据库连接。这意味着每来一个新的请求, Django 都会创建一个新的数据库连接。

当配置此项的值时,需要根据参考数据库的 wait_timeout 配置,建议不要大于 wait_timeout 。此外此项还有 None。如果配置为 None,就意味着不限制连接时长。

如果没有配置 CONN_MAX_AGE 就会出现数据库连接数太多,抛出 too many connections 错误的问题,原因就是上面所说的,所以当并发访问量过大来不及关闭连接时,会导致连接数不断增多。

但是需要注意的是,如果你采用多线程的方式部署项目,最好不要配置 CONN_MAX_AGE。因为如果每一个请求都会使用一个新的线程来处理的,那么每个持久化的连接就达不到复用的目的。另外一个经验就是,如果使用gevent 作为worker来运行项目的话,那么也建议不配置 CONN_MAX_AGE。因为 gevent 会给 Python 的 thread(线程模块)动态打补丁(patch),这回导致数据库连接无法复用

此段参考《Django 项目部署上线后,数据库连接数太多,抛出too many connections错误》

# CONN_MAX_AGE的值一定要小于数据库配置的最大连接数
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'xxx',
        'USER': 'xxx',
        'PASSWORD': 'xxx',
        'HOST': 'xxx',
        'PORT': '3306',
        'CONN_MAX_AGE': 5*60,
    }
}

至此,可以解决绝大部分的场景错误

赞(2) 打赏
本人经小丙张嘎纯手工打字生成,未经许可不得转载知识点滴:小丙张嘎blog » Django出现“Too many connections”错误
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏