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

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

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

背景

使用数据库时,偶尔会出现数据库连接数飙升的场景,最严重的情况是连接打满,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 Web 应用 异步数据库 数据同步 ACK 双主架构 循环复制 JumpServer SSL 堡垒机 跳板机 HTTPS TIME_WAIT 运维 负载均衡 HexHub Docker JumpServer安装 堡垒机安装 Linux安装JumpServer Deepseek 宝塔面板 Linux宝塔 生命周期 esxi esxi6 root密码不对 无法登录 web无法登录 服务器 管理口 序列 核心机制 Windows Windows server net3.5 .NET 安装出错 HTTPS加密 服务器性能 查看硬件 Linux查看硬件 Linux查看CPU Linux查看内存 宝塔面板打不开 宝塔面板无法访问 开源 PostgreSQL 存储引擎 Windows宝塔 Mysql重置密码 Oracle 处理机制 无法访问宝塔面板 InnoDB 数据库锁 连接控制 机制 监控 Serverless 无服务器 语言 Spring Redis 异步化 ES 协同 group by 索引 SQL 优化 万能公式 技术 Undo Log 缓存方案 缓存架构 缓存穿透 分页查询 高可用 动态查询 GreatSQL 连接数 机器学习 工具 响应模型 查询 日志文件 MIXED 3 scp Linux的scp怎么用 scp上传 scp下载 scp命令 R edis 线程 SVM Embedding R2DBC 锁机制 数据 主库 加密 场景 Netstat Linux 服务器 端口 openHalo Postgres OTel Iceberg 云原生 Linux 安全 RocketMQ 长轮询 配置 Recursive 自定义序列化 存储 AI 助手 ​Redis 推荐模型 SQLite-Web SQLite 数据库管理工具 共享锁 SQLark Hash 字段 向量数据库 大模型 PG DBA 电商 系统 OB 单机版 Ftp 架构 启动故障 国产数据库 MySQL 9.3 修改DNS Centos7如何修改DNS 数据分类 • 索引 • 数据库 流量 防火墙 黑客 人工智能 推荐系统 磁盘架构 Rsync sftp 服务器 参数 分库 分表 同城 双活 信息化 智能运维 Python 线上 库存 预扣 redo log 重做日志 不宕机 向量库 Milvus mini-redis INCR指令 MVCC 业务 Canal 传统数据库 向量化 行业 趋势 缓存 聚簇 非聚簇 Redisson 锁芯 PostGIS 高效统计 今天这篇文章就跟大家 INSERT COMPACT 网络架构 网络配置 Doris SeaTunnel 数据备份 filelock prometheus Alert 事务 Java 开发 语句 Web 窗口 函数 ZODB 虚拟服务器 虚拟机 内存 RDB AOF MongoDB 数据结构 引擎 性能 数据脱敏 加密算法 容器 读写 Go 数据库迁移 失效 OAuth2 Token 核心架构 订阅机制 数据类型 频繁 Codis B+Tree ID 字段 模型 Redis 8.0 IT运维 自动重启 容器化 分布式 集中式 崖山 新版本 发件箱模式 网络故障 DBMS 管理系统 聚簇索引 非聚簇索引 播客 SpringAI SSH 微软 SQL Server AI功能 MCP 开放协议 Web 接口 QPS 高并发 数据页 JOIN Entity 原子性 数据集成工具 速度 服务器中毒 网络 部署 Pottery 工具链 排行榜 排序 Testcloud 云端自动化 StarRocks 数据仓库 Redka Caffeine CP 事务隔离 分布式架构 分布式锁​ 分页方案 排版 大表 业务场景 池化技术 连接池 dbt 数据转换工具 1 悲观锁 乐观锁 主从复制 代理 AIOPS 日志 sqlmock LRU 优化器 EasyExcel MySQL8 单点故障 仪表盘 Order 分页 意向锁 记录锁 事务同步 数据字典 兼容性 InfluxDB UUIDv7 主键 对象 RAG HelixDB Ansible ReadView 单线程 UUID ID 订单 Crash 代码 IT 双引擎 LLM 字典 Valkey Valkey8.0 恢复数据 Weaviate 产业链 编程 MGR 分布式集群 分布式锁 Zookeeper 千万级 线程安全 Pump List 类型 拦截器 动态代理 关系数据库 表空间 Next-Key 解锁 调优 慢SQL优化 快照读 当前读 视图 GitHub Git 矢量存储 数据库类型 AI代理 国产 用户 RR 互联网 神经系统 查询规划 算法 count(*) count(主键) 行数 技巧 CAS 并发控制 恢复机制 多线程 闪回