MySQL-DBA 的保命技能

2023-03-24 14:36:17 浏览数 (2)

背景

作为一个 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 它现在有管理口可以用了。


最后

都到这里了,是时候图穷匕见了!

0 人点赞