背景
作为一个 MySQL-DBA ,我自然是希望它平稳运行不要出事。一旦出事不可避免的就是连接上 MySQL 看一下发生了什么。
但是!有一种场景我们可能根本就没能力连接上 MySQL;比如说连接用完了,当我们尝试连接时就会收到如下报错。
代码语言:javascript复制mysql -uroot
ERROR 1040 (HY000): Too many connections
本文就是讲怎么在这种情况下做到,挽狂澜于既倒,扶大厦之将倾!
源码相关的知识
这节可以说是我们处理这种情况的理论指导吧,如果你想看操作,那可以跳过这一节。对后面的实操没有影响。
1. mysqld.cc 这个文件里定义了它,它是全局的不是 thread-local 变量。
代码语言:javascript复制ulong max_connections, max_connect_errors;
2. 主线程在启动时会解析配置,并设置 max_connections 的值。
3. 主线程的线程 id 一定是 1 。
就这三点我们就可以破局了,就是这么的简单。
实操
1. 确认现在是连接用完了
代码语言:javascript复制mysql -uroot
ERROR 1040 (HY000): Too many connections
2. 确认 MySQL 的进程的 PID
代码语言:javascript复制ps -ef | grep mysqld
mysql 843877 843800 3 19:48 pts/60 00:00:02 /usr/local/mysql/bin/mysqld --defaults-file=/usr/local/mysql/my.cnf
3. 用 gdb attach 上去
代码语言:javascript复制gdb attach 843877
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Missing separate debuginfos, use: dnf debuginfo-install glibc-2.34-49.el9.x86_64 libffi-3.4.2-7.el9.x86_64 libgcc-11.3.1-4.el9.x86_64 libselinux-3.3-2.el9.x86_64 libstdc -11.3.1-4.el9.x86_64 libxcrypt-4.4.18-3.el9.x86_64 openssl-libs-3.0.7-2.el9.x86_64 p11-kit-0.24.0-4.el9.x86_64 pcre2-10.37-3.el9.1.x86_64 sssd-client-2.6.1-1.el9.x86_64 systemd-libs-250-11.el9.x86_64 zlib-1.2.11-35.el9.x86_64
--Type <RET> for more, q to quit, c to continue without paging--
0x00007fcee95429bf in poll () from /lib64/libc.so.6
(gdb)
4. 确认线程信息
代码语言:javascript复制(gdb) info threads
Id Target Id Frame
* 1 Thread 0x7fceea07e500 (LWP 843877) "mysqld" 0x00007fcee95429bf in poll () from /lib64/libc.so.6
2 Thread 0x7fced74f5640 (LWP 843881) "ib_io_ibuf" 0x00007fcee949c39a in __futex_abstimed_wait_common () from /lib64/libc.so.6
3 Thread 0x7fced6411640 (LWP 843882) "ib_io_log" 0x00007fcee949c39a in __futex_abstimed_wait_common () from /lib64/libc.so.6
... ... 这里的 id 就是线程 ID
41 Thread 0x7fce9c5f6640 (LWP 844005) "connection" 0x00007fcee9542abe in ppoll () from /lib64/libc.so.6
5. 切到线程 1 。(一般来讲我们 attach 上去之后就是在线程 1 上的,但是为了保证不要搞错了,我们在这里还是强制切一下。)
代码语言:javascript复制(gdb) thread 1
[Switching to thread 1 (Thread 0x7fceea07e500 (LWP 843877))]
#0 0x00007fcee95429bf in poll () from /lib64/libc.so.6
6. 检查当前 max_connections 的值。(为了方便造场景我把它设置成了 1 ,所以下面这个 p 指令看到的 1 是刻意的。)
代码语言:javascript复制(gdb) p max_connections
$1 = 1
7. 设置 max_connections 的值到 8848 个
代码语言:javascript复制(gdb) set max_connections = 8848
(gdb)
8. 退出 gdb
代码语言:javascript复制(gdb) quit
A debugging session is active.
Inferior 1 [process 843877] will be detached.
Quit anyway? (y or n) y
Detaching from program: /usr/local/mysql-8.0.32/bin/mysqld, process 843877
[Inferior 1 (process 843877) detached]
9. 现在应该可以连接上去了
代码语言:javascript复制mysql -uroot
Welcome to the MySQL monitor. Commands end with ; or g.
Your MySQL connection id is 12
Server version: 8.0.32-debug Source distribution
Copyright (c) 2000, 2023, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or 'h' for help. Type 'c' to clear the current input statement.
mysql> show global variables like 'max_connections';
----------------- -------
| Variable_name | Value |
----------------- -------
| max_connections | 8848 |
----------------- -------
1 row in set (0.01 sec)
可以看到 max_connections 是我们用 gdb 设置的 8848 这个值了,说明我们用 gdb 确实是设置对了。
如何避免连接用完的情况出现
1. 给 max_connections 配置一个适当的值
2. 做好权限控制,默认 root 是能力在 max_connections 发生时建立一个紧急连接到数据库;前提是你的应用不要用 root 权限连接数据库,不然这个保命的连接有可能被应用程序也占了。
3. 升级到 MySQL-8.0.x 它现在有管理口可以用了。
最后
都到这里了,是时候图穷匕见了!