本文分享自华为云社区《GaussDB(DWS)查询过滤器原理与应用》,作者:门前一棵葡萄树 。
一、概述
GaussDB(DWS)查询过滤器(黑名单)提供查询过滤功能,支持自动隔离反复被终止的查询,防止烂 SQL 再次执行。
主要应用场景包含以下两种:
1. 异常熔断机制
配置异常规则后,查询触发异常规则后,异常信息将被记录在 dbms_om.gs_blocklist_query 系统表中。同一个查询触发异常规则次数超限(query_exception_count_limit)后,查询自动加入黑名单,黑名单信息同样保存在 dbms_om.gs_blocklist_query 系统表中。加入黑名单后,该查询将被隔离,拒绝执行。
2. 紧急拦截
作业引发 CORE、hang 或性能大幅下降等问题时,需要紧急规避时,可以将作业加入黑名单进行过滤。
原理介绍
查询过滤器使用作业 Unique SQL ID 保存和识别作业黑名单和异常信息,在 SQL 中常数值发生变化时作业 Unique SQL ID 不会随之发生变化。Unique SQL ID 是遍历查询解析树计算出来的一个整数值,用于标识一类 SQL。通常对于 DML 语句,在计算 Unique SQL ID 的过程中会忽略常量值。但对于 DDL、DCL 以及设置参数等语句,常量值不会忽略。例如,以下两个查询:
select * from t1 where id = 1;
select * from t1 where id = 2;
复制代码
这两条 SQL 除过滤条件中的常量不同外,其他全部相同,由此生成的解析树拓扑完全相同,因此 Unique SQL ID 相同。Unique SQL ID 的计算只会忽略常数值,而不会忽略其他差异,SQL 语句“select * from t2 where id = 1;”与上述两个 SQL 的 Unique SQL ID 就不相同。
将作业加入黑名单主要有以下两种方式:
作业执行前判断作业是否在黑名单中,如果作业在黑名单中,拒绝作业执行,直接报错退出。
作业被拒绝执行后,对作业加入黑名单原因进行分析,问题解决后调用内置函数 gs_remove_blocklist(unique_sql_id int8)将作业移除黑名单。
二、应用示例
2.1 异常熔断示例
1. 设置异常熔断阈值。假设设置 query_exception_count_limit=1,即只要作业触发异常规则作业就会被加入黑名单。
2. 配置异常规则
创建 CPU 平均使用率异常规则 cpu_percent_except,作业运行时间超过 2000 秒且 CPU 使用率达到 30%时触发异常退出:
CREATE EXCEPT RULE cpu_percent_except WITH(ELAPSEDTIME=2000, CPUAVGPERCENT=30);
复制代码
异常规则还支持 BLOCKTIME、ALLCPUTIME、SPILLSIZE 等异常的识别处理,具体可参考:异常规则简介与演变。
3. 创建资源池 respool1 关联异常规则 cpu_percent_except。
CREATE RESOURCE POOL respool1 WITH(except_rule='cpu_percent_except');
复制代码
资源池支持最多关联 63 个异常规则集,每个异常规则集间独立生效,互不影响。
4. 创建业务用户 usr1,关联资源池 respool1:
CREATE USER usr1 RESOURCE POOL 'respool1' PASSWORD 'XXXXXX';
复制代码
5. 用户 usr1
运行作业,作业运行时间超过 2000 秒且 CPU 使用率达到 30%时触发“cpu_percent_except”异常规则,作业触发异常规则后资源管理对作业进行以下处理:
将作业异常信息保存至系统表 GS_BLOCKLIST_QUERY 中;
如果作业触发异常熔断,将系统表 GS_BLOCKLIST_QUERY 中作业黑名单标志置为 true;
更新 GS_BLOCKLIST_QUERY 中作业黑名单信息。
6. 查询作业黑名单和异常信息:
SELECT * FROM dbms_om.gs_blocklist_query;
unique_sql_id | block_list | except_num | except_time
---------------+------------+------------+----------------------------
4066836196 | t | 1 | 2022-08-08 18:00:00.596269
(1 row)
复制代码
7. 用户 usr1 再次运行作业触发异常熔断,GaussDB(DWS)的异常熔断机制禁止该作业执行。
ERROR: The query is in the blocklist and cannot be run, unique_sql_id(4066836196).
HINT: If you want to run the query later, confirm the reason why the query is blocklisted and remove the query from the blocklist after resolving the problem.
复制代码
8. 优化用户 usr1 所运行 ID 为 4066836196 的 SQL 后,将 ID 为 4066836196 的 SQL 从黑名单移除。
确认 SQL 异常原因,如果异常规则配置不合理,修改异常规则;如果异常规则合理,对 SQL 进行优化后重新运行。确认问题解决后将 SQL 移除黑名单。
select gs_remove_blocklist(4066836196);
gs_remove_blocklist
---------------------
t
(1 row)
复制代码
2.2 紧急拦截示例
查询过滤器使用作业 Unique SQL ID 识别和保存黑名单信息,为有效运用查询过滤器紧急拦截功能,建议 TopSQL 开启,在作业引发 CORE、报错、性能下降等问题时可以快速获取作业 Unique SQL ID。
2.2.1 获取作业 Unique SQL ID
获取作业 Unique SQL ID 的几种方法:
1. 作业引发报错/性能下降
CN 日志中获取作业 query_id,执行以下命令查询作业 Unique SQL ID。
select queryid,unique_sql_id,query from pgxc_wlm_session_info where queryid=query_id;
复制代码
2. 作业引发 CN 示例 CORE
解析 CORE 打印内存中保存的 Unique SQL ID 对应的变量参数值。
3. 作业引发 DN 实例 CORE
作业引发 DN 实例 CORE 时,CN 侧体现为作业报错,Unique SQL ID 获取方式可以参考作业报错时 Unique SQL ID 获取方式。
4. EXPLAIN VERBOSE 获取 Unique SQL ID(通用方法,但是仅 821 及以上版本支持)
EXPLAIN VERBOSE 不会实际执行 SQL,因此一般不会导致问题发生,使用 EXPLAIN VERBOSE XXX;可以打印得到作业 Unique SQL ID。示例:
postgres=# explain verbose select count(1) from pg_class;
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
id | operation | E-rows | E-distinct | E-width | E-costs
----+----------------------------------------+--------+------------+---------+---------
1 | -> Aggregate | 2 | | 8 | 52.94
2 | -> Seq Scan on pg_catalog.pg_class | 1034 | | 0 | 50.34
Targetlist Information (identified by plan id)
------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------------------------------------
1 --Aggregate
Output: count(1)
2 --Seq Scan on pg_catalog.pg_class
Output: relname, relnamespace, reltype, reloftype, relowner, relam, relfilenode, reltablespace, relpages, reltuples, relallvisible, reltoastrelid, reltoas
tidxid, reldeltarelid, reldeltaidx, relcudescrelid, relcudescidx, relhasindex, relisshared, relpersistence, relkind, relnatts, relchecks, relhasoids, relhaspkey, r
elhasrules, relhastriggers, relhassubclass, relcmprs, relhasclusterkey, relrowmovement, parttype, relfrozenxid, relacl, reloptions, relreplident, relfrozenxid64
====== Query Summary =====
--------------------------
Parser runtime: 0.027 ms
Planner runtime: 0.561 ms
Unique SQL Id: 2307078791
(17 rows)
复制代码
2.2.2 将作业加入黑名单
获取到作业 Unique SQL ID 后,调用内置函数 gs_append_blocklist(unique_sql_id int8)将作业加入黑名单:
postgres=# select * from gs_append_blocklist(2307078791);
gs_append_blocklist
---------------------
t
(1 row)
复制代码
2.2.3 查询黑名单信息
作业加入黑名单后,查询系统表确认黑名单加入是否成功:
postgres=# SELECT * FROM dbms_om.gs_blocklist_query;
unique_sql_id | block_list | except_num | except_time
---------------+------------+------------+-------------
2307078791 | t | 0 |
(1 row)
复制代码
2.2.4 再次执行作业触发紧急拦截
postgres=# select count(1) from pg_class;
ERROR: The query is in the blocklist and cannot be run, unique_sql_id(2307078791).
HINT: If you want to run the query later, confirm the reason why the query is blocklisted and remove the query from the blocklist after resolving the problem.
复制代码
2.2.5 问题解决,将作业移出黑名单
postgres=# select gs_remove_blocklist(2307078791);
gs_remove_blocklist
---------------------
t
(1 row)
复制代码
点击关注,第一时间了解华为云新鲜技术~
评论