• GreatSQL连接数被打满的三种紧急解决方案

GreatSQL连接数被打满的三种紧急解决方案

2025-06-06 07:00:10 栏目:宝塔面板 8 阅读

背景

使用数据库时,偶尔会出现数据库连接数飙升的场景,最严重的情况是连接打满,root 用户无法获取到连接,登陆数据库失败。这时候无法登录数据库kill 掉相关的数据连接,影响数据库的稳定性。下面将对这类的故障的处理进行详述。

场景复现

  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)

2. 使用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

3. 尝试登录数据库报错

$ /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也将无效。

  • 查看配置文件是否配置了admin_addressadmin_port
$cat /greatsql/conf/greatsql.cnf | grep admin
admin_address='127.0.0.1'
admin_port=3806
  • 使用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)
  • 使用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_address 和admin_port ,难道只有剩下数据库重启这种方式了吗?

其实不然,GreatSQL 默认使用 TCP/IP 进行网络连接,那是否可以把实例上由远程机器请求的部分 TCP socket 连接 kill 掉,但保持数据库进程的运行,以腾出部分连接数供 root 用户登录呢?

通过查阅资料, gdb attach 刚好能满足我们的设想:gdb attach 是 GDB(GNU 调试器)中的一个命令,用于附加(Attach)到一个正在运行的进程,而关闭一个 SOCKET,只要调用 close 函数就可以了。简单来说就是使用gdb attach 到进程上下文,然后 call close($fd)

不过需要注意的是,gdb attach 会暂停目标进程的所有线程。对于生产环境中需要持续运行的进程(如服务、数据库、实时系统等),这种暂停可能导致服务中断或超时。且gdb 需要较大的性能开销,进程的运行速度会显著下降,需要经过谨慎评估后再使用此方式。

继续复现一个连接数打满,但是未启用admin_address和 admin_port 的场景,此时尝试用管理员登录报错ERROR 1040 (HY000): Too many connections 。

  1. 通过 netstat 反查数据库的进程号为18979
$ netstat -nltp | grep 3306
tcp6       0      0 :::3306                 :::*                    LISTEN      18979/mysqld

2. 使用 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
....

4. 查看数据库进程,并再次尝试登录数据库,登录成功。

$ 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,保障线上稳定性为第一前提,连接数打满已经是一个较为糟糕的情况了。且前文描述的是数据库大版本为 8.0 后才开始支持admin_address ,admin_port  作为突发情况的紧急处理。但如果GreatSQL 5.7 或者更低的情况, 如何去保障生产的稳定性呢?

GreatSQL 还有一个参数max_user_connections  ,我们来比较max_user_connections  和max_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. 事后应排查连接数打满的原因,和业务协调优化措施,建议采用线程池等技术提前规避连接数飙高的场景。

本文地址:https://www.yitenyun.com/269.html

搜索文章

Tags

数据库 API FastAPI Calcite 电商系统 MySQL 数据同步 ACK Web 应用 异步数据库 双主架构 循环复制 生命周期 序列 核心机制 Deepseek 宝塔面板 Linux宝塔 Docker JumpServer JumpServer安装 堡垒机安装 Linux安装JumpServer esxi esxi6 root密码不对 无法登录 web无法登录 Windows Windows server net3.5 .NET 安装出错 宝塔面板打不开 宝塔面板无法访问 SSL 堡垒机 跳板机 HTTPS Windows宝塔 Mysql重置密码 无法访问宝塔面板 HTTPS加密 查看硬件 Linux查看硬件 Linux查看CPU Linux查看内存 ES 协同 修改DNS Centos7如何修改DNS scp Linux的scp怎么用 scp上传 scp下载 scp命令 防火墙 服务器 黑客 Serverless 无服务器 语言 存储 Oracle 处理机制 Spring SQL 动态查询 Linux 安全 网络架构 工具 网络配置 RocketMQ 长轮询 配置 加密 场景 开源 PostgreSQL 存储引擎 HexHub Rsync MySQL 9.3 Canal 架构 InnoDB 缓存方案 缓存架构 缓存穿透 信息化 智能运维 响应模型 索引 数据 业务 监控 日志文件 MIXED 3 线上 库存 预扣 AI 助手 数据库锁 单点故障 聚簇 非聚簇 B+Tree ID 字段 分库 分表 云原生 GreatSQL Hash 字段 Redis 自定义序列化 优化 万能公式 OB 单机版 数据集成工具 SQLite Redka DBMS 管理系统 SVM Embedding SpringAI Redis 8.0 sqlmock PostGIS 系统 SQLark 虚拟服务器 虚拟机 内存 分页查询 openHalo 查询 ​Redis 机器学习 推荐模型 SQLite-Web 数据库管理工具 自动重启 运维 同城 双活 缓存 sftp 服务器 参数 共享锁 RDB AOF 技术 排行榜 排序 Testcloud 云端自动化 EasyExcel MySQL8 prometheus Alert 向量数据库 大模型 不宕机 分布式架构 分布式锁​ 聚簇索引 非聚簇索引 • 索引 • 数据库 Entity 开发 Netstat Linux 服务器 端口 Doris SeaTunnel 人工智能 推荐系统 IT 容器化 数据备份 Postgres OTel Iceberg MongoDB 容器 数据类型 OAuth2 Token StarRocks 数据仓库 IT运维 分页 数据结构 AIOPS Python Web LRU Milvus Ftp 池化技术 连接池 Caffeine CP 部署 崖山 新版本 高可用 向量库 悲观锁 乐观锁 redo log 重做日志 磁盘架构 MCP mini-redis INCR指令 单线程 线程 MVCC 事务隔离 流量 开放协议 Web 接口 字典 电商 对象 微软 SQL Server AI功能 速度 服务器中毒 数据脱敏 加密算法 QPS 高并发 原子性 机制 R2DBC 双引擎 RAG HelixDB Order 窗口 函数 频繁 Codis SSH 引擎 性能 网络 dbt 数据转换工具 1 PG DBA 主库 ZODB 优化器 连接控制 List 类型 Pottery Crash 代码 工具链 模型 意向锁 记录锁 事务同步 网络故障 InfluxDB 发件箱模式 UUIDv7 主键 传统数据库 向量化 Redisson 锁芯 仪表盘 INSERT COMPACT 线程安全 JOIN 订单 Undo Log LLM 连接数