暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

技术干货 | GreatSQL连接数被打满的3种紧急解决方案

万里数据库 2025-06-05
99



背景

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



01

场景复现


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



        02

        场景分析


        方案1:使用admin_port处理故障


        从GreatSQL 8.0起,GreatSQL支持在配置文件配置admin_port和admin_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


          2. 使用admin_port和admin_address尝试登录数据库,登录成功 

            /greatsql/svr/greatsql/bin/mysql -h127.0.0.1 -uroot --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)


            3.使用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。



                      03

                      总结


                      1.无论对于GreatSQL5.7还是8.0,建议设置max_user_connections降低连接数打满的风险;


                      2.对于GreatSQL8.0版本,可通过配置增加admin_address和admin_port来启用管理接口,以应对突发情况;


                      3.如果出现连接数打满且未启用管理端口的情况,可以使用gdb attach在线关掉部分socket,以避免数据库重启。但需注意:gdb attach对机器性能的开销和 gdb 运行时数据库的所有线程都会暂停,请评估后再使用该方式;


                      4.监控可加上对连接数的监控,达到阈值时告警会出来,要提前介入处理;


                      5.事后应排查连接数打满的原因,与业务侧协调优化措施,建议采用线程池等技术提前规避连接数飙高等场景。


                      Enjoy GreatSQL





                      技术干货 | dbops 助力GreatSQL安装部署

                      数据迁移丨如何用AI完成 PostgreSQL 到 GreatSQL 迁移?附全干货解析~

                      使用gt-checksum迁移表结构到 GreatSQL


                      关于万里数据库


                      北京万里开源软件有限公司(简称“万里数据库”)成立于2000年,是专注于国产自主可控数据库产品研发的国家高新技术企业、国家级专精特新“小巨人”企业,拥有发明专利、软件著作权百余项。


                      万里数据库的技术底蕴源自对底层核心代码的掌控,产品始终坚持以“极致稳定、极致性能、极致易用”为目标,经过20余年的研发经验积累,产品在功能、性能、稳定、易用等方面均处于行业领先水平,广泛应用于金融、运营商、能源、政府、交通等行业重要业务系统中的超2000个业务场景,得到了用户和市场的认可与肯定。


                      2021年,公司创立GreatSQL开源社区,通过对MySQL技术的优化,目前已成长为国内活跃的自主开源数据库社区


                      极致稳定  极致性能  极致易用


                      “在看”点一下,万里早知道

                      文章转载自万里数据库,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                      评论