GaussDB(DWS)资源管理排队原理与问题定位

举报
门前一棵葡萄树 发表于 2022/12/15 16:11:05 2022/12/15
【摘要】 GaussDB(DWS)提供了资源管理功能,用户可以根据自身业务情况对资源进行划分,将资源按需划分成不同的资源池,不同资源池之间资源互相隔离。再通过用户关联资源池的方式将数据库用户关联至不同的资源池,用户查询依据“用户-资源池”的关联关系将查询路由至对应资源池执行,以此实现对查询并发、内存及CPU资源的管控。

    1. 前言

    • 适用版本:【8.1.1及以上】

    GaussDB(DWS)提供了资源管理功能,用户可以根据自身业务情况对资源进行划分,将资源按需划分成不同的资源池,不同资源池之间资源互相隔离。再通过用户关联资源池的方式将数据库用户关联至不同的资源池,用户查询依据“用户-资源池”的关联关系将查询路由至对应资源池执行,以此实现对查询并发、内存及CPU资源的管控。

    2. 内存管控原理

    GaussDB(DWS)提供了资源管理功能,用户可以根据自身业务情况对资源进行划分,将资源按需划分成不同的资源池,不同资源池之间资源互相隔离。再通过用户关联资源池的方式将数据库用户关联至不同的资源池,用户查询依据“用户-资源池”的关联关系将查询路由至对应资源池执行,以此实现对查询并发、内存及CPU资源的管控。从而实现对不同业务之间的资源限制和隔离,满足数据库混合负载需求,保证查询执行时资源调度的有序可控,防止烂SQL影响整个集群。

    2.1 自适应内存

    传统内存管理场景下,使用work_mem限制算子可以使用的内存上限,通常复杂查询的执行计划中包含多个算子,每个算子可能需要使用的内存并不相同,但是每个算子可用的内存上限均为work_mem,很难找到一个最优的work_mem取值,一方面保证查询性能满足预期,一方面还需要保证不会导致内存报错。在查询并发场景下,静态内存管理的work_mem及并发上限就更难设置了。单查询算子数量从0~N不等,设置work_mem后无法实现语句级内存资源使用的控制,多并发场景下可能会导致内存资源不受控,进而导致OOM。

    针对传统内存管理的弊端,GaussDB(DWS)设计实现了内存自适应技术:

    • 解除对work_mem的依赖,优化器依据统计信息对查询使用内存进行估算;
    • 执行器执行SQL过程中,如果使用内存超过估算内存即触发下盘;
    • 资源管理依据优化器估算的查询内存,对查询进行调度和管控。

    另外,为保证多CN场景下的内存可控,设计实现CCN用于查询的统一调度,以此保证所有CN上运行的查询使用内存之和不会超过内存上限,进而导致内存不足,引发报错。CM在第一次集群启动时,通过集群部署形式,选择编号最小的CN作为CCN,CCN故障之后,由CM选择新的CCN进行替换。

    CCN管控与CN管控间差异及优劣:

    • CN管控查询由各CN单独调度,各CN间互相不感知负载情况,无法准确感知和控制整个集群并发,内存管控效果有限,有可能出现内存报错;
    • CCN管控查询由CCN统一调度,结合DN内存负反馈机制,CCN可以感知集群整体负载,内存管控更加精准,可以消除内存不足报错;
    • CCN管控涉及CN与CCN之间的通信,通信延迟可能带来查询性能的不稳定;通信延迟与网络环境及查询并发度有关,大概10ms~ 1s不等;
    • CCN管控相对CN管控逻辑更加复杂,除涉及资源池内存/并发管控外,还包含CCN全局内存管控,在作业管控和唤醒时都需要进行两层逻辑判断;
    • CCN管控因为所有查询都需要由CCN统一调度,因此管控时发生所冲突的可能性就更大。

    综上所述,CN管控对查询性能影响较小,但是内存管控效果有限,CCN管控对查询性能影响可能较大,但是可以实现内存精准管控,消除内存不足报错。

    为实现更为精细的管控,我们根据查询预期执行时间和资源消耗,将查询划分为执行时间长、资源消耗多的复杂查询和执行时间短、资源消耗少的简单查询。简单查询和复杂查询的划分与资源消耗密切相关,同时因为查询执行前就需要划分简单/复杂查询,因此根据估算内存(代价)对查询进行划分:

    • 简单查询:估算内存小于32MB;
    • 复杂查询:估算内存大于等于32MB。

    混合负载场景下,虽然简单查询本身执行时间短、消耗资源少,但是因为复杂查询可能会长时间大量占用资源,进而导致资源耗尽,使得简单查询不得不在队列中等待复杂查询执行完成。为提升执行效率、提高数据库整体吞吐量, 设计实现“短查询加速”功能,实现对简单查询的单独管控。

    • 开启短查询加速后,简单查询与复杂查询分别进行管控。
    • 关闭短查询加速后,简单查询与复杂查询一起进行管控。

    虽然单个简单查询资源消耗少,但是大量简单查询并发运行还是可能占用大量资源,另外对简单查询进行CCN管控可能会影响查询性能,降低吞吐量。因此为降低对查询的性能影响,同时实现内存管控目的,我们仅对复杂查询进行CCN并发和内存管控,简单查询由各自CN单独进行并发控制。

    2.2 内存管控能力

    GaussDB(DWS) 内存管控分为三级,分别是:

    1. 实例级内存管控:通过max_process_memory限制CN、DN可以使用的内存上限;
    2. 资源池内存管控:通过资源池参数mem_percent限制资源池内存使用,结合优化器估算的查询内存,实现资源池之间的内存隔离;
    3. 作业内存管控:查询优化器根据统计信息估算查询执行时使用内存的最大值,查询以估算内存为准向资源管理申请内存资源,查询执行过程中使用内存超过估算内存即触发下盘。

    基于优化器给出的查询估算内存,资源管理提供了两种内存管控方式:

    1. 静态内存管控(单CN管控):各CN互不感知,分别进行管控,多CN同时下发作业可能导致内存不可控;
    2. 动态内存管控(CCN管控):估算内存大于32MB的查询统一由CCN调度,结合DN内存负反馈机制,CCN感知集群整体负载,实现内存的精准管控。

    特例:

    1. 静态内存管控关闭(资源池mem_percent=0)或查询估算内存为0情况下,查询执行过程中使用work_mem控制每个算子可以使用的内存上限,多算子并行可能导致内存不受控;
    2. 默认资源池支持DN上内存扩展,DN内存资源充足情况下查询可以使用更多内存,提升查询执行性能。

    通过以上描述,其实不难看出内存管控的基础是优化器的内存估算,内存估算准确可以实现内存的精准管控,内存估算不准可能引起一系列的问题:

    1. 内存估算小使用大(DN内存扩展),可能导致内存报错;
    2. 内存估算大使用小,可能导致内存利用率低,吞吐量上不去;
    3. 内存估算过大,可能导致CCN/CN异常排队。

    基于以上问题,资源管理做了以下功能降低估算不准带来的影响:

    1. 资源池增加参数memory_limit,用于配置单查询估算内存上限,默认情况下查询估算内存上限为资源池内存*0.4,实际场景下可按需设置该值大小,理论上查询估算内存不应超过该值;
    2. 内存负反馈:正在执行的作业查询估算内存之和超过总内存40%,实际使用内存低于估算内存60%时触发内存负反馈,按照一定比例逐步降低查询估算内存记账值,以此下发更多查询,提升内存使用率;

    查询估算内存兜底机制(820-1230):在查询估算内存超过单查询估算内存上限时,对查询估算内存进行修正,按照单查询估算内存上限进行管控

    3. 排队原理与问题排查

    3.1 排队原理

    GaussDB(DWS)可能在以下情况下发生排队:

    1. 单CN并发控制:单个CN上查询并发超过max_active_statements引发排队;
    2. 资源池快车道并发控制:资源池上简单查询并发超过资源池参数max_dop引发排队;
    3. 资源池慢车道并发控制:资源池上复杂查询并发超过资源池参数active_statements引发排队;
    4. 资源池慢车道内存管控:资源池上运行的复杂查询估算内存之和超过资源池参数mem_percent配置的资源池内存上限引发排队;
    5. CCN全局内存管控:所有CN上运行的查询内存估算内存/使用内存超过DN内存上限(max_dynamic_memory)引发排队。

    特例:初始用户及白名单语句不受控。

    3.2 常见视图

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

    pgxc_session_wlmstat ☆☆☆☆☆

    查询集群所有CN节点上用户执行作业的负载管理相关信息,包含作业属性、作业状态、估算内存、排队信息、排队时间、运行时间等信息。
    pg_user ☆☆☆

    查询集群内所有用户信息,主要关注用户关联资源池以及配置的空间限额。
    pg_resource_pool ☆☆☆

    查询集群内所有资源池信息,重点关注是否开启短查询加速、快慢车道并发数以及关联的异常规则。
    pgxc_respool_resource_info ☆☆☆☆

    查询集群所有实例上资源池实时监控信息,作业统计(并发)信息仅在CN上有效,每个CN只显示本CN上运行的作业统计信息,DN上资源监控信息主要用于判断是否存在计算倾斜,多数情况下,只需要查看CN监控信息即可。

    对应单CN视图:gs_respool_resource_info
    pg_total_user_resource_info ☆☆

    查询当前实例上用户实时监控信息,不同于资源池监控包含统计信息,用户监控仅包含资源监控信息,包括:内存、CPU、IO以及存储资源使用信息,因此多数情况下仅需要关注单CN视图即可。

    对应集群视图:pgxc_total_user_resource_info
    pgxc_wlm_session_statistics ☆☆☆

    TopSQL实时视图,查询集群所有CN上正在执行的作业监控信息,包含作业基本信息、执行时间、估算信息以及内存、CPU、IO等资源监控信息,资源监控信息包括作业在所有DN上使用资源的最大值、最小值以及倾斜率。
    pgxc_wlm_session_info ☆☆☆☆

    TopSQL历史视图,查询集群所有CN上已经运行结束的作业监控信息。TopSQL历史视图对多租户的划分及资源管理的应用具有重要的指导价值。
    pg_stat_get_workload_struct_info ☆☆

    动态负载管理开发者视图,通过以上视图无法完成问题定位时可能会用到该视图定位分析问题。该视图可以查询到内存中Client端及Server端记录的作业信息和记账信息,现网在动态负载管理场景下出现问题,需要紧急恢复时,建议先在CCN上查询该视图后再进行重启恢复。
    pg_stat_get_mem_mbytes_reserved ☆☆

    作业负载管理开发者视图,该视图可以查询到指定会话相关的负载管理内存记录信息,可以辅助问题定位与确认。

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

    3.3 自定义视图

    为方便迅速定位问题,根据现网实践经验对以上常见视图进行组合,整合了三个问题定位过程中的常用视图:资源池监控视图、用户监控视图以及作业监控视图。与上面内置视图相比,这几个视图依据现网定位经验与分布式数据库特点,对查询结果做了针对性优化,同时优化了字段显示,用户更易理解,可以作为常规监控视图使用。具体视图定义可参考附件(821及以上版本已内置视图定位,用户自定义建议不要重名)自定义监控视图.rar

    gs_respool_monitor ☆☆☆☆☆

    查询集群内所有资源池的静态和动态运行信息以及资源使用信息,包含:会话数量、快慢车道运行作业数、排队作业数、并发上限、估算内存、内存上限等信息。

    与pgxc_respool_resource_info各CN分别统计该CN上查询运行信息不同,该视图将所有CN上所有查询查询运行信息进行了汇总,可以更快捷的判断查询为什么排队,同时该视图对老版本(800/811)进行了适配。
    gs_user_monitor ☆☆☆

    查询集群内所有用户查询运行信息及资源使用信息,包含:会话数量、快慢车道运行作业数、排队作业数、并发上限、估算内存、内存上限等信息。

    与pgxc_total_user_resource_info各CN分别统计该CN上查询运行信息不同,该视图将所有CN上所有查询查询运行信息进行了汇总。该视图主要用于日常用户查询运行及资源使用监控,在定位排队问题时一般不常有。
    gs_query_monitor ☆☆☆☆☆

    查询集群内所有作业运行信息,包含:查询下发CN、查询优先级、查询执行时间、查询状态、排队信息、估算内存等信息。

    该视图节选了pgxc_session_wlmstat中的部分字段,增加了查询开始时间以及查询的算子数量监控,同时按照优先级、排队信息和查询开始时间对查询结果进行了排序,优先显示排队队列中靠前的作业,其次显示运行时间较早的作业。该视图与gs_respool_monitor配合使用,可以迅速完成排队问题定位,有效缩短排队问题定位时间。

    3.4 视图应用

    创建资源池,设置快慢车道并发上限都是2,其余参数使用默认参数:

    CREATE RESOURCE POOL rp1 WITH (ACTIVE_STATEMENTS=2,MAX_DOP=2);
    

    创建用户,关联资源池rp1

    CREATE USER usr1 PASSWORD 'password' RESOURCE POOL 'rp1';
    

    使用usr1创建表并运行作业,快慢车道各运行10个作业(视图查询过程中可能有作业结束,因此排队作业数可能减少),查询视图查询作业信息:

    PGXC_STAT_ACTIVITY视图

    postgres=# select coorname,usename,query_start,enqueue,state,query_id from pgxc_stat_activity where usename='usr1' order by query_start;
       coorname   | usename |          query_start          |         enqueue          | state  |     query_id
    --------------+---------+-------------------------------+--------------------------+--------+-------------------
     coordinator1 | usr1    | 2021-06-11 09:59:02.822459+08 |                          | active | 75153818781745720
     coordinator1 | usr1    | 2021-06-11 09:59:02.823087+08 |                          | active | 75153818781745723
     coordinator1 | usr1    | 2021-06-11 09:59:02.8231+08   | waiting in respool queue | active | 75153818781745724
     coordinator1 | usr1    | 2021-06-11 09:59:02.823715+08 | waiting in respool queue | active | 75153818781745726
     coordinator1 | usr1    | 2021-06-11 09:59:02.823928+08 | waiting in respool queue | active | 75153818781745727
     coordinator1 | usr1    | 2021-06-11 09:59:02.825433+08 | waiting in respool queue | active | 75153818781745728
     coordinator1 | usr1    | 2021-06-11 09:59:02.825918+08 | waiting in respool queue | active | 75153818781745730
     coordinator1 | usr1    | 2021-06-11 09:59:02.828873+08 | waiting in respool queue | active | 75153818781745732
     coordinator1 | usr1    | 2021-06-11 09:59:02.870048+08 | waiting in respool queue | active | 75153818781745739
     coordinator1 | usr1    | 2021-06-11 09:59:02.870726+08 | waiting in respool queue | active | 75153818781745740
     coordinator1 | usr1    | 2021-06-11 09:59:04.532598+08 |                          | active | 75153818781745779
     coordinator1 | usr1    | 2021-06-11 09:59:04.53264+08  |                          | active | 75153818781745778
     coordinator1 | usr1    | 2021-06-11 09:59:04.533594+08 | waiting in ccn queue     | active | 75153818781745782
     coordinator1 | usr1    | 2021-06-11 09:59:04.533626+08 | waiting in ccn queue     | active | 75153818781745783
     coordinator1 | usr1    | 2021-06-11 09:59:04.53382+08  | waiting in ccn queue     | active | 75153818781745784
     coordinator1 | usr1    | 2021-06-11 09:59:04.533834+08 | waiting in ccn queue     | active | 75153818781745787
     coordinator1 | usr1    | 2021-06-11 09:59:04.534021+08 | waiting in ccn queue     | active | 75153818781745786
     coordinator1 | usr1    | 2021-06-11 09:59:04.534788+08 | waiting in ccn queue     | active | 75153818781745788
     coordinator1 | usr1    | 2021-06-11 09:59:04.53515+08  | waiting in ccn queue     | active | 75153818781745789
     coordinator1 | usr1    | 2021-06-11 09:59:04.536193+08 | waiting in ccn queue     | active | 75153818781745790
    

    enqueue字段可能取值:

    • waiting in queue:表示语句在排队中。(向前兼容取值)
    • waiting in global queue:表示语句在CN并发队列排队中。
    • waiting in respool queue:表示语句在资源池排队中。
    • waiting in ccn queue:表示作业在CCN排队中。
    • 空:表示语句不在任何队列中,正在运行。
      state字段可能取值:(该字段代表session当前状态,不能说明语句在排队/运行中)
    • active:后台正在执行查询。(该取值代表session有活跃作业,但是作业可能处于排队/实际运行中)
    • idle:后台正在等待新的客户端命令。
    • idle in transaction:后端在事务中,但事务中没有语句在执行。
    • idle in transaction (aborted):后端在事务中,但事务中有语句执行失败。
    • fastpath function call:后端正在执行一个fast-path函数。
    • disabled:如果后端禁用track_activities,则报告此状态。

    从视图中可看出usr1所有session状态均处于active状态,代表所有session都在运行查询;通过enqueue字段可以看出有8个作业在CCN队列排队(复杂作业/慢车道),8个作业在资源池队列排队(简单作业/快车道),其余四个作业enqueue字段为空代表正在运行,其中包含两个快车道作业,两个慢车道作业,这点在后面PG_SESSION_WLMSTAT视图查询结果中得到验证。

    PG_SESSION_WLMSTAT视图

    postgres=# select usename,processid,threadid,priority,attribute,lane,enqueue,status,block_time,elapsed_time,statement_mem from pg_session_wlmstat where usename='usr1';
     usename | processid |    threadid     | priority |  attribute  | lane |   enqueue    | status  | block_time | elapsed_time | statement_mem
    ---------+-----------+-----------------+----------+-------------+------+--------------+---------+------------+--------------+---------------
     usr1    |     46919 | 140323231098624 |        2 | Simple      | fast | Respool      | pending |          3 |            0 |             1
     usr1    |     46920 | 140322958997248 |        2 | Simple      | fast | None         | running |          0 |            3 |             1
     usr1    |     46922 | 140323509499648 |        2 | Simple      | fast | None         | running |          0 |            3 |             1
     usr1    |     46921 | 140323556685568 |        2 | Simple      | fast | Respool      | pending |          3 |            0 |             1
     usr1    |     46923 | 140323492718336 |        2 | Simple      | fast | Respool      | pending |          3 |            0 |             1
     usr1    |     46924 | 140323416160000 |        2 | Simple      | fast | Respool      | pending |          3 |            0 |             1
     usr1    |     46925 | 140323396757248 |        2 | Simple      | fast | Respool      | pending |          3 |            0 |             1
     usr1    |     46926 | 140323347470080 |        2 | Simple      | fast | Respool      | pending |          3 |            0 |             1
     usr1    |     46927 | 140323330688768 |        2 | Simple      | fast | Respool      | pending |          3 |            0 |             1
     usr1    |     46928 | 140323313907456 |        2 | Simple      | fast | Respool      | pending |          3 |            0 |             1
     usr1    |     46952 | 140323293980416 |        2 | Complicated | slow | CentralQueue | pending |          2 |            0 |           256
     usr1    |     46953 | 140323277199104 |        2 | Complicated | slow | CentralQueue | pending |          2 |            0 |           256
     usr1    |     46954 | 140323254695680 |        2 | Complicated | slow | None         | running |          0 |            2 |           256
     usr1    |     46956 | 140323191777024 |        2 | Complicated | slow | CentralQueue | pending |          2 |            0 |           256
     usr1    |     46955 | 140323208558336 |        2 | Complicated | slow | CentralQueue | pending |          2 |            0 |           256
     usr1    |     46958 | 140323113662208 |        2 | Complicated | slow | None         | running |          0 |            2 |           256
     usr1    |     46959 | 140323083773696 |        2 | Complicated | slow | CentralQueue | pending |          2 |            0 |           256
     usr1    |     46960 | 140322866190080 |        2 | Complicated | slow | CentralQueue | pending |          2 |            0 |           256
     usr1    |     46957 | 140323172374272 |        2 | Complicated | slow | CentralQueue | pending |          2 |            0 |           256
     usr1    |     46961 | 140322830010112 |        2 | Complicated | slow | CentralQueue | pending |          2 |            0 |           256
    (20 rows)
    

    attribute显示为Simple代表简单作业,显示Complicated代表复杂作业;lane显示fast代表语句运行在快车道,显示slow代表运行在慢车道;enqueue字段为None表示作业不在排队,显示Respool表示在资源池排队,显示CentralQueue表示在CCN排队,该字段与PGXC_STAT_ACTIVITY视图中enqueue字段相对应;status为pending表示查询排队/默认状态,显示running表示查询正在运行。

    备注:pending作业不一定在排队,有可能还没走到负载管理,做到走过负载管理后状态才更新为running,显示pending作业需要结合enqueue字段判断作业是否排队;pending作业enqueue为None表示作业未走到负载管理。

    3.5 排队问题排查

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

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

    • 813及以上版本可以查询资源池监控视图
    SELECT s.resource_pool AS rpname, s.node_group, COUNT(1) AS session_cnt, 
    	SUM(CASE WHEN a.state = 'active' THEN 1 ELSE 0 END) AS active_cnt, 
    	SUM(CASE WHEN s.enqueue = 'Global' THEN 1 ELSE 0 END) AS global_wait, 
    	SUM(CASE WHEN s.lane = 'fast' AND s.status = 'running' THEN 1 ELSE 0 END) AS fast_run, 
    	SUM(CASE WHEN s.lane = 'fast' AND s.status = 'pending' AND s.enqueue NOT IN ('Global', 'None') THEN 1 ELSE 0 END) AS fast_wait, 
    	SUM(CASE WHEN s.lane = 'slow' AND s.status = 'running' THEN 1 ELSE 0 END) AS slow_run, 
    	SUM(CASE WHEN s.lane = 'slow' AND s.status = 'pending' AND s.enqueue NOT IN ('Global', 'None') THEN 1 ELSE 0 END) AS slow_wait, 
    	SUM(CASE WHEN s.status = 'running' THEN s.statement_mem ELSE 0 END) AS est_mem 
    FROM pg_catalog.pgxc_session_wlmstat s, pg_catalog.pgxc_stat_activity a
    WHERE s.threadid = a.pid(+)
    	AND s.attribute != 'Internal'
    	AND s.resource_pool != 'root'
    GROUP BY 1, 2;
    
    • 811及以上版本可以作业运行监控视图
    -- 创建作业排队PGXC视图,使用完毕后删除
    CREATE OR REPLACE FUNCTION pgxc_session_wlmstat_temp()
    RETURNS setof pg_session_wlmstat
    AS $$
    DECLARE
    	row_name record;
    	row_data pg_session_wlmstat%rowtype;
    	query_str text;
    	query_str_nodes text;
    	BEGIN
    		--Get all the node names
    		query_str_nodes := 'SELECT node_name FROM pgxc_node WHERE node_type IN (''C'')';
    		FOR row_name IN EXECUTE(query_str_nodes) LOOP
    			 query_str := 'EXECUTE DIRECT ON (' || row_name.node_name || ') ''SELECT * from pg_session_wlmstat''';
    			  FOR row_data IN EXECUTE(query_str) LOOP
    				  RETURN NEXT row_data;
    			  END LOOP;
    		END LOOP;
    		return;
    	END; $$
    LANGUAGE 'plpgsql' NOT FENCED;
    
    --查询作业运行信息
    SELECT s.resource_pool AS rpname, s.node_group AS nodegroup, COUNT(1) AS session_cnt, 
    	SUM(CASE WHEN a.state = 'active' THEN 1 ELSE 0 END) AS active_cnt, 
    	SUM(CASE WHEN s.enqueue = 'Global' THEN 1 ELSE 0 END) AS global_wait, 
    	SUM(CASE WHEN s.lane = 'fast' AND s.status = 'running' THEN 1 ELSE 0 END) AS fast_run, 
    	SUM(CASE WHEN s.lane = 'fast' AND s.status = 'pending' AND s.enqueue NOT IN ('Global', 'None') THEN 1 ELSE 0 END) AS fast_wait, 
    	SUM(CASE WHEN s.lane = 'slow' AND s.status = 'running' THEN 1 ELSE 0 END) AS slow_run, 
    	SUM(CASE WHEN s.lane = 'slow' AND s.status = 'pending' AND s.enqueue NOT IN ('Global', 'None') THEN 1 ELSE 0 END) AS slow_wait, 
    	SUM(CASE WHEN s.status = 'running' THEN s.statement_mem ELSE 0 END) AS est_mem 
    FROM pgxc_session_wlmstat_temp() s, pg_catalog.pgxc_stat_activity a
    WHERE s.threadid = a.pid(+)
    	AND s.attribute != 'Internal'
    	AND s.resource_pool != 'root'
    GROUP BY 1, 2;
    
    -- 删除临时函数
    DROP FUNCTION pgxc_session_wlmstat_temp;
    
    • 800版本查询作业运行监控视图
    -- 创建作业排队PGXC视图,使用完毕后删除
    CREATE OR REPLACE FUNCTION pgxc_session_wlmstat_temp()
    RETURNS setof pg_session_wlmstat
    AS $$
    DECLARE
    	row_name record;
    	row_data pg_session_wlmstat%rowtype;
    	query_str text;
    	query_str_nodes text;
    	BEGIN
    		--Get all the node names
    		query_str_nodes := 'SELECT node_name FROM pgxc_node WHERE node_type IN (''C'')';
    		FOR row_name IN EXECUTE(query_str_nodes) LOOP
    			 query_str := 'EXECUTE DIRECT ON (' || row_name.node_name || ') ''SELECT * from pg_session_wlmstat''';
    			  FOR row_data IN EXECUTE(query_str) LOOP
    				  RETURN NEXT row_data;
    			  END LOOP;
    		END LOOP;
    		return;
    	END; $$
    LANGUAGE 'plpgsql' NOT FENCED;
    
    --查询作业运行信息
    SELECT 
    	s.resource_pool AS rpname, s.node_group AS nodegroup, count(1) AS session_cnt,
    	SUM(CASE WHEN a.enqueue = 'waiting in global queue' THEN 1 ELSE 0 END) AS global_wait,
    	SUM(CASE WHEN s.attribute= 'Simple' AND a.state = 'active' AND (a.enqueue IS NULL OR a.enqueue = 'no waiting queue') THEN 1 ELSE 0 END) AS fast_run,
    	SUM(CASE WHEN s.attribute= 'Simple' AND a.enqueue = 'waiting in respool queue' THEN 1 ELSE 0 END) AS fast_wait,
    	SUM(CASE WHEN s.attribute= 'Complicated' AND a.state = 'active' AND (a.enqueue IS NULL OR a.enqueue = 'no waiting queue') THEN 1 ELSE 0  END) AS slow_run,
    	SUM(CASE WHEN s.attribute= 'Complicated' AND (a.enqueue = 'waiting in ccn queue' OR a.enqueue = 'waiting in respool queue') THEN 1 ELSE 0  END) AS slow_wait,
    	SUM(CASE WHEN (a.enqueue IS NULL OR a.enqueue = 'no waiting queue') AND a.state = 'active' THEN statement_mem ELSE 0 END) AS est_mem
    FROM pgxc_session_wlmstat_temp() s,pgxc_stat_activity a
    WHERE s.threadid=a.pid(+) AND s.attribute != 'Internal' 
    GROUP BY 1,2;
    
    -- 删除临时函数
    DROP FUNCTION pgxc_session_wlmstat_temp;
    
    • 直接查询自定义视图

    通过查询自定义视图可以获取到各资源池快慢车道作业运行信息以及作业排队信息,据此可以直接判断是否排队问题。

    Step2 排查排队原因
    常见排队原因及解决措施

    排队类别 排队原因 备注/解决措施
    并发 业务高峰(高并发),短暂排队 正常现象
    长时间持续排队,资源使用率低 考虑提高并发
    资源瓶颈,长时间持续阻塞 CPU分配过低
    实际并发未达到上限排队 考虑是否是BUG
    内存 内存估算过大,实际使用很少 统计信息不准;设置memory_limit
    普遍内存估算大,实际使用也大 内存分配过低;内存瓶颈考虑扩容
    实际估算内存未达上限 考虑是否是BUG
    CCN 内存估算过大 统计信息不准;设置memory_limit
    大量查询报错,CCN排队 报错时查询信息不会实时同步CCN
    CCN不止一个,查询等待5s运行 多CCN导致DN内存收集失败
    CN/CCN处于RECOVER 重启CN/CCN
    查询已结束,在CCN队列残留 gs_wlm_node_recorver恢复
    CCN查询hang死 低版本mutex锁丢失
    队首作业残留 现象:队首作业不在CCN哈希中
    1. 全局并发排队
    • 单CN实际运行作业数≥全局并发上限,则全局并发排队正常;
    • 单CN实际运行作业数长时间小于全局并发上限,则可能存在计数泄露。
    1. 快车道排队
    • 快车道实际运行作业数≥快车道并发上限,则快车道并发排队正常;
    • 快车道实际运行作业数长时间小于快车道并发上限,则可能存在计数泄露。
    1. 静态慢车道排队
    • 慢车道实际运行作业数≥慢车道并发上限,则慢车道并发排队正常
    • 慢车道实际运行作业累计估算内存≥慢车道内存上限,则慢车道内存占用达到上限导致排队,关注是否有查询估算内存过大;
    • 如果慢车道并发和内存占用长时间达不到上限,则可能存在计数泄露。
    1. 动态CCN排队
      如果查询在CCN排队,可使用附件中自定义资源池监控视图和作业监控视图确认排队原因,或查询CCN开发者视图确认排队原因(不推荐):
    SELECT * FROM pg_stat_get_workload_struct_info();
    

    CCN上可能的排队原因:

    • CCN全局可用内存不足导致排队,此时需特别关注是否有查询估算内存过大;
    • 资源池实际运行作业数≥慢车道车道并发上限,资源池并发上限,正常排队;
    • 资源池实际运行作业累计估算内存≥慢车道内存上限,则慢车道内存占用达到上限导致排队,此时需特别关注是否有查询估算内存过大;
    • 资源池实际运行作业数或占用内存与记账值不符,则可能存在计数泄露BUG;
    • 队首作业在CCN哈希中不存在,说明队首作业残留导致查询不能正常下发;
    • CN/CCN处于recover状态或收集DN内存信息失败(多CCN)导致所有查询等待5s下发,现象为所有查询排队时间均为5~6s。

    4. 总结

    本文介绍内存管控基本原理和其能力,并列举负载管理常用视图,同时着重介绍了PGXC_STAT_ACTIVITY和PG_SESSION_WLMSTAT在实际应用中的差异,实际应用过程中可以根据实际需求将两个视图进行关联查询,为性能分析、负载管理提供帮助。由于现网问题比较繁杂,本文给出了三种常用的自定义视图,可供参考。最后对因为排队的可能原因以及解决措施进行梳理。

    【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
    • 点赞
    • 收藏
    • 关注作者

    评论(0

    0/1000
    抱歉,系统识别当前为高风险访问,暂不支持该操作

    全部回复

    上滑加载中

    设置昵称

    在此一键设置昵称,即可参与社区互动!

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。