跳到主要内容

查询熔断:SQL Block Rule 与 Workload Policy 配置指南

查询熔断是一种保护机制,用于防止长时间运行或消耗过多资源的查询影响集群稳定性。当查询超过预设的资源或时间限制时,熔断机制自动终止该查询,避免单个查询耗尽系统资源、拖慢其他业务。

Doris 提供两种熔断策略,分别作用于查询生命周期的不同阶段:

对比维度SQL Block Rule(规划时熔断)Workload Policy(运行时熔断)
生效阶段查询规划阶段,执行前拦截查询执行阶段,运行中熔断
判断依据预估扫描量、SQL 模式匹配实际执行时间、内存占用、扫描量等实时指标
准确性基于代价估算,可能存在误判基于实时监测,更加准确
适用场景阻止已知危险 SQL 模式和全表扫描熔断运行中超出预期的大查询
适用语句任意语句(DDL、DML)select、insert into select、stream load、routine load

SQL Block Rule

SQL Block Rule(SQL 阻止规则)在查询规划阶段拦截符合特定模式的语句,阻止其进入执行阶段。通常由 DBA 配置,用于防止全表扫描、危险函数调用等已知风险操作。

规则属性说明

每条规则由以下属性定义其行为和作用范围:

属性说明取值
sql匹配查询语句的正则表达式Java 正则表达式字符串
sqlHash匹配查询语句的哈希值SQL 哈希值字符串
cardinality允许扫描的最大行数正整数
partition_num允许扫描的最大分区数正整数
tablet_num允许扫描的最大分桶数正整数
global是否为全局规则"true"(全局生效)/ "false"(仅对绑定用户生效)
enable是否启用规则"true" / "false"

使用场景与示例

场景一:限制扫描行数

问题SELECT * FROM t 等全表扫描操作会大量消耗 BE 的 IO 和 CPU 资源。

方案:设置单表扫描行数上限,超过阈值的查询将被阻止。

CREATE SQL_BLOCK_RULE rule_card 
PROPERTIES
(
"cardinality" = "1000",
"global" = "true",
"enable" = "true"
);

单表扫描超过 1000 行时,查询将被拒绝执行。

场景二:限制扫描分区数

问题:扫描过多分区会显著增加 BE 的 CPU 消耗;查询外表时还会带来额外的网络开销和元数据拉取开销,通常由遗漏或写错分区过滤条件导致。

方案:设置单次查询可扫描的最大分区数。

CREATE SQL_BLOCK_RULE rule_part_num 
PROPERTIES
(
"partition_num" = "30",
"global" = "true",
"enable" = "true"
);

单表扫描分区数超过 30 个时,查询将被拒绝执行。

场景三:限制扫描分桶数

问题:扫描过多分桶同样会显著增加 BE 的 CPU 消耗。

方案:设置单次查询可扫描的最大分桶数。

CREATE SQL_BLOCK_RULE rule_tablet_num 
PROPERTIES
(
"tablet_num" = "200",
"global" = "true",
"enable" = "true"
);

单表扫描分桶数超过 200 个时,查询将被拒绝执行。

场景四:阻止特定 SQL 模式

问题:某些查询模式(如调用特定函数、执行危险操作)可能导致计算复杂度过高或规划时间过长。

方案:通过正则表达式匹配阻止这类查询。

示例 1:阻止使用特定函数

以下规则阻止所有包含 abs 函数的查询:

CREATE SQL_BLOCK_RULE rule_abs
PROPERTIES(
"sql"="(?i)abs\\s*\\(.+\\)",
"global"="true",
"enable"="true"
);

正则说明:

  • (?i):大小写不敏感匹配
  • abs:目标函数名
  • \\s*:允许函数名与左括号之间有任意空白
  • \\(.+\\):匹配函数参数部分

示例 2:阻止危险操作

同理,可用正则阻止 set global(防止非预期的变量修改)或 truncate table(防止非预期的数据删除)。

正则表达式使用 Java 规范,详见 Pattern 文档

场景五:针对特定用户设置规则

问题:默认规则全局生效,但某些场景下只需对特定用户启用限制。

方案:创建非全局规则并绑定到目标用户。

  1. 创建规则时将 global 设为 "false"

    CREATE SQL_BLOCK_RULE rule_001
    PROPERTIES (
    "sql"="select \\* from t",
    "global" = "false",
    "enable" = "true"
    );
  2. 将规则绑定到目标用户:

    SET PROPERTY FOR 'root' 'SQL_block_rules' = 'rule_001';
  3. 验证规则已生效:

    MySQL root@127.0.0.1:test> select * from t;
    (1105, 'errCode = 2, detailMessage = errCode = 2, detailMessage = SQL match regex SQL block rule: rule_001')

多规则管理

  • 为一个用户绑定多条规则:在规则列表中以英文逗号分隔所有规则名,例如 'rule_001,rule_002'
  • 移除用户的所有规则:将规则列表置为空字符串,例如 SET PROPERTY FOR 'root' 'SQL_block_rules' = '';

注意事项

  • 估算方式:扫描行数、分区数、分桶数均在规划阶段基于最坏情况估算(仅考虑分区裁剪和分桶裁剪,不计其他过滤条件),实际扫描量小于设置值的查询也可能被阻止。
  • 性能影响:正则匹配是计算密集型操作,过多或过于复杂的正则规则会给 FE 的 CPU 带来显著压力,建议谨慎添加。
  • 临时关闭规则:将规则属性中的 "enable" 修改为 "false" 即可临时禁用,无需删除规则。

Workload Policy

Workload Policy(负载策略)在查询运行时对实时指标进行监测,并对超出预期的查询执行熔断或变量调整等动作。相比 SQL Block Rule 的静态规划估算,Workload Policy 基于实际运行数据,判断更加准确。

Workload Policy 自 Doris 2.1 版本起支持,各负载类型的支持情况如下:

负载类型是否支持
select支持
insert into select支持
insert into values不支持
stream load支持
routine load支持
backup不支持
compaction不支持

创建与配置

使用 CREATE WORKLOAD POLICY 命令创建策略,需要 admin_priv 权限。

基本语法

CREATE WORKLOAD POLICY <policy_name>
CONDITIONS(<condition_expr>)
ACTIONS(<action_expr>)
PROPERTIES('<key>'='<value>');

以下示例创建一个取消运行时间超过 1000 ms 的查询的策略:

CREATE WORKLOAD POLICY test_cancel_policy
CONDITIONS(query_time > 1000)
ACTIONS(cancel_query)
PROPERTIES('enabled'='true');

触发条件(Conditions)

Conditions 表示策略的触发条件,多个条件之间以逗号 , 分隔,表示"与"关系。

Condition说明
username查询携带的用户名,只会在 FE 触发 set_session_variable Action
be_scan_rows一个 SQL 在单个 BE 进程内扫描的行数,多并发执行时为累加值
be_scan_bytes一个 SQL 在单个 BE 进程内扫描的字节数,多并发执行时为累加值(单位:字节)
query_time一个 SQL 在单个 BE 进程上的运行时间(单位:毫秒)
query_be_memory_bytes一个 SQL 在单个 BE 进程内使用的内存量,多并发执行时为累加值(单位:字节)

执行动作(Actions)

Actions 表示条件触发时采取的动作。目前一个 Policy 只能定义一个 Action(set_session_variable 除外)。

Action说明
cancel_query取消查询
set_session_variable执行 set session variable 语句;同一个 Policy 可包含多个该选项,目前只会在 FE 由 username Condition 触发

策略属性(Properties)

Property说明默认值
enabled是否启用,取值为 truefalsetrue
priority优先级,取值范围 0~100,值越大优先级越高;多个 Policy 匹配时只有优先级最高的生效0
workload_group绑定的 Workload Group 名称,指定后 Policy 仅对该 Workload Group 的查询生效;为空时对所有查询生效空(全局)

绑定 Workload Group

如需将策略限定在某个 Workload Group 内,通过 workload_group 属性绑定:

CREATE WORKLOAD POLICY test_cancel_big_query
CONDITIONS(query_time > 1000)
ACTIONS(cancel_query)
PROPERTIES('workload_group'='normal');

使用示例

示例一:熔断超时查询

以下审计日志显示,某个 SQL 正常执行需要 4.5 秒:

MySQL [hits]> SELECT REGEXP_REPLACE(Referer, '^https?://(?:www\\.)?([^/]+)/.*$', '\\1') AS k, AVG(length(Referer)) AS l, COUNT(*) AS c, MIN(Referer) FROM hits WHERE Referer <> '' GROUP BY k HAVING COUNT(*) > 100000 ORDER BY l DESC LIMIT 25;
+-----------------------------------------------------------------------+------------------+----------+---------------------------------------------------------------------------------------------------------------------+
| k | l | c | min(Referer) |
+-----------------------------------------------------------------------+------------------+----------+---------------------------------------------------------------------------------------------------------------------+
| 1 | 85.4611926713085 | 67259319 | http://%26ad%3D1%25EA%25D0%26utm_source=web&cd=19590&input_onlist/би-2 место будущей кондицин |
| http:%2F%2Fwwww.regnancies/search&evL8gE&where=all&filmId=bEmYZc_WTDE | 69 | 207347 | http:%2F%2Fwwww.regnancies/search&evL8gE&where=all&filmId=bEmYZc_WTDE |
| http://новострашная | 31 | 740277 | http://новострашная |
| http://loveche.html?ctid | 24 | 144901 | http://loveche.html?ctid |
| http://rukodeliveresult | 23 | 226135 | http://rukodeliveresult |
| http://holodilnik.ru | 20 | 133893 | http://holodilnik.ru |
| http://smeshariki.ru | 20 | 210736 | http://smeshariki.ru |
| http:%2F%2Fviewtopic | 20 | 391115 | http:%2F%2Fviewtopic |
| http:%2F%2Fwwww.ukr | 19 | 655178 | http:%2F%2Fwwww.ukr |
| http:%2F%2FviewType | 19 | 148907 | http:%2F%2FviewType |
| http://state=2008 | 17 | 139630 | http://state=2008 |
+-----------------------------------------------------------------------+------------------+----------+---------------------------------------------------------------------------------------------------------------------+
11 rows in set (4.50 sec)

创建一个运行时间超过 3 秒即取消查询的策略:

CREATE WORKLOAD POLICY test_cancel_3s_query
CONDITIONS(query_time > 3000)
ACTIONS(cancel_query);

再次执行同一 SQL,查询被熔断:

MySQL [hits]> SELECT REGEXP_REPLACE(Referer, '^https?://(?:www\\.)?([^/]+)/.*$', '\\1') AS k, AVG(length(Referer)) AS l, COUNT(*) AS c, MIN(Referer) FROM hits WHERE Referer <> '' GROUP BY k HAVING COUNT(*) > 100000 ORDER BY l DESC LIMIT 25;
ERROR 1105 (HY000): errCode = 2, detailMessage = (127.0.0.1)[CANCELLED]query cancelled by workload policy,id:12345

示例二:自动调整用户 Session 变量

通过 Workload Policy 可自动修改特定用户的 session 变量,例如降低其并发度以减少资源占用:

-- 查看 admin 用户当前并发参数
MySQL [(none)]> show variables like '%parallel_fragment_exec_instance_num%';
+-------------------------------------+-------+---------------+---------+
| Variable_name | Value | Default_Value | Changed |
+-------------------------------------+-------+---------------+---------+
| parallel_fragment_exec_instance_num | 8 | 8 | 0 |
+-------------------------------------+-------+---------------+---------+
1 row in set (0.00 sec)

-- 创建策略:将 admin 用户的并发参数调整为 1
CREATE WORKLOAD POLICY test_set_var_policy
CONDITIONS(username='admin')
ACTIONS(set_session_variable 'parallel_fragment_exec_instance_num=1');

-- 稍后再次查看,参数已生效
MySQL [(none)]> show variables like '%parallel_fragment_exec_instance_num%';
+-------------------------------------+-------+---------------+---------+
| Variable_name | Value | Default_Value | Changed |
+-------------------------------------+-------+---------------+---------+
| parallel_fragment_exec_instance_num | 1 | 8 | 1 |
+-------------------------------------+-------+---------------+---------+
1 row in set (0.01 sec)

注意事项

  • FE/BE 侧隔离:同一个 Policy 的 Condition 和 Action 必须属于同一侧(FE 或 BE)。例如,set_session_variable(FE 侧)和 cancel_query(BE 侧)不能配置在同一 Policy 中;username(FE 侧)和 be_scan_rows(BE 侧)同理。
  • 异步执行延迟:Policy 由异步线程每 500 ms 执行一次检查,策略生效存在一定滞后。运行时间极短的查询可能会在检查触发前已完成,从而绕过策略。
  • 优先级机制:一个查询可能匹配多个 Policy,但只有优先级最高(priority 值最大)的 Policy 会生效。
  • 修改限制:目前不支持直接修改已有 Policy 的 Action 和 Condition,需删除后重新创建。