联系我们
18591797788
hubin@rlctech.com
北京市海淀区中关村南大街乙12号院天作国际B座1708室
18681942657
lvyuan@rlctech.com
上海市浦东新区商城路660号乐凯大厦26c-1
18049488781
xieyi@rlctech.com
广州市越秀区东风东路华宫大厦808号1608房
029-81109312
service@rlctech.com
西安市高新区天谷七路996号西安国家数字出版基地C座501
数据库突发高负载、慢SQL抢占资源、业务接口雪崩?
传统限流治标不治本,关键字限流前置拦截,从根源守住数据库稳定性!尤其是OceanBase这类分布式数据库,多租户、高并发场景下,SQL限流更是运维必备技能。今天就深度拆解OceanBase两种限流方案,重点揭秘关键字限流的实战用法。
SQL限流是一种数据库流量控制机制,用于对特定的SQL请求进行并发或资源使用上的限制,以防止异常或高负载的SQL语句影响整个数据库系统的稳定性与性能。
当某些SQL请求过于频繁或消耗过多资源(如CPU、IO、响应时间等)时,可能会影响其他正常业务的执行。通过设置SQL限流规则,可以:
使用场景
ALTER SYSTEM ENABLE SQL THROTTLE FOR PRIORITY <= 100 USING QUEUE_TIME=0.1;
--对 PRIORITY 小于等于 100 的 Session 上队列等待时间超过 0.1s 的请求限流。
具体限流特征支持情况需要看对应版本的文档说明
参考文档:https://www.oceanbase.com/docs/enterprise-oceanbase-database-cn-10000000000946702
使用 Outline 绑定, 添加/*+max_concurrent(N)*/这个 Hint。其中,N 表示某类 Query 可同时执行的请求数,实际内部限制的是某个 Plan 可同时执行的请求数;
支持使用文本限流、SQL_ID 限流以及模糊限流三种方式来绑定 Outline。
CREATE [OR REPLACE] OUTLINE outline_name ON stmt_with_hint [ TO ];
CREATE OUTLINE outline_name ON sql_id USING HINT hint_text;
CREATE [OR REPLACE] FORMAT OUTLINE outline_name ON stmt_with_hint [ TO ];
CREATE FORMAT OUTLINE outline_name ON sql_id USING HINT hint_text;

查看DBA_OB_OUTLINES视图:发现通过ocp为该SQL_ID创建了outline_content为/*+max_concurrent(1) */的outline!

查看该SQL_ID(1FA56D57B98FCA5F4151B385D0C4F736)的执行计划:发现outline已经被用到执行计划里了
select PLAN_ID,OUTLINE_ID,OUTLINE_DATA from oceanbase.gv$ob_plan_cache_plan_stat where sql_id = '1FA56D57B98FCA5F4151B385D0C4F736';
+---------+------------+-----------------------------------------------------------------------------------------------------------------------+
| PLAN_ID | OUTLINE_ID | OUTLINE_DATA |
+---------+------------+-----------------------------------------------------------------------------------------------------------------------+
| 234967 | 583343 | /*+BEGIN_OUTLINE_DATA FULL(@"SEL$1" "cjx_test"."t1"@"SEL$1") OPTIMIZER_FEATURES_ENABLE('4.2.1.11') END_OUTLINE_DATA*/ |
| 317638 | 583343 | /*+BEGIN_OUTLINE_DATA FULL(@"SEL$1" "cjx_test"."t1"@"SEL$1") OPTIMIZER_FEATURES_ENABLE('4.2.1.11') END_OUTLINE_DATA*/ |
+---------+------------+-----------------------------------------------------------------------------------------------------------------------+
2 rows in set (0.06 sec)
查看sql_audit:发现后续该sql_id的sql执行都使用了带有outline的执行计划

总结:白屏是通过为sql_id创建 /* max_concurrency(N) */的outline来实现并发限流。
当前创建完outline限流规则后,若想限流规则生效,仍需进入SQL引擎。
使用outline的限流逻辑必须要先通过Parse、Resolve和Optimize阶段生成出执行计划,且在将计划添加进执行计划缓存。后续SQL进入进行快速参数化访问plan_cache后才会检查是否触发限流上限。对于一些在Parse、Resolve阶段就卡死的SQL来说,此类限流方法将失效。需要一种新的限流方式预期能够在SQL请求进入SQL引擎之前就将其拦住。

为此,引入了关键字限流
对于 V4.3.X 版本,该语句从 OceanBase 数据库 V4.3.5 BP3 版本开始引入。
对于 V4.4.X 版本,该语句从 OceanBase 数据库 V4.4.1 版本开始引入。
CREATE CONCURRENT_LIMITING_RULE [ IF NOT EXISTS ] `ccl_rule_name`
ON `database`.`table`
TO ''@'ip'
FOR { ALL | UPDATE | SELECT | INSERT | DELETE }
filter_options:
[ FILTER BY KEYWORD('KEYWORD1', 'KEYWORD2',…) ]
with_options:
WITH MAX_CONCURRENCY = value1 [per sql]
核心参数解读:
统计粒度:所有命中该规则的 SQL 总并发≤MAX_CONCURRENCY
CREATE CONCURRENT_LIMITING_RULE IF NOT EXISTS product_reviews
-> ON *.*
-> TO '%'@'%'
-> FOR ALL
-> FILTER BY KEYWORD('product_reviews')
-> WITH MAX_CONCURRENCY = 1;
select rating,sleep(1) from product_reviews;

同时执行两个语句

执行结果:命中限流规则
统计粒度:每个格式化后的 SQL 单独计数,各自并发≤1
创建新的限流规则(多了一个PER SQL)
MySQL [test]> CREATE CONCURRENT_LIMITING_RULE IF NOT EXISTS product_reviews
-> ON *.*
-> TO '%'@'%'
-> FOR SELECT
-> FILTER BY KEYWORD('product_reviews')
-> WITH MAX_CONCURRENCY = 1 per sql;
Query OK, 0 rows affected (0.17 sec)
在两个窗口同时分别执行不一样SQL_ID的查询语句
-- 窗口1 SQL
select user_id,rating,sleep(1) from product_reviews
-- 窗口1 SQL_ID: 02E17F50C77BA44C23A4F3B7B031F004
-- 窗口2 SQL
select rating,product_id,sleep(1) from product_reviews
-- 窗口2 SQL_ID: 1FF7D06783EC120A29EE890C85ED15D8
执行结果如下:

执行成功,未命中CCL_RULE
添加一个窗口3,执行和窗口1一样的语句,预期就会命中限流规则报错

从sql_audit也可以查看CCL_RULE_ID来判断是否命中CCL_RULE
SVR_IP: XX.XX.XX.XX
SVR_PORT: 2882
REQUEST_ID: 1635878
SQL_EXEC_ID: 20545345
TRACE_ID: YB42C0A8054B-000642EF0AE65536-0-0
SID: 297797
CLIENT_IP: XX.XX.XX.XX
CLIENT_PORT: 46744
TENANT_ID: 1004
TENANT_NAME: test
EFFECTIVE_TENANT_ID: 1004
USER_ID: 200001
USER_NAME: root
USER_GROUP: 0
USER_CLIENT_IP: XX.XX.XX.XX
DB_ID: 500001
DB_NAME: test
SQL_ID: 02E17F50C77BA44C23A4F3B7B031F004
QUERY_SQL: select user_id,rating,sleep(1) from product_reviews
PLAN_ID: 0
AFFECTED_ROWS: 0
RETURN_ROWS: 0
PARTITION_CNT: 1
RET_CODE: -11087
QC_ID: 0
DFO_ID: 0
SQC_ID: 0
WORKER_ID: 0
EVENT:
P1TEXT:
P1: 0
P2TEXT:
P2: 0
P3TEXT:
P3: 0
LEVEL: 0
WAIT_CLASS_ID: 100
WAIT_CLASS#: 0
WAIT_CLASS: OTHER
STATE: MAX_WAIT TIME ZERO
WAIT_TIME_MICRO: 0
TOTAL_WAIT_TIME_MICRO: 0
TOTAL_WAITS: 0
RPC_COUNT: 0
PLAN_TYPE: 0
IS_INNER_SQL: 0
IS_EXECUTOR_RPC: 0
IS_HIT_PLAN: 0
REQUEST_TIME: 1762600230468937
ELAPSED_TIME: 819
NET_TIME: 0
NET_WAIT_TIME: 3
QUEUE_TIME: 240
DECODE_TIME: 1
GET_PLAN_TIME: 440
EXECUTE_TIME: 79
APPLICATION_WAIT_TIME: 0
CONCURRENCY_WAIT_TIME: 0
USER_IO_WAIT_TIME: 0
SCHEDULE_TIME: 0
ROW_CACHE_HIT: 0
BLOOM_FILTER_CACHE_HIT: 0
BLOCK_CACHE_HIT: 0
DISK_READS: 0
RETRY_CNT: 0
TABLE_SCAN: 0
CONSISTENCY_LEVEL: -1
MEMSTORE_READ_ROW_COUNT: 0
SSSTORE_READ_ROW_COUNT: 0
DATA_BLOCK_READ_CNT: 0
DATA_BLOCK_CACHE_HIT: 0
INDEX_BLOCK_READ_CNT: 0
INDEX_BLOCK_CACHE_HIT: 0
BLOCKSCAN_BLOCK_CNT: 0
BLOCKSCAN_ROW_CNT: 0
PUSHDOWN_STORAGE_FILTER_ROW_CNT: 0
REQUEST_MEMORY_USED: 8565248
EXPECTED_WORKER_COUNT: 0
USED_WORKER_COUNT: 0
SCHED_INFO: NULL
FUSE_ROW_CACHE_HIT: 0
PS_CLIENT_STMT_ID: -1
PS_INNER_STMT_ID: -1
TX_ID: 0
SNAPSHOT_VERSION: 0
REQUEST_TYPE: 2
IS_BATCHED_MULTI_STMT: 0
OB_TRACE_INFO: NULL
PLAN_HASH: 0
LOCK_FOR_READ_TIME: 0
PARAMS_VALUE:
RULE_NAME:
PARTITION_HIT: 1
TX_INTERNAL_ROUTING: 0
TX_STATE_VERSION: 0
FLT_TRACE_ID: 00064313-589e-3d45-641f-4857b908d45e
PL_TRACE_ID: NULL
PLSQL_EXEC_TIME: 0
FORMAT_SQL_ID: 2E1AEEDF0CE5A757B4D4BEAF7D16AE89
STMT_TYPE: SELECT
TOTAL_MEMSTORE_READ_ROW_COUNT: 0
TOTAL_SSSTORE_READ_ROW_COUNT: 0
PROXY_USER:
SEQ_NUM: 0
NETWORK_WAIT_TIME: 0
PLSQL_COMPILE_TIME: 0
INSERT_DUPLICATE_ROW_COUNT: 0
CCL_RULE_ID: 500016
CCL_MATCH_TIME: 148
oceanbase.DBA_OB_CCL_RULES
GV$OB_SQL_CCL_STATUS
0 ALL
1 SELECT
2 UPDATE
3 INSERT
4 DELETE
SQL限流是数据库运维的最后一道防线,OceanBase关键字限流彻底解决了传统限流的滞后性问题,实现前置拦截、精准控流、低耗高效。
你在运维实战中,曾遭遇哪些棘手难题?欢迎在评论区交流!