您在购买RDS实例时所选择的内存大小决定了该实例的最大连接数。在RDS管理控制台对应实例的基本信息中可看到该实例所支持的最大连接数。当RDS实例的连接数量超过该实例的最大连接数时,将无法创建新的连接,此时将会影响您业务的正常进行。
MySQL的连接通常是一个请求占用一个连接,一般的后端语言(例如php没用swoole实现连接池的), 在请求(update,insert,delete,select等)长时间没有执行完毕,则会造成连接的堆积,迅速的消耗完RDS实例的连接数。
连接数过多的优化方法
排查连接数过多的方法是什么呢? 有以下方法可排查:
监控告警
当用户收到连接数告警时,意味着连接数即将达到实例的上限。这是一个重要的指示,提示我们需要采取措施来处理连接数过多的情况,以避免对用户业务的影响。
分析连接占用
MySQL的连接通常是一个请求占用一个连接。如果某个请求(如update、insert、delete、select)长时间未执行完毕,就会导致连接堆积,迅速消耗数据库的连接数。在这种情况下,技术支持人员需要登录数据库并检查连接的占用情况,找出具体哪些SQL语句占用了连接。
优化SQL语句
一旦确定哪些SQL语句占用了连接,就需要对其进行优化。通过优化查询语句、添加索引、调整数据库配置等方式,提升SQL语句的执行效率,从而减少连接占用的时间。
增加连接数限制
如果经过优化后仍然存在连接数过多的问题,可以考虑增加数据库实例的连接数限制。这需要根据实际情况评估数据库的硬件资源和负载情况,确保增加连接数不会对系统性能造成过大的影响。
连接池
使用连接池可以更好地管理数据库连接,避免连接的频繁创建和销毁,从而提高连接的复用率和效率。连接池可以帮助平衡连接的分配和释放,有效控制连接数,减少连接数过多的情况发生。
场景: 阿里云RDS控制台下的优化
查看实例配置:
如果是阿里云的RDS, 你可登录RDS控制台“详情与配置”查看实例额定链接数,我们假设最高支持1500个链接
查看当前的连接数:
1)可登录RDS控制台“性能监控”查看实例当前链接数。
2)或者登录数据库查询当前连接,可以使用同步帐号或者用户的业务帐号登录数据库,执行show processlist;
[root@r41d05036.xy2.aliyun.com ~]# mysql -uroot -h127.0.0.1 -P3020 -e "show processlist"|wc -l 1262
可以看到该实例已经有1262 个连接
排查是啥动作占用了那么多连接:
[root@r41d05036.xy2.aliyun.com ~]# myql -uroot -h127.0.0.1 -P3018 -e "show full processlist">/tmp/1.log root@r14d11038.dg.aliyun.com # more /tmp/1.log 615083 my_db 223.4.49.212:54115 my_db Query 100 Sending data INSERT INTO tmp_orders_modify (oid, tid, seller_id, `status`, gmt_create, gmt_modified) SELECT oid, tid, seller_id, `status`, gmt_create, gmt_modified FROM sys_info.orders WHERE gmt_modified < NAME_CONST('v_last',_binary'2012-12-24 10:33:00' COLLATE 'binary') AN D gmt_modified >= NAME_CONST('v_curr',_binary'2012-12-24 10:32:00' COLLATE 'binary') 621564 my_db 223.4.49.212:46596 my_db Query 3890 sorting result insert into tmp_trades(sid, d, h, tc, tm, tp, ic, new_tp, old_tp) select a.seller_id as sid, ………….. from orders_1 as a where seller_id =1 and is_detail = '1' and created < date_format('2012-12-24 10:35:00', '%Y-%m-%d %H:00:00') and gmt_create < date_format('2012-12-24 10:40:00', '%Y-%m-%d %H:%i:00') and gmt_create >= date_format('2012-12-24 10:35:00', '%Y-%m-%d%H:%i:00') group by d, h order by d ……………….此处省略其他sql
分析连接占用的原因:
可以看到数据库中有长时间没有执行完成的sql,一直占用着连接没有释放,而应用的请求一直持续不断的涌入数据库,这个时候数据库的连接很快就被使用完;所以这个时候需要排查为什么这些sql 为什么长时间没有执行完毕,是索引没有创建好,还是sql执行耗时严重。
第一条sql:
INSERT INTO tmp_orders_modify (oid, tid, seller_id, `status`, gmt_create, gmt_modified) SELECT oid, tid, seller_id, `status`, gmt_create, gmt_modified FROM sys_info.orders WHERE gmt_modified < NAME_CONST('v_last',_binary'2012-12-24 10:33:00' COLLATE 'binary') AND gmt_modified >= NAME_CONST('v_curr',_binary'2012-12-24 10:32:00' COLLATE 'binary')
是用户从sys_info 数据库中拉取订单到自己的业务库中那个,但是在orders 表上没有gmt_modified 的索引,导致了全表扫描;(更加详尽的排查方法可以参考:为什么我的RDS慢了);
第二条sql:
看到这条sql 正在进行sorting 排序,为什么导致sql 长时间sorting,通常情况下为排序的结果集太大导致排序不能在内存中完成,需要到磁盘上排序,进而导致了性能的下降;解决的办法就是降低排序的结果集,常用的手段是利用索引的有序性,消除排序,或者建立适当的索引减小结果集;我们可以看到第二条sql 的排序字段非常的复杂,但是我们可以看到查询的时间范围是很短,只有5 分钟的时间间隔,这个时候就可以在gmt_create上创建一个索引,过滤掉大部分的记录:
Alter tale order_1 add index ind_order_gmt_create(gmt_create);
(该用户对orders 进行了分表,大概有50 多张分表需要添加gmt_create 字段的索引);
经过上面两步的优化后,用户实例恢复正常:io 情况和connection 情况,可再登录一回RDS控制台查看连接数。