GaussDB(DWS)查询过滤器原理与应用

Posted 华为云开发者社区

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GaussDB(DWS)查询过滤器原理与应用相关的知识,希望对你有一定的参考价值。

摘要:GaussDB(DWS)查询过滤器(黑名单)提供查询过滤功能,支持自动隔离反复被终止的查询,防止烂SQL再次执行。

本文分享自华为云社区《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就不相同。

将作业加入黑名单主要有以下两种方式:

  • 在GUC参数query_exception_count_limit≥0情况下,作业触发异常次数超过该阈值后自动将作业加入黑名单;
  • 调用内置函数gs_append_blocklist(unique_sql_id int8)将作业加入黑名单。

作业执行前判断作业是否在黑名单中,如果作业在黑名单中,拒绝作业执行,直接报错退出。

作业被拒绝执行后,对作业加入黑名单原因进行分析,问题解决后调用内置函数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)

 

点击关注,第一时间了解华为云新鲜技术~

详解GaussDB(DWS)的query_band负载识别与应用

摘要:query_band是一个会话级别(session)的GUC参数,本身是字符串类型,支持任意形式字符组合。

本文分享自华为云社区《GaussDB(DWS)的query_band负载识别与应用》,作者:门前一棵葡萄树。

query_band概述

GaussDB(DWS)实现了基于query_band的负载识别和优先级调度,一方面提供了更为灵活的负载识别手段,不再局限于依据“用户-资源池”的映射关系将作业路由至对应资源池,提供了“键值对-资源池”的路由方式;另一方面实现了作业优先级调度,出现排队时按照优先级调度作业。

管理员用户可根据业务场景及作业类别配置query_band关联的资源池和优先级等实现更为灵活的负载管理。如果业务未配置query_band或用户未将query_band关联行为时,作业会默认使用用户关联的资源池和默认优先级(Medium)。

query_band是什么?

query_band是一个会话级别(session)的GUC参数,本身是字符串类型,支持任意形式字符组合。query_band用于负载识别时,为了便于区分、解决无意义字符串难以理解的问题,仅支持识别键值对形式的字符串。query_band键值对有以下限制:

  • 仅支持识别键值对形式的字符串,即:“key=value”;
  • 有效字符:数字0~9、大写字母A~Z、小写字母a~z以及部分符号(‘.’、‘-’、‘_’ 以及‘#’);
  • 单个键值对最大长度1024;
  • 支持多个键值对组合,键值对之间使用分号分隔;
  • 示例:SET query_band = ‘JobName=abc;AppName=test;ApplicationName=jdbc’。

query_band负载识别

GaussDB(DWS)提供的资源管理功能,从资源池维度实现了资源隔离管控和查询调度,借此实现了不同业务间的资源隔离。资源池作为资源管控和查询调度的基本单位,查询运行前需要确定使用哪个资源池,在查询调度和查询运行过程中使用该资源池资源(计算资源/并发等)。

查询是由用户发起运行的,而且一般情况下用户都是按业务划分的,因此理所当然地就想到将用户和资源池关联起来,以此实现用户的查询在对应资源池运行的效果。GaussDB(DWS)提供了用户-资源池关联的能力,默认情况下用户关联默认资源池,可根据业务需求创建自定义资源,并将用户关联至自定义资源池,用户查询依据“用户-资源池”的关联关系将查询路由至对应资源池执行,以此实现对查询并发、内存及CPU资源的管控。从而实现对不同业务之间的资源限制和隔离,满足数据库混合负载需求,保证查询执行时资源调度的有序可控。

“用户-资源池”提供的用户和资源池的关联关系,对于用户和业务混合交叉(多个用户均对应多个业务)的场景就不适用了。此外一个资源池内不同用户的作业可能有不同优先级,此时就需要给不同用户或业务配置不同优先级,实现优先级调度。因此就需要提供一种能力,一方面不再局限于“用户-资源池”的关联方式,一方面还可以实现资源池内的优先级调度。这种情况下,query_band负载识别应运而生。

query_band负载识别提供了两方面能力:

  • 一方面提供了更为灵活的负载识别手段,不再局限于依据“用户-资源池”的映射关系将作业路由至对应资源池,提供了“键值对-资源池”的路由方式;
  • 另一方面实现了优先级调度,支持为不同用户或业务设置不同的优先级,实现资源池内的优先级调度。

query_band功能实现

工作原理

query_band负载识别以键值对为单位,用户使用的键值对可能有很多,但实际上关联负载行为的键值对只有很少的一部分,为方便后续理解,这里按是否关联负载行为,将键值对分为有效键值对和无效键值对:

有效键值对:有关联负载行为;

无效键值对:未关联任何负载行为。

会话内设置的query_band可能包含多个键值对,不同场景下可能要使用不同的键值对进行负载识别,以实现负载控制(分时/分天)。当query_band内包含唯一有效键值对时,使用该键值对进行负载识别;当query_band内包含多个有效键值对时,按以下规则选择有效键值对进行负载识别:

  • 键值对匹配顺序不同时,优先选择匹配序号最小的键值对进行负载识别;
  • 所有键值对匹配顺序相同时,按照先后顺序选择靠前的键值对进行负载识别

示例:假设set query_band=\'b=1;a=3;c=1\'中所有键值对匹配顺序都一样,则选择b=1进行负载识别;假设set query_band=‘b=1;a=3;c=1’ ,其中b=1顺序为-1,a=3顺序为4,c=1顺序为1,则选择c=1进行负载识别。

识别能力

管理员用户根据业务场景和负载变化,调整业务(不同业务对应不同query_band键值对)使用的资源池和调度优先级。业务运行过程中负载识别与query_band工作机制如下:

  1. 会话内设置query_band,示例:SET query_band=\'JobName=abc;UserName=elk\';
  2. 负载管理模块解析query_band,判断其中是否包含有效键值对;
  3. query_band内不包含有效键值对,则使用"用户-资源池"的方式将作业路由至对应资源池运行,同时设置作业优先级为Medium;
  4. query_band内包含有效键值对,则使用“键值对-资源池”的方式将作业路由至对应资源池运行,同时设置作业优先级为键值对关联优先级;
  5. 作业在对应资源池,按照设置的优先级进行排队,等待查询调度。

优先级调度

query_band支持高中低(High/Medium/Low)三个优先级,同时提供Rush作为特殊优先级(绿色通道),默认优先级为Medium。实践过程中,建议大部分作业使用Medium优先级,优先级较低作业使用Low优先级,特权作业使用High优先级,High作业不建议过多。Rush优先级作为特殊场景下应急使用,平时不建议使用。

调度时优先调度高优作业,高优作业全部调度完才调度低优作业,GaussDB(DWS)包含多个优先级队列。除动态负载管理场景下,CN全局并发控制队列不支持优先级调度外,以下队列均支持优先级调度(按优先级顺序调度):

  • 静态负载管理场景下,CN全局并发控制队列;
  • 动态负载管理场景下,CCN全局内存管控队列;
  • 资源池并发控制和内存管控队列。(动态静态均支持)

作业运行过程中可通过pgxc_session_wlmstat/pg_session_wlmstat视图查询作业优先级,视图中优先级显示为INT类型,数字和优先级对应关系如下:

query_band对外接口

gs_wlm_set_queryband_action

提供FUNCTION:gs_wlm_set_queryband_action(query_band cstring, action cstring, order int4)用于设置query_band负载行为,函数返回值类型为bool,表示函数调用是否成功,包含三个入参,含义如下:

  • query_band:query_band键值对
  • action:负载行为
  • order:匹配顺序(序号),缺省参数,默认值-1

应用示例:设置query_band键值对“UserName=elk”关联资源池p1、优先级Rush、匹配顺序为1。

SELECT * FROM gs_wlm_set_queryband_action(\'UserName=elk\',\'respool=p1;priority=rush\',1);

gs_wlm_set_queryband_order

提供FUNCTION:gs_wlm_set_queryband_order(query_band cstring, order int4)用于修改query_band匹配顺序,函数返回值类型为bool,表示函数调用是否成功,包含两个入参,含义如下:

  • query_band:query_band键值对
  • order:匹配顺序(序号),缺省参数,默认值-1

除-1外,不允许两个query_band键值对使用相同匹配顺序,设置query_band键值对匹配顺序时,如果存在query_band持有该匹配顺序,则其顺序自动+1,重复上述步骤直至无相同匹配顺序的query_band键值对存在。匹配顺序中-1最大,代表匹配优先级最低,最小值为0,代表匹配优先级最高。

应用示例:假设query_band键值对“UserName=elk”的匹配顺序为1,“UserName=bin”的匹配顺序为2,“UserName=yagao”的匹配顺序为3,此时设置query_band键值对“UserName=on”匹配顺序为1。

SELECT * FROM gs_wlm_set_queryband_order(\'UserName=on\',1);

设置完成后,query_band键值对匹配顺序如下:

系统表pg_workload_action

query_band支持多种负载行为,使用系统表pg_workload_action存储不同query_band键值对对应的负载行为。为了后续扩展性(新增负载行为不需要新增字段),系统表设计采用一行对应一个负载行为的方式存储,当一个query_band键值对关联多个负载行为时,每个负载行为存储一行数据。系统表包含四个字段:

  • qband:键值对
  • class:负载行为类别
  • object:负载行为名称
  • action:关联的负载行为

query_band目前支持以下负载行为,其中query_band键值对的匹配顺序(序号)也作为一种负载行为存储在系统表中。

备注:默认值不需要存储在系统表中;资源池保存的是OID。

示例:假设已经设置query_band键值对“UserName=elk”关联资源池p1、优先级Rush、匹配顺序为1;“UserName=on”关联资源池p1、优先级Medium、匹配顺序为-1。查询pg_workload_action结果如下:

postgres=# select * from pg_workload_action order by 1,2;
 qband | classname | objname | action
--------------+-----------+----------+--------
 UserName=elk | order | respool  | 1
 UserName=elk | workload  | respool  | 16722
 UserName=elk | workload  | priority | rush
 UserName=on | workload  | respool  | 16722
(4 rows)

pg_queryband_action视图

pg_workload_action系统表用于存储query_band键值对负载行为,查询query_band行为可以直接查询该表,但是随着每一个负载行为显示一行的方式易用性较差,因此我们提供了pg_queryband_action用于查询所有query_band键值对的负载行为,每一行对应一个键值对的所有负载行为。

示例:假设已经设置query_band键值对“UserName=elk”关联资源池p1、优先级Rush、匹配顺序为1;“UserName=on”关联资源池p1、优先级Medium、匹配顺序为-1。查询pg_queryband_action结果如下:

postgres=# select * from pg_queryband_action;
 qband | respool_id | respool | priority | qborder
--------------+------------+---------+----------+---------
 UserName=on | 16722 | p1      | Medium   | -1
 UserName=elk | 16722 | p1      | rush     | 1
(2 rows)

query_band应用

基础应用

创建资源池respool_1,并创建用户user_1关联资源池respool_1、respool_2。不设置query_band负载行为场景下,使用user_1用户运行作业,此时user_1作业全部路由至respool_1运行,优先级为Medium。

设置query_band键值对"JobName=elk"的负载行为为关联资源池respool_2,优先级为Medium;设置query_band键值对"JobName=on"的负载行为为优先级High。user_1用户分别设置不同的query_band运行作业,不同作业运行方式、关联资源池及作业优先级如下表所示:

扩展应用(用户优先级调度)

创建资源池respool_1,并创建用户user_1、user_2、user_3关联资源池respool_1。不设置query_band负载行为场景下,使用user_1、user_2和user_3用户运行作业,此时user_1、user_2和user_3作业全部路由至respool_1运行,优先级均为Medium。

设置query_band键值对"UserName=elk"的优先级为High;设置query_band键值对"UserName=on"的优先级为Low。

备注:“UserName=elk”、“UserName=on”只用于用户标识,没有特殊含义,用户可按需配置。

按以下方式设置用户默认query_band:

ALTER USER user_2 SET query_band=\'UserName=elk\';
ALTER USER user_3 SET query_band=\'UserName=on\'; 

会话内不单独设置query_band,使用user_1、user_2和user_3用户运行作业,此时user_1作业优先级为Medium(默认优先级),user_2作业优先级为High(对应键值对“UserName=elk”),user_3作业优先级为Low(对应键值对“UserName=on”)。

此外,用户还可设置包含多个键值对的query_band,在不同场景下(或不同时间段),按照不同键值对进行负载识别,实现更为灵活的负载控制,这里就不再赘述了。

 

点击关注,第一时间了解华为云新鲜技术~

以上是关于GaussDB(DWS)查询过滤器原理与应用的主要内容,如果未能解决你的问题,请参考以下文章

详解GaussDB(DWS)的query_band负载识别与应用

GaussDB(DWS)如何实现实时,批量和交付式查询一站式开发

GaussDB(DWS)如何实现实时,批量和交付式查询一站式开发

GaussDB(DWS)如何实现实时,批量和交付式查询一站式开发

猿创征文|GaussDB(DWS)如何实现实时,批量和交付式查询一站式开发

列举GaussDB(DWS)常见的查询时索引失效场景