【笔记】最佳实践—如何限流慢SQL

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 本文介绍了如何对慢SQL进行有效限流。

在数据库会话或者慢日志中发现大量慢SQL,大量占用数据库资源,同时活跃会话数、CPU使用率、IOPS、内存使用率等监控指标一项或者多项处于高位。分析后发现这些慢SQL不属于核心业务,是优化不足的烂SQL,为保障核心业务的稳定运行,此时我们需要对其进行限流。

相关限流语法,请参见SQL限流

SQL限流的运维操作步骤

  1. 实例会话页面或使用如下语句发现慢SQL。
select *

from information_schema.processlist
where COMMAND!= 'SLEEP'
and TIME>= 1000
order by TIME DESC;
  1. 分析慢SQL,请参见如何分析及优化慢SQL
  2. 创建限流规则,可使用SQL命令,或者实例会话里SQL限流功能上的白屏化操作。
  3. 从以下几方面观察限流规则效果。
    • 监控指标恢复情况;
    • 业务侧反馈;
    • show ccl_rules查看每个限流规则的限流情况的统计信息;
    • 查看会话和SQL日志。
  1. 创建索引、修改SQL、增加资源等。
  2. 关闭限流规则,使用DROP CCL_RULE或者CLEAR CCL_RULES语句。

如下案例说明了如何对发现的慢SQL进行限流,您可以参照案例中的限流规则,修改后使用。

案例1: 慢SQL属于同一个SQL模版

某DBA收到了数据库资源某指标处于高位的报警,查看数据库慢日志和会话后均发现有如下的慢SQL:


+--------+---------------+---------------------+--------------------+---------+------+-------+----------------------------------------------+-----------------+
| ID | USER | HOST | DB | COMMAND | TIME | STATE | INFO | SQL_TEMPLATE_ID |
+--------+---------------+---------------------+--------------------+---------+------+-------+----------------------------------------------+-----------------+
| 951494 | userxxxxxxxxx | 222.0.0.1:33830 | analy_db | Query | 40 | | select * from bmsql_oorder where `o_id` > 12 | 65c92c88 |
| 952468 | userxxxxxxxxx | 222.0.0.1:33517 | analy_db | Query | 43 | | select * from bmsql_oorder where `o_id` > 10 | 65c92c88 |
| 953468 | userxxxxxxxxx | 222.0.0.1:33527 | analy_db | Query | 43 | | select * from bmsql_oorder where `o_id` > 23 | 65c92c88 |
| 954468 | userxxxxxxxxx | 222.0.0.1:33537 | analy_db | Query | 43 | | select * from bmsql_oorder where `o_id` > 25 | 65c92c88 |
| 955468 | userxxxxxxxxx | 222.0.0.1:33547 | analy_db | Query | 43 | | select * from bmsql_oorder where `o_id` > 27 | 65c92c88 |
+--------+---------------+---------------------+--------------------+---------+------+-------+----------------------------------------------+-----------------+

可见,这些慢SQL属于同一个SQL模版(模版ID为65c92c88):


select * from bmsql_oorder where `o_id` > ?

bmsql_oorder为一个数据量较大的表,而且列o_id上没有索引,显然这个一个未经优化的SQL,占尽了数据库资源影响了其他重要SQL的正常执行。这是一个非常适合利用模版ID去做SQL限流的场景。

创建限流规则

  • 如果这个SQL模版的SQL不应该在当时执行,而且应该在业务低峰期执行,则我们可以创建SQL限流规则不让它执行:
CREATE CCL_RULE `KILL_CCL`       //限流规则名称为KILL_CCL
ON `analy_db`.`*` //&匹配analy_db下的所有表上执行的SQL
TO 'userxxxxxxxxx'@'%' //&匹配来自userxxxxxxxxx用户的SQL
FOR SELECT //&匹配是SELECT类型的SQL语句
FILTER BY TEMPLATE '65c92c88' //&匹配模版ID
WITH MAX_CONCURRENCY = 0; //设置单节点并发度为0,不允许匹配到的SQL执行
  • 客户端再次执行这类SQL的时候将会返回报错信息:
ERROR 3009 (HY000): 13172dbaf2801000[analy_db]Exceeding the max concurrency 0 per node of ccl rule KILL_CCL
  • 如果允许这个SQL模版的SQL少量执行,只要不占尽数据库资源就行,则我们可以在创建限流规则的时候设置一定的并发度:
CREATE CCL_RULE `KILL_CCL_2`       //限流规则名称为KILL_CCL
ON `analy_db`.`*` //&匹配analy_db下的所有表上执行的SQL
TO 'userxxxxxxxxx'@'%' //&匹配来自userxxxxxxxxx用户的SQL
FOR SELECT //&匹配是SELECT类型的SQL语句
FILTER BY TEMPLATE '65c92c88' //&匹配模版ID 65c92c88
WITH MAX_CONCURRENCY = 2; //允许单个节点可以同时有两个这样的SQL在执行
  • 也可使用实例会话页面里的SQL限流功能,进行如下操作:8..png
  • 如果希望这个SQL模版的SQL执行的时候可以慢,但尽量不要出错,则可以设置等待队列和等待超时时间(默认为600秒):


CREATE CCL_RULE `QUEUE_CCL_2`       //限流规则名称为KILL_CCL
ON `analy_db`.`*` //&匹配analy_db下的所有表上执行的SQL
TO 'userxxxxxxxxx'@'%' //&匹配来自userxxxxxxxxx用户的SQL
FOR SELECT //&匹配是SELECT类型的SQL语句
FILTER BY TEMPLATE '65c92c88' //&匹配模版ID
WITH MAX_CONCURRENCY = 2, WAIT_QUQUE_SIZE=20, WAIT_TIMEOUT=500; //单节点并发度为2,单节点等待队列长度为20,等待超时时间为500秒

创建完后,可以通过show ccl_rules指令查询各个限流规则的实际效果,比如当前匹配到某个限流规则的正在执行的SQL的数量、被限流报错的SQL数量、总匹配成功次数等。如果想放开被限流SQL,比如在增加了某个索引后,被限流SQL的执行效率变高了,则可以通过drop ccl_rule命令来关闭指定限流规则,或者使用clear ccl_rules来关闭所有的限流规则。

当然上面的SQL也可以通过关键字来限流,将SQL语句上的关键字做拆分,我们得到关键字列表:

  • select
  • from
  • bmsql_oorder
  • where
  • `o_id`

创建限流规则:


CREATE CCL_RULE `KILL_CCL`       //限流规则名称为KILL_CCL
ON `analy_db`.`*` //&匹配analy_db下的所有表上执行的SQL
TO 'userxxxxxxxxx'@'%' //&匹配来自userxxxxxxxxx用户的SQL
FOR SELECT //&匹配是SELECT类型的SQL语句
FILTER BY KEYWORD('select','from','bmsql_oorder','where','`o_id`') //&匹配模版ID
WITH MAX_CONCURRENCY = 0; //设置单节点并发度为0,不允许匹配到的SQL执行

在能获取到模版ID(在SQL日志、explain命令、会话中)的情况下,我们还推荐使用更精准的基于模版ID的限流。

也可使用实例会话页面里的SQL限流功能,操作如下:

案例2: 慢SQL都是同一个SQL

某DBA收到了数据库资源某指标处于高位的报警,查看数据库慢日志和会话后均发现有如下的慢SQL:


+--------+---------------+---------------------+--------------------+---------+------+-------+---------------------------------------------------+-----------------+
| ID     | USER          | HOST                | DB                 | COMMAND | TIME | STATE | INFO                                              | SQL_TEMPLATE_ID |
+--------+---------------+---------------------+--------------------+---------+------+-------+---------------------------------------------------+-----------------+
| 951494 | userxxxxxxxxx | 222.0.0.1:33830     | analy_db           | Query   |   40 |       | select * from bmsql_oorder where o_carrier_id = 2 | 438b00e4        |
| 952468 | userxxxxxxxxx | 222.0.0.1:33517     | analy_db           | Query   |   43 |       | select * from bmsql_oorder where o_carrier_id = 2 | 438b00e4        |
| 953468 | userxxxxxxxxx | 222.0.0.1:33527     | analy_db           | Query   |   43 |       | select * from bmsql_oorder where o_carrier_id = 2 | 438b00e4        |
| 954468 | userxxxxxxxxx | 222.0.0.1:33537     | analy_db           | Query   |   43 |       | select * from bmsql_oorder where o_carrier_id = 2 | 438b00e4        |
| 955468 | userxxxxxxxxx | 222.0.0.1:33547     | analy_db           | Query   |   43 |       | select * from bmsql_oorder where o_carrier_id = 2 | 438b00e4        |
+--------+---------------+---------------------+--------------------+---------+------+-------+---------------------------------------------------+-----------------+

bmsql_oorder中的符合o_carrier_id = 2条件的有较多记录,导致了慢SQL,如果使用模版ID限流,则会影响o_carrier_id不是2的SQL语句,如果使用关键字限流则会影响类似如下的正常SQL:


select * from bmsql_oorder where o_carrier_id = 2 limit 1;

select * from bmsql_oorder where o_carrier_id = 2 and o_c_id = 1;

限流具体的SQL,可以使用模版ID加关键字的方法,创建如下限流规则:


CREATE CCL_RULE `KILL_CCL`       //限流规则名称为KILL_CCL
ON `analy_db`.`*` //&匹配analy_db下的所有表上执行的SQL
TO 'userxxxxxxxxx'@'%' //&匹配来自userxxxxxxxxx用户的SQL
FOR SELECT //&匹配是SELECT类型的SQL语句
FILTER BY TEMPLATE '438b00e4' //&匹配模版ID 438b00e4
FILTER BY KEYWORD('o_carrier_id','2') //&匹配参数关键字
WITH MAX_CONCURRENCY = 0; //设置单节点并发度为0,不允许匹配到的SQL执行

如果使用PolarDB-X的CN内核版本为5.4.11以上,且该SQL不在prepare模式下执行,还可以使用如下高阶语法进行限流:


CREATE CCL_RULE `KILL_CCL`       //限流规则名称为KILL_CCL
ON `analy_db`.`*` //&匹配analy_db下的所有表上执行的SQL
TO 'userxxxxxxxxx'@'%' //&匹配来自userxxxxxxxxx用户的SQL
FOR SELECT //&匹配是SELECT类型的SQL语句
FILTER BY QUERY 'select * from bmsql_oorder where o_carrier_id = 2' //&匹配SQL语句
WITH MAX_CONCURRENCY = 0; //设置单节点并发度为0,不允许匹配到的SQL执行

案例3: 慢SQL集包含多个SQL模版

某DBA收到了数据库资源某指标处于高位的报警,查看数据库慢日志和会话后均发现有如下的慢SQL:


+--------+---------------+---------------------+--------------------+---------+------+-------+---------------------------------------------------+-----------------+
| ID | USER | HOST | DB | COMMAND | TIME | STATE | INFO | SQL_TEMPLATE_ID |
+--------+---------------+---------------------+--------------------+---------+------+-------+---------------------------------------------------+-----------------+
| 951494 | userxxxxxxxxx | 222.0.0.1:33830 | analy_db | Query | 40 | | select * from bmsql_oorder where o_carrier_id = 2 | 438b00e4 |
| 952468 | userxxxxxxxxx | 222.0.0.1:33517 | analy_db | Query | 43 | | select * from bmsql_order_line where ol_o_id = 2 | 57a572f9 |
| 953468 | userxxxxxxxxx | 222.0.0.1:33527 | analy_db | Query | 43 | | select * from bmsql_new_order where no_w_id = 2 | de6eefdb |
+--------+---------------+---------------------+--------------------+---------+------+-------+---------------------------------------------------+-----------------+

此种情况较为复杂,如果一条明显执行效率很高的SQL也成了慢SQL,则不排除是由于网络抖动或者服务节点异常等原因导致运行效率降低从而产生大批量的慢SQL,也可能是由于真正的烂SQL完全耗尽了资源,导致原本正常的SQL也成了慢SQL,需要通过SQL分析具体原因,不在本文的讨论范围内。假设已经确定了需要限流的慢SQL,我们则可以针对每个模版ID创建一个限流规则。但随着限流规则增加,匹配效率会略有降低,当PolarDB-X的CN内核版本为5.4.11以上时,我们推荐使用多模版限流:


CREATE CCL_RULE `KILL_CCL`       //限流规则名称为KILL_CCL
ON `analy_db`.`*` //&匹配analy_db下的所有表上执行的SQL
TO 'userxxxxxxxxx'@'%' //&匹配来自userxxxxxxxxx用户的SQL
FOR SELECT //&匹配是SELECT类型的SQL语句
FILTER BY TEMPLATE('438b00e4','57a572f9','de6eefdb') //&匹配中其中一个模版ID,则该匹配项算匹配成功
WITH MAX_CONCURRENCY = 0; //设置单节点并发度为0,不允许匹配到的SQL执行

如果确定会话中的慢SQL是都是需要限流的烂SQL,且PolarDB-X的CN内核版本为5.4.11以上时,可以开启慢SQL限流。也可以使用实例会话页面里的SQL限流功能,进行如下操作:9..png

总结

SQL限流为应急措施,可在数据库由于烂SQL导致效率降低的时候,起到快速恢复的作用。对烂SQL进行限流后,用户需要将注意力集中在如何优化烂SQL上,并在合适的时机清空SQL限流规则。

相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
相关文章
|
监控 Java Go
深入探索 RUM 与全链路追踪:优化数字体验的利器
本文主要介绍了基于 OpenTeletemetry 与 W3C 协议构建端到端全链路的解决方案,同时探讨了 RUM 与端到端链路集成的最佳实践,希望可以为大家在生产环境落地应用提供一些参考。
715 116
|
人工智能 自然语言处理 Serverless
评测
本文对“触手可及,函数计算玩转 AI 大模型”解决方案进行全面测评,涵盖功能特性、性能表现、易用性和成本效益等多个方面。测评结果显示,该方案在大模型集成便捷性、函数计算能力拓展、多场景适配性等方面表现出色,能够显著降低使用门槛、提升开发效率和运行性能。然而,在高并发场景下的响应时间和大规模应用的成本控制方面仍有改进空间。总体而言,该方案特别适合中小企业和创新型项目快速落地 AI 应用。
|
10月前
|
消息中间件 NoSQL 架构师
招行面试:亿级秒杀,超卖问题+少卖问题,如何解决?(图解+秒懂+史上最全)
45岁资深架构师尼恩在读者交流群中分享了如何系统化解决高并发下的库存抢购超卖少买问题,特别是针对一线互联网企业的面试题。文章详细解析了秒杀系统的四个阶段(扣库预扣、库存扣减、支付回调、库存补偿),并通过Redis分布式锁和Java代码示例展示了如何防止超卖。此外,还介绍了使用RocketMQ延迟消息和xxl-job定时任务解决少卖问题的方法。尼恩强调,掌握这些技术不仅能提升面试表现,还能增强实际项目中的高并发处理能力。相关答案已收入《尼恩Java面试宝典PDF》V175版本,供后续参考。
|
SQL 监控 数据库
MSSQL性能调优秘籍:索引深度优化、SQL重构技巧与高效锁策略
在Microsoft SQL Server(MSSQL)环境中,性能调优是确保数据库高效运行、满足业务快速增长需求的关键
|
Kubernetes 容器 Perl
k8s 部署 elasticsearch 单节点
k8s 部署 elasticsearch 单节点
|
Java 开发者
偏向锁和轻量锁哪个更常用
【10月更文挑战第20天】偏向锁和轻量锁哪个更常用
|
消息中间件 Java API
Spring Cloud Stream 消息发送
Spring Cloud Stream 消息发送
612 0
|
SQL 关系型数据库 MySQL
MySQL 默认隔离级别是RR,为什么阿里这种大厂会改成RC?
我之前写过一篇文章《[为什么MySQL选择REPEATABLE READ作为默认隔离级别?][1]》介绍过MySQL 的默认隔离级别是 Repeatable Reads以及背后的原因。
3586 0
|
Linux C++
Linux进程状态——top,ps中看到进程状态D,S的含义
在top和ps命令中有一列显示进程状态,分别有如下值 值 含义 备注 S 进程处于interruptable sleep状态 na D 进程处于Uninterruptable sleep状态 na R 进程处于运行状态 na Z 进程处于僵尸状态 na T Stop模式,进程要么处于被调试状态 na interruptable sleep vs uninterruptable sleep interruptable sleep 进程等待某个资源处于sleep状态,此时可以通过发送信号将这个进程唤醒。
4056 0