摘要:DWS的负载管理分为两层,第一层为cn的全局并发控制,第二层为资源池级别的并发控制。
本文分享自华为云社区《GaussDB(DWS) 并发管控&内存管控》,作者: fighttingman。
这里将并发管控和内存管控写在一起,是因为内存管控实际是通过限制语句的并发达到内存管控的目的的。内存管控是基于语句的估算内存的前提下进行管控的,通俗的说就是语句有个估算内存,当资源池的剩余内存小于语句的估算内存时,这个语句就会排队等待,等资源池内的语句执行完,资源池有足够的剩余内存的时候,才会让这个语句执行。所以内存管控的实际效果和语句的估算内存有很大关系,估算的大了就会造成大量语句排队,实际没有使用那么多内存,造成内存资源浪费,相反估算的小了,就会有很多语句下发,实际内存使用就会变多,就有语句报内存不足的错误风险。
数据库系统的并发控制,在整个系统中起着很重要的作用,比如很多用户的业务压力过大时,有时会导致连接数量被占满,有时会导致某种计算资源被占满,有时会导致存储空间被占满,这些情况都会导致整个集群进入异常甚至不可用的状态:正在执行的作业互相争抢CPU,会导致大家都不能好好执行;大量作业执行时,占用大量内存,很容易触发到内存瓶颈,造成作业内存不可用问题,导致业务报错等等。在不进行并发控制的情况下,这些情况都很可能会出现,影响到正常业务。
DWS的负载管理分为两层,第一层为cn的全局并发控制,第二层为资源池级别的并发控制。在通过第一层控制的时候,会继续向前走到第二层资源池控制,根据资源池当前的负载资源情况决定作业继续执行或者排队。
基于DWS并发控制逻辑看出,实际作业执行中,可能会在两种队列中排队:
一种是全局队列(global queue)这种队列不区分简单和复杂作业,也不区分是DDL或者是普通语句,这种是每个cn生效。
一种是资源池队列(resource pool queue),用户下发的一般语句会根据资源消耗估算以及复杂程度在这里进行判断是否排队。
在两层队列的过滤下,DWS会筛选出当前能执行的语句,使其正常运行,运行时也会受到其所属资源池资源的限制(只能使用资源池配置的CPU、内存、IO配额)。
这里介绍几个常用视图以及SQL语句,可以迅速判断目前的业务出现问题的原因,受限根据以下视图可以看到目前的作业是不是在排队,之后要迅速分析为什么在排队,是因为负载管理各个参数配置问题,还是因为正在执行的语句占据了过多的资源导致的排队。
pgxc_stat_activity (活跃视图)
查询当前执行时间最长的语句的排队状态,query_id(数据库中作业的唯一标识),以及详细的语句信息。
select coorname,usename, current_timestamp-query_start as duration, enqueue,query_id,query from pgxc_stat_activity where state='active' and usename <> 'Ruby' order by duration desc;
根据该语句可以迅速判断出哪些语句执行时间很长,是什么样的语句执行很慢以及该语句的query_id,便于迅速进入下一步排查。
该视图中enqueue字段中如果显示waiting in global queue就代表在全局排队。全局排队是受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字段就会显示waiting in global queue。
当GUC参数enable_dynamic_workload设置为off的时候就代表是静态负载管理模式。静态负载管理的情况下,pgxc_stat_activity视图中enqueue字段只会有waiting in respool queue。并发控制参数为资源池的max_dop(简单作业)和active_statements(复杂作业)。
1)简单作业和复杂作业的定义
在静态负载管理中,简单作业是估算代价cost值小于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字段就会显示waiting in respool queue。
3)复杂作业并发限制
ALTER RESOURCE POOL resource_pool_a2 WITH (active_statements=10);
通过设置资源池的active_statements参数控制复杂作业的并发数,关联资源池resource_pool_a2的用户都受到这个参数的控制。
资源池使用并发点数的计数方式来计算可执行的复杂作业并发数量,并发点数计算公式为
作业使用内存点数:active_points = (query_mem/respool_mem) * active_statements * 100
作业使用并发点数:active_points = 100
资源池总点数:total_points = active_statements * 100
单位点数: 100
4)相关说明
当GUC参数enable_dynamic_workload设置为on的时候就代表是动态负载管理模式。动态负载管理的情况下,pgxc_stat_activity视图中enqueue字段会有waiting in respool queue和waiting in global queue。
1)简单作业和复杂作业的定义
动态负载管理下优化器估算内存大于32M认为是复杂作业,反之认为是简单作业。
运行中的作业复杂简单情况可以通过PG_SESSION_WLMSTAT中的attribute字段查看。
2)动态负载管理相关说明
3)短查询加速(默认开启,建议开启)
混合负载场景下,复杂查询可能会长时间占用大量资源,虽然简单查询执行时间短、消耗资源少,但是因为资源耗尽,简单查询不得不在队列中等待复杂查询执行完成。为提升执行效率、提高系统吞吐量,GaussDB(DWS)的“短查询加速”功能,实现对简单查询的单独管理。
虽然单个简单作业资源消耗少,但是大量简单作业并发运行还是会占用大量资源,因此短查询加速开启情况下,需要对简单查询进行并发管理;资源管理可能会影响查询性能,影响系统吞吐量,因此简单查询不进行资源管理,异常规则也不生效。
设置方法:
资源池的内存管理是基于语句的估算内存进行管理的。
1)资源池可用内存设置方法
ALTER RESOURCE POOL resource_pool_a1 WITH (MEM_PERCENT=20);
2)资源池作业估算内存限制设置方法
ALTER RESOURCE POOL resource_pool_a1 WITH (MEMORY_LIMIT="300MB");
GaussDB(DWS)对外提供诸多系统视图,可以用来辅助资源管理及资源使用相关问题的分析定位,常用视图及用法说明如下表所示。(☆代表常用程度)
除过上述常用视图,资源管理问题定位过程需要根据实际场景,结合实例日志、集群状态等共同分析定位。
因为并发的配置和业务的复杂程度和集群的规格配置有很大的关系,本推荐仅做参考。推荐基于3CN 12DN,每个dn实例最大可使用64G内存情况下推荐的
在813内核版本及以上版本推荐配置如下。
GUC参数:
资源池参数:
出现业务阻塞、性能下降、查询无响应等类似现网问题时,通过以下方法可以排查是否排队问题并定位排队原因,同时根据排队原因给出相应规避措施。
首先确认是否排队问题,其次排查排队原因,确认是否属于正常排队:
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;
通过视图可以获取到各资源池快慢车道作业运行信息,据此可以判断是否排队问题:
如果有作业处于排队状态,则可能是排队导致的问题,否则排除排队问题;可能的排队原因包括:
排查排队原因
常见排队原因及解决措施
1)全局并发排队
单CN实际运行作业数≥全局并发上限,则全局并发排队正常;
单CN实际运行作业数长时间小于全局并发上限,则可能存在计数泄露。
2)快车道排队
快车道实际运行作业数≥快车道并发上限,则快车道并发排队正常;
快车道实际运行作业数长时间小于快车道并发上限,则可能存在计数泄露。
3)静态慢车道排队
慢车道实际运行作业数≥慢车道并发上限,则慢车道并发排队正常;
慢车道实际运行作业累计估算内存≥慢车道内存上限,则慢车道内存占用达到上限导致排队,关注是否有查询估算内存过大;
如果慢车道并发和内存占用长时间达不到上限,则可能存在计数泄露。
4)动态CCN排队
如果查询在CCN排队,则需要查询CCN开发者视图确认排队原因:
select * from pg_stat_get_workload_struct_info();
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;
通过该查询可以直观的观察各资源池作业负载信息,如果资源池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作业并发、内存长时间无法达到资源池上限,则考虑是否存在排队异常。
确认是否存在排队异常
如果经过前两个步骤分析,怀疑可能存在排队异常,可能的原因有以下几种: