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

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

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

背景

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