解决GreatSQL连接数爆满的3种应急之法

3周前发布 gsjqwyl
15 0 0

解决GreatSQL连接数被占满的3种应急处理办法

背景

在使用数据库的过程中,偶尔会出现数据库连接数大幅上升的情况,最严重的情形是连接数被完全占满,此时root用户都无法获取连接,导致无法登录数据库。这种情况下,无法通过登录数据库来杀掉相关数据连接,会对数据库的稳定性产生影响。接下来将详细阐述这类故障的处理方式。

场景复现

  1. 设置max_connections为500
greatsql> SET GLOBAL max_connections=500; 
Query OK, 0 rows affected (0.00 sec)
greatsql> SHOW variables LIKE '%max_connections%';
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| max_connections        | 500   |
+------------------------+-------+
1 rows in set (0.01 sec)
  1. 用sysbench模拟并发连接
    准备测试数据:
$ sysbench oltp_read_write --mysql-host=127.0.0.1 --mysql-port=3306 --mysql-user=yourusername --mysql-password=yourpassword --mysql-db=sysbench_test --tables=10 --table-size=10000 prepare

执行测试:

$ sysbench oltp_read_write --mysql-host=127.0.0.1  --mysql-port=3306 --mysql-user=yourusername --mysql-password=yourpassword --mysql-db=sysbench_test --tables=10 --table-size=10000 --time=600 --threads=500 --report-interval=10 run
  1. 尝试登录数据库报错
$ /greatsql/svr/greatsql/bin/mysql -h127.0.0.1 -uroot -p
ERROR 1040 (HY000): Too many connections

场景分析

方案1:利用admin_port处理故障

从GreatSQL 8.0开始,GreatSQL支持在配置文件中配置admin_portadmin_address,这两个参数是静态参数,不支持动态修改。admin_address没有默认值,若不显式开启,GreatSQL不会维护管理接口。admin_port是管理接口连接TCP/IP的端口号,默认值为33062。

注意:若admin_address未设置,admin_port也将无效。
1. 查看配置文件中是否配置了admin_address和admin_port

$cat /greatsql/conf/greatsql.cnf | grep admin
admin_address='127.0.0.1'
admin_port=3806
  1. 使用admin_port和admin_address尝试登录数据库,登录成功
$ /greatsql/svr/greatsql/bin/mysql -h127.0.0.1 -uroot -p -P3806
greatsql > SELECT count(*),User FROM information_schema.processlist GROUP BY 2 ;
+----------+-----------------+
| count(*) | User            |
+----------+-----------------+
|        1 | root            |
|      500 | test_user       |
+----------+-----------------+
1 row in set (0.00 sec)
  1. 使用kill杀掉特定条件的连接
    如果处于业务高峰期,可先使用SET GLOBAL max_connections=[value]临时调大连接数,需注意资源负载情况。以下是查找出语句正在运行且执行时间超过100s、用户为test_user的id并拼装成kill语句的示例,可根据实际场景调整条件:
greatsql> SELECT concat("kill ",id,";") FROM information_schema.processlist 
WHERE info IS NOT NULL  
AND command != 'sleep'
AND time>100
AND USER ='test_user';
方案2:GDB在线关闭TCP SOCKET

前面演示的是较为顺利的情况,但假设未设置admin_addressadmin_port,难道就只能重启数据库了吗?其实不然,GreatSQL默认通过TCP/IP进行网络连接,能否将实例上远程机器请求的部分TCP socket连接杀掉,同时保持数据库进程运行,从而腾出部分连接数供root用户登录呢?
通过查阅资料,gdb attach能满足这一设想:gdb attach是GDB(GNU调试器)的一个命令,用于附加到正在运行的进程,而关闭一个SOCKET只需调用close函数。简单来说就是用gdb attach连接到进程上下文,然后call close($fd)
不过需要注意,gdb attach会暂停目标进程的所有线程。对于生产环境中持续运行的进程(如服务、数据库等),这种暂停可能导致服务中断或超时,且gdb会带来较大性能开销,进程运行速度会显著下降,使用前需谨慎评估。
复现一个连接数打满但未启用admin_addressadmin_port的场景,此时尝试用管理员登录会报错ERROR 1040 (HY000): Too many connections。
1. 通过netstat反查数据库的进程号为18979

$ netstat -nltp | grep 3306
tcp6       0      0 :::3306                 :::*                    LISTEN      18979/mysqld 
  1. 使用lsof找到进程号18979的文件描述,并找到对应的socket
$ lsof -np 18979
COMMAND  PID    USER   FD      TYPE             DEVICE   SIZE/OFF     NODE NAME
mysqld 18979 greatsql  cwd       DIR                8,2       4096  4971025 /greatsql/dbdata/data3306/data
mysqld 18979 greatsql  rtd       DIR                8,2       4096        2 /
mysqld 18979 greatsql  txt       REG                8,2 1241425104  4971271 /greatsql/svr/GreatSQL-8.0.32-27-Linux-glibc2.17-x86_64/bin/mysqld
mysqld 18979 greatsql  mem       REG                8,2      37216   688174 /usr/lib64/libnss_sss.so.2
...
mysqld 18979 greatsql  371u     IPv6           31132193        0t0      TCP 172.17.134.208:mysql->172.17.139.57:40694 (ESTABLISHED)
mysqld 18979 greatsql  372u     IPv6           31132194        0t0      TCP 172.17.134.208:mysql->172.17.139.57:40698 (ESTABLISHED)
mysqld 18979 greatsql  373u     IPv6           31132195        0t0      TCP 172.17.134.208:mysql->172.17.139.57:40700 (ESTABLISHED)
mysqld 18979 greatsql  374u     IPv6           31132196        0t0      TCP 172.17.134.208:mysql->172.17.139.57:40702 (ESTABLISHED)
mysqld 18979 greatsql  375u     IPv6           31132197        0t0      TCP 172.17.134.208:mysql->172.17.139.57:40704 (ESTABLISHED)
mysqld 18979 greatsql  376u     IPv6           31132198        0t0      TCP 172.17.134.208:mysql->172.17.139.57:40706 (ESTABLISHED)
mysqld 18979 greatsql  377u     IPv6           31132201        0t0      TCP 172.17.134.208:mysql->172.17.139.57:40708 (ESTABLISHED)
...

其中NODE NAME有(ESTABLISHED)表示两台主机TCP连接已成功建立。找到对应的FD并记录。
3. 使用gdb连接到进程,并关闭socket连接

$ gdb -p 18979
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-114.el7
Copyright (C) 2013 Free Software Foundation, Inc
....
Loaded symbols for /greatsql/svr/greatsql/lib/mysql/libjemalloc.so
Reading symbols from /lib64/libpthread.so.0...(no debugging symbols found)...done.
$ (gdb) call close(371u)
$1 = 0
$ (gdb) call close(372u)
$1 = 0
....
  1. 查看数据库进程,并再次尝试登录数据库,登录成功
$ ps -ef | grep mysql
greatsql  18979     1 99 13:30 ?        00:48:41 /greatsql/svr/greatsql/bin/mysqld --defaults-file=/greatsql/conf/greatsql.cnf
方案3:预防性设置max_user_connections

以上是出现问题时的紧急处理办法,作为DBA,保障线上稳定性是首要任务,连接数被占满已是较糟糕的情况。前文提到的是GreatSQL 8.0后才支持admin_addressadmin_port作为突发情况的紧急处理方式。但如果是GreatSQL 5.7或更低版本,如何保障生产稳定性呢?
GreatSQL还有一个参数max_user_connections,来看看max_user_connectionsmax_connections的区别:
max_connections:表示允许连接数据库的所有用户的连接数总和
max_user_connections:表示允许单个用户的最大连接数,即并发值

出现故障时,往往是同一个用户频繁申请连接,所以如果将单个用户的最大连接数调整到比最大连接数稍小的值,就能确保管理员账号有足够的连接数来处理突发故障,也能有效减少连接被占满的情况。该参数可以动态调整,通过SET GLOBAL max_user_connections=[value]生效。此外,还可针对特定用户设置:如ALTER USER 'test_user'@'%' WITH MAX_USER_CONNECTIONS 100;

总结

  1. 无论对于5.7还是8.0版本,建议设置max_user_connections以降低连接数被占满的风险。
  2. 对于8.0版本,可以通过配置添加admin_addressadmin_port来启用管理接口,以应对突发情况。
  3. 如果出现连接数被占满且未启用管理端口的情况,可以使用gdb attach在线关闭部分socket,避免数据库重启。但需注意gdb attach对机器性能的开销以及gdb运行时数据库所有线程都会暂停,使用前需评估。
  4. 可以添加对连接数的监控,达到阈值时进行告警,提前介入处理。
  5. 事后应排查连接数被占满的原因,与业务协调优化措施,建议采用线程池等技术提前规避连接数飙升的场景。

Enjoy GreatSQL 😃

关于 GreatSQL

GreatSQL是适用于金融级应用的国内自主开源数据库,具备高性能、高可靠、高易用性、高安全等多个核心特性,可作为MySQL或Percona Server的可选替代,用于线上生产环境,且完全免费并兼容MySQL或Percona Server。

相关链接: GreatSQL社区
Gitee
GitHub
Bilibili

GreatSQL社区:

社区博客有奖征稿详情:https://greatsql.cn/thread-100-1-1.html

image-20230105161905827

技术交流群:

微信:扫码添加GreatSQL社区助手微信好友,发送验证信息加群

image-20221030163217640
© 版权声明

相关文章

暂无评论

暂无评论...