GaussDB for DWS Hang问题定位指南
1 Hang问题基础知识
GaussDB for DWS 为分布式数据库,通常由于单节点亚健康、系统资源紧张或查询本身的计划等问题,造成系统疑似发生Hang。Hang问题的产生原因由很多种,比如,死锁等待、日志同步等待、事务超时、通信故障、数据溢出发生死循环等等,更为常见的是由于执行慢、中间结果集倾斜而导致的疑似Hang。掌握Hang问题的基本定位方法对于大集群环境下快速找准疑似阻塞点,修复故障环境或优化执行性能是至关重要的。
1.1 常用视图
目前,GaussDB for DWS对外提供诸多系统视图,可以用来辅助Hang问题的分析定位,
常用视图及用法说明如下表所示。(☆代表常用程度)
pgxc_stat_activity ☆☆☆ 查询当前集群所有DN实例上各个session的信息,重点关注正在执行(state状态为active)的SQL。我们一般首先分析pgxc_stat_activity中的内容,初步根据执行时间筛选出疑似query,然后使用此query的query_id和视图pgxc_thread_wait_status结合,获取此query集群级别的线程状态进行hang问题分析。
注:此视图需要以超级用户的身份来运行
在问题分析时,我们首先需要客户反馈的疑似hang的作业的信息,根据作业所在的databse、运行作业的用户身份、运行作业客户端以及运行作业所连接的实例CN名称初步筛选出问题SQL的运行信息,具体运行信息见附件中字段含义解释。比如疑似hang作业是以omm用户运行在postgres数据库连接到cn_5001实例上运行的,我们使用如下SQL进行作业状态查询 我们可以根据上述返回的结果,结合作业运行的客户端名称、客户端ip、作业query运行开始时间query_start进一步筛选出疑似hang作业。
【附:视图各字段含义】 字段名称数据类型字段描述coornametext运行业务SQL的CN节点名称datidoid用户会话在后台连接到的数据库OID。datnamename用户会话在后台连接到的数据库名称。可以看到此语句实际在哪个数据库运行,来帮助区分是什么业务。pidbigint后台线程ID。即运行此SQL的线程的线程号,此线程号在pg_thread_wait_status/pg_locks等视图中也存在,可以用这个线程号来与这些视图进行关联。usesysidoid登录该后台的用户OID。usenamename登录该后台的用户名。执行此SQL的用户名,可以用来确认是什么用户调起的业务。application_nametext连接到该后台的应用名。应用名称,一般有三种:l gsql:此SQL是从gsql客户端发起l Data Studio:从Data Studio客户端发起的SQLl cn_50XX:代表从远端CN发送过来的SQL语句,一般出现在DDL、DCL、analyze、vacuum作业场景下l 其它:其它业务客户端发起的业务连接,如果应用程序未显式命名application_name,数据侧一般显式为unkonwnclient_addrinet连接到该后台的客户端的IP地址。 如果此字段是null,它表明通过服务器机器上UNIX套接字连接客户端或者这是内部进程(如autovacuum)。可以用来确定是从哪个机器发起的连接,进而帮助确认是什么业务发起的语句client_hostnametext客户端的主机名,这个字段是通过client_addr的反向DNS查找得到。这个字段只有在启动log_hostname且使用IP连接时才非空。client_portinteger客户端用于与后台通讯的TCP端口号,如果使用Unix套接字,则为-1。通过此字段圈定业务SQL发起客户端backend_starttimestamp with time zone该后台线程启动的时间,即当客户端连接到服务器的时间。xact_starttimestamp with time zone启动当前事务的时间,如果没有事务是活跃的,则为null。如果当前查询是首个事务,则这列等同于query_start列。如果启用了显式事务,即使用begin/start transaction等开启了一个事务,则此字段代表事务开始的时间。query_starttimestamp with time zone开始当前活跃SQL的开始时间, 如果state的值不是active,则这个值是上一个SQL的开始执行时间state_changetimestamp with time zone上次state字段值变化的时间。waitingboolean如果后台当前正等待锁则为true,否则为falseenqueuetext工作负载管理资源状态。· 语句当前的排队情况,包括:· Global::在全局队列中排队。 · Respool:在资源池队列中排队。 · CentralQueue:在中心协调节点(CCN)中排队。 · Transaction:语句处于一个事务块中排队。 · StoredProc : 语句处于一个存储过程中排队。 · None:未在排队。 · Forced None : 事务块语句或存储过程语句由于超出设定的等待时间而强制执行。上面这些状态表明了当前语句的排队情况,如果处在排队状态,语句是不在执行的,也不会占用系统资源。statetext该后台当前总体状态。状态值可能是如下的一种:· active:后台正在执行一个作业。 · idle:后台线程空闲,且不在一个事务块中。 · idle in transaction:后台线程空闲,且在事务块中· idle in transaction (aborted):后台线程空闲,且后台线程在事务块中有语句执行失败且没有执行rollback命令 · fastpath function call:后台正在执行一个fast-path函数。 · disabled:如果后台禁用track_activities,则报告这个状态。resource_poolname用户作业关联的资源池。query_idbigint查询语句的ID。当前语句的唯一标识,可以用此字段与pg_thread_wait_status关联。进一步进行问题分析定位querytext该后台的最新查询。如果state状态是active(活跃的),此字段显示当前正在执行的查询。所有其他情况表示上一个查询。语句默认仅显示1024字节。
|
pgxc_thread_wait_status ☆☆☆☆☆ 查询集群全局所有线程的层次调用关系及阻塞等待情况,通常在视图查询语句增加其他过滤条件(比如根据pgxc_stat_activity筛选出来的疑似hang的SQL的query_id),缩小关注排查范围。 【附:视图各字段含义】 字段名称数据类型字段含义描述node_nametext实例的名称。db_nametext数据库名称。thread_nametext线程名称。query_idbigint业务SQL的ID编号,同一条SQL对应的所有的执行线程的query_id是相同的,与pg_stat_activity中query_id一致tidbigint当前线程的线程号。与pgxc_stat_activity中的pid、pg_locks中的pid一致lwtidinteger当前线程的轻量级线程号。使用此线程号可以在所在节点上进行gstack获取此线程运行栈信息ptidintegerstreaming线程的父线程号tlevelintegerstreaming线程的层级。与执行计划的层级(id)相对应。smpidintegersmp执行模式下并行线程的并行编号。wait_statustext当前线程的等待状态。等待状态的详细信息请参见资料。一般常见的状态有:wait node:dn_xxxx_xxxx:表示在等待某个DNnone:表示正在执行,没有等待任何其他节点acquire lock :表示正在等待锁。这时需要到对应节点上查看pg_locks视图。
|
pg_thread_wait_status ☆☆☆☆ 单个实例上所有作业线程的层次调用关系及阻塞等待情况,在大集群复杂query问题定位时,视图pgxc_thread_wait_status返回的信息过多,会对问题定位形成一定干扰,这时可以在CN上通过execute direct on语法获取指定dn实例的作业线程信息。比如要获取dn_6001_dn_6002节点的作业线程调用信息
|
pgxc_comm_recv_stream ☆☆☆ 查询集群所有DN的通信库接收流状态,辅助通信层发生收发Hang的排查定位。 |
pgxc_comm_send_stream ☆☆☆ 查询集群所有DN的通信库发送流状态,与pgxc_comm_recv_stream视图结合使用,来定位通信层的收发Hang问题。 |
pgxc_prepared_xacts ☆☆ 查询集群中所有节点的启动事务信息,辅助事务超时场景下的Hang问题定位,通过查询该视图获取gxid,然后结合pgxc_xacts_iscommitted(gxid)可以获知事务是否提交。 |
pgxc_running_xacts ☆☆ 查询集群中所有节点的运行事务信息。 |
pg_locks ☆☆ 查询当前实例的锁状态,辅助死锁等待的Hang问题定位。 名称类型引用描述locktypetext-被锁定对象的类型:relation,extend,page,tuple,transactionid,virtualxid,object,userlock,advisory。databaseoidPG_DATABASE.oid被锁定对象所在数据库的OID。· 如果被锁定的对象是共享对象,则OID为0。 · 如果是一个事务ID,则为NULL。relationoidPG_CLASS.oid表的OID,如果锁定的对象不是表,也不是表的一部分,则为NULL。锁等待一般都是等待表的锁,用relation做条件可以看到当前的表锁被谁持有。pageinteger-关系内部的页面编号,如果对象不是关系页或者不是行页,则为NULL。tuplesmallint-页面里边的行编号,如果对象不是行,则为NULL。virtualxidtext-事务的虚拟ID,如果对象不是一个虚拟事务ID,则为NULL。transactionidxid-事务的ID,如果对象不是一个事务ID,则为NULL。classidoidPG_CLASS.oid包含该对象的系统表的OID,如果对象不是普通的数据库对象,则为NULL。objidoid-对象在其系统表内的OID,如果对象不是普通数据库对象,则为NULL。objsubidsmallint-对于表的一个字段,这是字段编号;对于其他对象类型,这个字段是零;如果这个对象不是普通数据库对象,则为NULL。virtualtransactiontext-持有此锁或者在等待此锁的事务的虚拟ID。pidbigint-持有或者等待这个锁的服务器线程的逻辑ID。如果锁是被一个预备事务持有的,则为NULL。语句pid,可以看到这个pid是在等待哪几各锁,持有哪几各锁。modetext-这个线程持有的或者是期望的锁模式。grantedboolean-· 如果锁是持有锁,则为TRUE。 · 如果锁是等待锁,则为FALSE。表示锁被谁持有fastpathboolean-如果通过fast-path获得锁,则为TRUE;如果通过主要的锁表获得,则为FALSE。
|
pgxc_node ☆☆ 查询集群中所有实例节点信息,重点关注节点的node_name, node_port, node_id。 |
除过上述常用视图,Hang问题定位过程需要根据实际场景,结合执行计划、gstack工具、系统日志等共同分析定位。
1.2 简单示例
比如在执行create table的时候疑似发生hang,那么我们可以执行以下操作定位问题
1. 获取疑似hang的SQL的query_id
select * from pgxc_stat_activity where state = ‘active’ and lower(query) like ‘create table %’;
2. 获取此作业的线程等待关系
select * from pgxc_thread_wait_status where query_id = xx;
xx:为上一步获取的疑似hang的SQL的query_id值
分析此query_id相关的线程的状态(字段wait_status),查看是否有acquire lock状态的线程,找到其node_name 和 tid字段
3. 到对应的node_name上获取锁信息
execute direct on (xx) ‘select * from pg_locks where pid = xxx’;
--xx: 上一步获取的node_name字段的值
--yy:上一步获取的tid字段值。
获取等待加锁的表信息(字段relation)
4.到对应的node_name上获取此表的持锁信息
execute direct on (xx) ‘select * from pg_locks where relation = yy and granted = true’;
--xx: 第二步获取的node_name字段的值
--yy: 第三步获取的等待加锁字段的值
获取持锁的线程(字段pid)
5.获取持锁的作业信息
select * from pgxc_stat_activity where pid=xx;
--xx: 第四步获取持锁线程信息
字段query的内容即为持锁线程信息,也是阻塞create table语句的作业信息
2 Hang问题分类
客户侧感知的hang分为三种
1. 真实hang
一般是轻量级锁缺陷、执行链路环状或者死循环执行。这种场景下作业永远无法执行完
2. 执行慢:
业务执行慢,远远超出客户的预期,客户侧产生hang的认知效果。这种问题最终需要通过调优解决
3. 锁等待:
因抢占不到锁资源,导致作业排队等待加锁。这种场景的表现是要么作业执行时间边长,要么等待一段时间(一般为20min)之后报锁超时的失败信息
根据以往的经验,局点常见的hang问题有以下几种
3 Hang问题定位方法及解决措施
3.1 基本步骤
Step1. cm_ctl query查询集群当前状态,确保集群状态正常;
Step2. gsql连接数据库,执行select * from pgxc_stat_activity,查询目标查询的query_id,有时候可以增加where state = ‘active’筛选活跃SQL;
Step3. 执行select * from pgxc_thread_wait_status where query_id = xxx,查询集群全局与之关联的所有线程的层次调用关系及阻塞等待情况。自上而下,逐层分析,确定疑似阻塞节点及线程信息,甚至,可以绘制线程等待关系图,更加直观地分析当前Hang问题的根因。除此,可结合执行计划或gstack查看线程堆栈,进一步佐证定位结论。
Step4. 如果Step3仍无定论,则针对其他常见Hang场景(目前以锁等待和通信收发等待最为常见),结合2.1节相应视图,进一步分析定位:
a) 锁等待:从Step3的查询结果分析线程等待关系,如果阻塞线程状态为acquire lock,则进一步执行select * from pg_locks where pid = xxx查询阻塞线程的加锁情况;
b) 通信层数据收发成环:从Step3的查询结果分析线程等待关系,如果阻塞线程状态一直为flush data: wait quota,则可能是通信层收发过程hang死,继续执行select * from pgxc_comm_send_stream和select * from pgxc_comm_recv_stream,可以根据Step3的查询结果增加where条件限定node_name、remote_name、query_id、pn_id(即plevel),进一步排查wait quota的根因是否是发送端或接收端数据流异常或者通信问题等。
- 点赞
- 收藏
- 关注作者
评论(0)