写点什么

一文详解 GaussDB(DWS) 的并发管控和内存管控

  • 2022-11-24
    中国香港
  • 本文字数:6888 字

    阅读完需:约 23 分钟

一文详解GaussDB(DWS) 的并发管控和内存管控

本文分享自华为云社区《GaussDB(DWS) 并发管控&内存管控》,作者: fighttingman。

1 背景


这里将并发管控和内存管控写在一起,是因为内存管控实际是通过限制语句的并发达到内存管控的目的的。内存管控是基于语句的估算内存的前提下进行管控的,通俗的说就是语句有个估算内存,当资源池的剩余内存小于语句的估算内存时,这个语句就会排队等待,等资源池内的语句执行完,资源池有足够的剩余内存的时候,才会让这个语句执行。所以内存管控的实际效果和语句的估算内存有很大关系,估算的大了就会造成大量语句排队,实际没有使用那么多内存,造成内存资源浪费,相反估算的小了,就会有很多语句下发,实际内存使用就会变多,就有语句报内存不足的错误风险。


数据库系统的并发控制,在整个系统中起着很重要的作用,比如很多用户的业务压力过大时,有时会导致连接数量被占满,有时会导致某种计算资源被占满,有时会导致存储空间被占满,这些情况都会导致整个集群进入异常甚至不可用的状态:正在执行的作业互相争抢 CPU,会导致大家都不能好好执行;大量作业执行时,占用大量内存,很容易触发到内存瓶颈,造成作业内存不可用问题,导致业务报错等等。在不进行并发控制的情况下,这些情况都很可能会出现,影响到正常业务。

2 总体介绍


DWS 的负载管理分为两层,第一层为 cn 的全局并发控制,第二层为资源池级别的并发控制。在通过第一层控制的时候,会继续向前走到第二层资源池控制,根据资源池当前的负载资源情况决定作业继续执行或者排队。


基于 DWS 并发控制逻辑看出,实际作业执行中,可能会在两种队列中排队:


一种是全局队列(global queue)这种队列不区分简单和复杂作业,也不区分是 DDL 或者是普通语句,这种是每个 cn 生效。


一种是资源池队列(resource pool queue),用户下发的一般语句会根据资源消耗估算以及复杂程度在这里进行判断是否排队。


在两层队列的过滤下,DWS 会筛选出当前能执行的语句,使其正常运行,运行时也会受到其所属资源池资源的限制(只能使用资源池配置的 CPU、内存、IO 配额)。

3 全局排队


这里介绍几个常用视图以及 SQL 语句,可以迅速判断目前的业务出现问题的原因,受限根据以下视图可以看到目前的作业是不是在排队,之后要迅速分析为什么在排队,是因为负载管理各个参数配置问题,还是因为正在执行的语句占据了过多的资源导致的排队。


pgxc_stat_activity (活跃视图)


查询当前执行时间最长的语句的排队状态,query_id(数据库中作业的唯一标识),以及详细的语句信息。


选择 coorname,usename,current_timestamp-query_start 作为持续时间,排队,query_id,从 pgxc_stat_activity 查询,其中 state='active'和 usename<>“Ruby”顺序按持续时间说明;


根据该语句可以迅速判断出哪些语句执行时间很长,是什么样的语句执行很慢以及该语句的 query_id,便于迅速进入下一步排查。


该视图中 enqueue 字段中如果显示正在等待全局队列就代表在全局排队。全局排队是受 GUC 参数 max_active_statements 参数控制的,是单 cn 生效的,也就是每个 cn 都可以支持这么大的并发量。比如集群中有 3 个 cn 实例,GUC 参数 max_active_statements 参数设置为 60,也就是说每个 cn 都支持 60 个语句并发执行,集群全局支持 3 * 60 = 180 并发执行作业。当下发作业大于这个 cn 设置的 max_active_statements 的时候就会进行全局排队,在 pgxc_stat_activity 视图中 enqueue 字段就会显示等待全局队列。

4 资源池排队

4.1 静态负载管理


当 GUC 参数 enable_dynamic_workload 设置为 off 的时候就代表是静态负载管理模式。静态负载管理的情况下,pgxc_stat_activity 视图中 enqueue 字段只会有 wait in repool queue。并发控制参数为资源池的 max_dop(简单作业)和 active_statements(复杂作业)。


1)简单作业和复杂作业的定义


在静态负载管理中,简单作业是估算代价成本值小于 GUC 参数 parctl_min_cost 值的作业。反之则判定为复杂作业。该 GUC 参数默认为 10W,当 parctl_min_cost 为-1 时,或者作业估算成本小于 10 时,作业都判定为简单作业。


2)简单作业并发限制


ALTER RESOURCE POOL resource_pool_a1 WITH (max_dop=10);
复制代码


通过设置资源池的 max_dop 参数设置简单作业并发,关联资源池 resource_pool_a1 的用户都受到这个参数的控制。当所有关联这个资源池的用户的所有作业数量之和大于这个参数的时候,就会进行资源池排队,活跃视图 enqueue 字段就会显示正在等待的 respool queue。


3)复杂作业并发限制


ALTER RESOURCE POOL resource_pool_a2 WITH (active_statements=10);
复制代码


通过设置资源池的 active_statements 参数控制复杂作业的并发数,关联资源池 resource_pool_a2 的用户都受到这个参数的控制。


  • 当 MEM_PERCENT 参数数值为 0 时,ACTIVE_STATEMENTS 为 x(1~INT_MAX),该资源池上的作业并发数不大于 x。

  • 当 ACTIVE_STATEMENTS 参数数值为-1 且 MEM_PERCENT 为正值时,并发由运行作业的内存估值和 MEM_PERCENT 的取值决定。

  • 当 MEM_PERCENT 参数数值为正值且 ACTIVE_STATEMENTS 为 x(1~INT_MAX)时,并发由运行作业的内存估值和 MEM_PERCENT 的取值决定,且并发不能大于 x。

  • 当 MEM_PERCENT 参数数值为 0 且 ACTIVE_STATEMENTS 为-1 时,资源池并发不受限。


资源池使用并发点数的计数方式来计算可执行的复杂作业并发数量,并发点数计算公式为


作业使用内存点数:active_points = (query_mem/respool_mem) * active_statements * 100


作业使用并发点数:active_points = 100


资源池总点数:total_points = active_statements * 100


单位点数: 100


4)相关说明


  • 资源池分快慢车道,快车道管控简单作业,慢车道管控复杂作业

  • MAX_DOP 对快车道并发进行限制,取值范围为-1 ~ INT_MAX,默认为-1,表示不管控。

  • ACTIVE_STATEMENTS 取值范围为 -1 ~ INT_MAX, 默认值为 10,建议使用该默认值。当取值设置为 0 或者-1 时,慢车道并发不受 ACTIVE_STATEMENTS 限制。

  • MEM_PERCENT 取值范围为 0~100,当取值设置为 0 时,慢车道并发不受 MEM_PERCENT 限制。

  • 慢车道并发受 ACTIVE_STATEMENTS 和 MEM_PERCENT 限制,同时点数由 ACTIVE_STATEMENTS 决定。当 ACTIVE_STATEMENTS=-1 或 0 时,total_points=90。total_points 点数耗尽后,慢车道查询会触发排队操作,队列满足先进先出。

  • query_mem 为优化器估算的作业内存大小,即 PG_SESSION_WLMSTAT 视图中的 statement_mem;作业无估算内存数值时,不进行并发控制。

  • respool_mem 为资源池的实际内存。

4.2 动态负载管理


当 GUC 参数 enable_dynamic_workload 设置为 on 的时候就代表是动态负载管理模式。动态负载管理的情况下,pgxc_stat_activity 视图中 enqueue 字段会有在重新队列中等待和在全局队列中等待。


1)简单作业和复杂作业的定义


动态负载管理下优化器估算内存大于 32M 认为是复杂作业,反之认为是简单作业。


运行中的作业复杂简单情况可以通过 PG_SESSION_WLMSTAT 中的 attribute 字段查看。


2)动态负载管理相关说明


  • 集群有一个 CN 会作为中心协调节点(CCN),用于收集和调度作业执行,该节点可以通过 cm_ctl query -cv 查询到,Central Coordinator State 会显示其状态。当 CCN 不存在时,作业不再受动态负载管理控制。

  • CCN 上包含全局内存管控队列和资源池队列,目前暂不支持跨队列优先级,在以下场景下优先级低的作业可能优先下发:如果优先级高的作业在全局内存管控队列排队,优先级低的作业在资源池队列排队,则优先级低的作业会优先下发。

  • 单 CN 上依然受到 max_active_statements 参数限制,但不是强制限制,实际运行的作业可能稍微大于该数值。

  • 简单查询作业(估算值<32MB)、非 DML(即非 INSERT、UPDATE、DELETE 和 SELECT)语句,不走自适应负载,需要通过 max_active_statements 来进行单 CN 的上限控制。

  • 默认 work_mem 数值为 512MB,在自适应负载特性下,该数值不能变大,否则会引起内存不受控(例如未做 Analyze 的语句)。

  • 作业估算内存小于等于 0 时,如果强制将作业指定为慢车道管控,作业不会发往 CCN 管控将直接运行。

  • 以下场景或语句由于内存使用特殊性和不确定性,可能导致大并发场景内存不受控,如果遇到需要降低并发数。

  • 单条元组占用内存过大的场景,例如,基表包含超过 MB 级别的宽列。

  • 完全下推语句的查询。

  • 需要在 CN 上耗费大量内存的语句,例如,不能下推的语句,withhold cursor 场景。

  • 由于计划生成不当导致 hashjoin 算子建立的 hash 表重复值过多,占用大量内存。

  • 包含 UDF 的场景,且 UDF 中使用大量内存的场景。


3)短查询加速(默认开启,建议开启)


混合负载场景下,复杂查询可能会长时间占用大量资源,虽然简单查询执行时间短、消耗资源少,但是因为资源耗尽,简单查询不得不在队列中等待复杂查询执行完成。为提升执行效率、提高系统吞吐量,GaussDB(DWS)的“短查询加速”功能,实现对简单查询的单独管理。


  • 开启短查询加速后,简单查询与复杂查询分开管理。

  • 关闭短查询加速后,简单查询与复杂查询执行相同的工作负载管理。


虽然单个简单作业资源消耗少,但是大量简单作业并发运行还是会占用大量资源,因此短查询加速开启情况下,需要对简单查询进行并发管理;资源管理可能会影响查询性能,影响系统吞吐量,因此简单查询不进行资源管理,异常规则也不生效。


设置方法:


  • 通过 GUC 参数 wlm_query_accelerate 设置

  • 通过资源池 alter Resource Pool query_pool with(short_acc='f');

4.3 资源池内存管理


资源池的内存管理是基于语句的估算内存进行管理的。


1)资源池可用内存设置方法


ALTER RESOURCE POOL resource_pool_a1 WITH (MEM_PERCENT=20);
复制代码
  • 当 MEM_PERCENT 参数取值设置为 0 时,表示查询作业的内存不受限。

  • 当 MEM_PERCENT 参数取值设置为“x”(1<=x<=100)时,表示设置资源池使用的内存大小为可用内存大小的“x%”,查询作业将使用给定的内存来运行。


2)资源池作业估算内存限制设置方法


ALTER RESOURCE POOL resource_pool_a1 WITH (MEMORY_LIMIT="300MB");
复制代码


  • 当 MEMORY_LIMIT 参数取值设置为 unlimited 时,表示作业内存受数据库内存限制。

  • 当 MEMORY_LIMIT 参数取值设置为 default 时,表示作业内存限制为资源池内存的 1/2。

  • 当 MEMORY_LIMIT 参数取值设置为 x kB/MB/GB 时,表示作业内存限制为 xkB/MB/GB。

  • 当 memory_limit 配置小于 256M 时,为防止估算内存过小导致问题,作业估算内存上限为 256MB。

5 资源管理相关视图


GaussDB(DWS)对外提供诸多系统视图,可以用来辅助资源管理及资源使用相关问题的分析定位,常用视图及用法说明如下表所示。(☆代表常用程度)



除过上述常用视图,资源管理问题定位过程需要根据实际场景,结合实例日志、集群状态等共同分析定位。

6 推荐配置


因为并发的配置和业务的复杂程度和集群的规格配置有很大的关系,本推荐仅做参考。推荐基于 3CN 12DN,每个 dn 实例最大可使用 64G 内存情况下推荐的


在 813 内核版本及以上版本推荐配置如下。


GUC 参数:


  • max_active_statements 60 (每个 cn 的最大并发数,控制全局队列排队)

  • enable_dynamic_workload on (开启动态负载)

  • wlm_query_accelerate -1 (开启短查询加速)


资源池参数:


  • 将资源池 resource_pool_a1 更改为 (MAX_DOP=50) (简单作业数 50 并发)

  • 将资源池 resource_pool_a1 更改为 (active_statements=10) (复杂作业 10 并发)

7 并发控制常用定位方法及解决措施

7.1 排队问题


出现业务阻塞、性能下降、查询无响应等类似现网问题时,通过以下方法可以排查是否排队问题并定位排队原因,同时根据排队原因给出相应规避措施。

7.1.1 确认是否排队


首先确认是否排队问题,其次排查排队原因,确认是否属于正常排队:


  • 813 及以上版本查询资源池监控视图

select rpname,slow_run,slow_wait,slow_limit,used_cpu,cpu_limit,used_mem,estimate_mem from gs_respool_resource_info;
复制代码
  • 老版本查询作业负载视图

select resource_pool,attribute,lane,status,enqueue,sum(statement_mem) as stmt_mem,count(1) from pgxc_session_wlmstat where status!='finished' and attribute!='Internal' and usename!='Ruby' group by 1,2,3,4,5;
复制代码


通过视图可以获取到各资源池快慢车道作业运行信息,据此可以判断是否排队问题:


如果有作业处于排队状态,则可能是排队导致的问题,否则排除排队问题;可能的排队原因包括:


  • 单 CN 全局并发排队;

  • 快车道并发排队;

  • 静态慢车道并发排队;

  • 静态慢车道内存排队;

  • 动态 CCN 全局内存排队;

  • 动态 CCN 慢车道并发排队;

  • 动态 CCN 慢车道内存排队。


排查排队原因


常见排队原因及解决措施



1)全局并发排队


单 CN 实际运行作业数≥全局并发上限,则全局并发排队正常;


单 CN 实际运行作业数长时间小于全局并发上限,则可能存在计数泄露。


2)快车道排队


快车道实际运行作业数≥快车道并发上限,则快车道并发排队正常;


快车道实际运行作业数长时间小于快车道并发上限,则可能存在计数泄露。


3)静态慢车道排队


慢车道实际运行作业数≥慢车道并发上限,则慢车道并发排队正常;


慢车道实际运行作业累计估算内存≥慢车道内存上限,则慢车道内存占用达到上限导致排队,关注是否有查询估算内存过大;


如果慢车道并发和内存占用长时间达不到上限,则可能存在计数泄露。


4)动态 CCN 排队


如果查询在 CCN 排队,则需要查询 CCN 开发者视图确认排队原因:


select * from pg_stat_get_workload_struct_info();


CCN 上可能的排队原因:


  • CCN 全局可用内存不足导致排队,此时需特别关注是否有查询估算内存过大;

  • 资源池实际运行作业数≥慢车道车道并发上限,资源池并发上限,正常排队;

  • 资源池实际运行作业累计估算内存≥慢车道内存上限,则慢车道内存占用达到上限导致排队,此时需特别关注是否有查询估算内存过大;

  • 资源池实际运行作业数或占用内存与记账值不符,则可能存在计数泄露 BUG;

  • 队首作业在 CCN 哈希中不存在,说明队首作业残留导致查询不能正常下发;

  • CN/CCN 处于 recover 状态或收集 DN 内存信息失败(多 CCN)导致所有查询等待 5s 下发,现象为所有查询排队时间均为 5~6s。

8 常见案例

8.1 CCN 排队


1)查询资源池监控视图,确认是否正常排队(813 及以上版本)


下面以单 CN 下发作业为例,多 CN 下发作业需查询 pgxc_respool_resource_info 视图。


select rpname,slow_run,slow_wait,slow_limit,used_cpu,cpu_limit,used_mem,estimate_mem from gs_respool_resource_info;
复制代码


  • 如果 slow_wait 不等于 0,说明有查询在 CCN 排队,否则无查询排队;

  • 如果 slow_run 大于等于 slow_limit,说明达到慢车道并发上限导致排队,否则说明不是并发过大导致排队;

  • 如果 estimate_mem 大于资源池内存上限,说明内存不足导致排队,否则说明不是内存不足导致排队;

  • 如果 used_mem 长时间远小于 estimate_mem,说明该资源池上运行作业估算内存过大,可以尝试 analyze;

  • 如果 used_mem 大于 estimate_mem,则查询可能触发内存二次扩展(默认资源池)或查询内存不可控;

  • 如果 used_cpu 长时间接近甚至大于等于 cpu_limit,说明资源池分配 CPU 过少,可能导致作业大量堆积;


通过该查询可以直观的观察各资源池作业负载信息,如果资源池 running 作业并发、内存长时间无法达到资源池上限,则考虑是否存在排队异常。


2)查询作业负载视图(813 以下版本)


813 及以上版本建议使用上边方法确认是否有排队异常,当然也可以使用以下方法确认存在排队异常,排除特性 BUG 影响。


813 以下版本仅有 pg_session_wlmstat 视图,没有 pgxc 视图,可通过以下语句创建临时 pgxc 视图:


CREATE OR REPLACE VIEW pgxc_session_wlmstat_tp AS
SELECT * FROM pg_catalog.pgxc_parallel_query('cn', 'SELECT pg_catalog.pgxc_node_str(), * FROM pg_catalog.pg_session_wlmstat') AS (
nodename name,
datid oid,
datname name,
threadid bigint,
processid integer,
usesysid oid,
appname text,
usename name,
priority bigint,
attribute text,
block_time bigint,
elapsed_time bigint,
total_cpu_time bigint,
cpu_skew_percent integer,
statement_mem integer,
active_points integer,
dop_value integer,
control_group text,
status text,
enqueue text,
resource_pool name,
query text,
is_plana boolean,
node_group text,
lane text
);
复制代码


查询集群内各资源池在所有 CN 上的作业运行、排队统计信息:


select resource_pool,attribute,lane,status,enqueue,sum(statement_mem) as stmt_mem,count(1) from pgxc_session_wlmstat where status!='finished' and attribute!='Internal' and usename!='Ruby' group by 1,2,3,4,5;
复制代码


通过该查询可以直观的观察各资源池作业负载信息,如果资源池 running 作业并发、内存长时间无法达到资源池上限,则考虑是否存在排队异常。


确认是否存在排队异常


如果经过前两个步骤分析,怀疑可能存在排队异常,可能的原因有以下几种:


  • 大批作业一开始运行就报错退出,依靠 CCN 周期任务完成作业同步和唤醒;

  • CCN 全局内存排队导致资源池并发、内存长时间无法达到资源池上限。


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

发布于: 刚刚阅读数: 3
用户头像

提供全面深入的云计算技术干货 2020-07-14 加入

华为云开发者社区,提供全面深入的云计算前景分析、丰富的技术干货、程序样例,分享华为云前沿资讯动态,方便开发者快速成长与发展,欢迎提问、互动,多方位了解云计算! 传送门:https://bbs.huaweicloud.com/

评论

发布
暂无评论
一文详解GaussDB(DWS) 的并发管控和内存管控_大数据_华为云开发者联盟_InfoQ写作社区