ITPub博客

首页 > 数据库 > 国内数据库 > OceanBase SQL限流实战:告别数据库雪崩,关键字限流才是终极解法|文末宠粉福利

OceanBase SQL限流实战:告别数据库雪崩,关键字限流才是终极解法|文末宠粉福利

原创 国内数据库 作者:瑞蓝创_RLC_888 时间:2026-03-26 17:20:34 0 删除 编辑

数据库突发高负载、慢SQL抢占资源、业务接口雪崩? 传统限流治标不治本,关键字限流前置拦截,从根源守住数据库稳定性!尤其是OceanBase这类分布式数据库,多租户、高并发场景下,SQL限流更是运维必备技能。今天就深度拆解OceanBase两种限流方案,重点揭秘 关键字限流的实战用法。

SQL限流的概念和使用场景

SQL限流是一种数据库流量控制机制,用于对特定的SQL请求进行并发或资源使用上的限制,以防止异常或高负载的SQL语句影响整个数据库系统的稳定性与性能。

当某些SQL请求过于频繁或消耗过多资源(如CPU、IO、响应时间等)时,可能会影响其他正常业务的执行。通过设置SQL限流规则,可以:

  • 提前终止不符合要求的SQL请求;
  • 限制并发执行数量;
  • 基于优先级控制影响范围;
  • 避免个别SQL占用过多系统资源,从而保障整体服务的可用性和响应速度。

使用场景

  1. 控制高并发访问:限制某一类SQL的最大并发执行数,避免数据库过载。
  2. 应急响应手段:在出现突发流量或SQL性能问题时,作为快速止损措施。

SQL限流的常用方法

1. 设置 SQL 特征限流(Throttle)

对特定优先级SQL限流


ALTER SYSTEM ENABLE SQL THROTTLE FOR PRIORITY <= 100 USING QUEUE_TIME=0.1; 

--对 PRIORITY 小于等于 100 的 Session 上队列等待时间超过 0.1s 的请求限流。

RT:按照sql 响应时间限流

QUEUE_TIME:按照队列等待时间限流

具体限流特征支持情况需要看对应版本的文档说明

参考文档:https://www.oceanbase.com/docs/enterprise-oceanbase-database-cn-10000000000946702

2. 绑定Hint限流(创建Outline)

使用 Outline 绑定, 添加 /*+max_concurrent(N)*/这个 Hint。其中,N 表示某类 Query 可同时执行的请求数,实际内部限制的是某个 Plan 可同时执行的请求数;

支持使用文本限流、SQL_ID 限流以及模糊限流三种方式来绑定 Outline。

sql_text限流



CREATE [
OR 
REPLACE] 
OUTLINE outline_name 
ON stmt_with_hint [ 
TO  ];

SQL_ID 限流



CREATE 
OUTLINE outline_name 
ON sql_id 
USING HINT hint_text;


format outline



CREATE [
OR 
REPLACE] 
FORMAT 
OUTLINE outline_name 
ON stmt_with_hint [ 
TO  ];

CREATE  FORMAT  OUTLINE outline_name  ON sql_id  USING HINT hint_text;
  1. format outline使用需要注意版本是否支持。
  2. 当同一条 SQL 可以匹配多个限流规则时,会选择并发度最小的进行限流。
  3. 所有的 Outline 相关功能都只能针对本租户,不能通过系统租户对其他租户进行 Outline 相关操作。

SQL限流存在的问题

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

查看该SQL_ID(1FA56D57B98FCA5F4151B385D0C4F736)的执行计划:发现outline已经被用到执行计划里了

+---------+------------+-----------------------------------------------------------------------------------------------------------------------+
| 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.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]

核心参数解读:

  1. 限流规则名称不能超过 128 字节 。
  2. 限流规则个数目前无限制 。
  3. DBname 和 tablename在MySQL模式下会受 lower_case_table_names 变量的影响。
  4. 关键字之间将用通配符%连接,例如给定3个关键词   'abc' , 'c1 = 2' , 'xyz'   后续将按照 '%abc%c1=2%xyz%'  这个字符串进行SQL 文本的通配匹配。
  5. 当关键字中有'_'时会被转义,如关键字'table_t1'会被记录成'%table_t1%',限流关键字无个数限制,但限制拼凑后的字符串长度不能超过OB_MAX_VARCHAR_LENGTH=1048576 。
  6. 关键字字符串的字符集和字符序为binary 其中 MAX_CONCURRENCY=10指单机并发上限,即其为机器级而非集群级的。比如假设集群有3 台机器,那么指的是这三台机器各自的限流并发上限为 10。
  7. per sql为可选的选项。如果没有 per sql,表示统计粒度为规则级别,那么sql1和sq12同一时间全部 SQL 数量总计不能超过 10;如果有 per sql,表示统计粒度为 Format SQL_ID 语句级别,sq1和sql2 将各自被限制执行并发上限,同一时间每个 SQL 数量总计不能超过 10。

eg:不加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;

同时执行两个语句

执行结果:命中限流规则

加per sql

统计粒度:每个格式化后的 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

AFFECT_DML值和对应的SQL类型

0        ALL

1 SELECT

2 UPDATE

3 INSERT

4 DELETE

SQL限流是数据库运维的最后一道防线,OceanBase关键字限流彻底解决了传统限流的滞后性问题,实现 前置拦截、精准控流、低耗高效。

你在运维实战中,曾遭遇哪些棘手难题?欢迎在评论区交流!

为感谢瑞蓝创粉丝支持,我们特意设置宠粉福利

🎁 粉丝专属福利 OBCA V4 考券 免费申领!

https://mp.weixin.qq.com/s/Tl1MBGKjjBVzTmVq2IY1gA


🎯 获奖规则: 在【瑞蓝创软件】公众号本条推文(上方链接)评论区留言参与互动


留言点赞量 前 3 名小伙伴,可以免费获取“OBCA V4 考券”1张!


⏰ 活动时间截止至 2026 年 3 月 27 日 17:00

更多福利活动正在路上,超多运维干货持续更新!微信公众号【瑞蓝创软件】 关注不迷路 , 福利不错过 !

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70047467/viewspace-3114641/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
专注于企业信息科技战略咨询、数据中心规划及运维、智能化软件产品研发,致力于为金融、能源、电信、制造等行业提供智能的业务永续及流程自动化解决方案。

注册时间:2025-09-08

  • 博文量
    89
  • 访问量
    86720