内存问题常用定位视图

目前,GaussDB DWS对外提供诸多系统视图,可以用来辅助内存问题的分析定位,常用视图及用法说明如下表所示。(☆代表常用程度)

  • pv_total_memory_detail ☆☆☆☆☆

    查询当前实例上整体内存使用状态和信息,可以看到各类型内存使用情况,来对当前实例上内存使用情况做一个概要的判断。

    SELECT * FROM pv_total_memory_detail;

    返回结果如下:

1.png

表1 Memorytype中各类型含义
名称 描述
max_process_memory 实例可用最大内存阈值。由guc参数max_process_memory控制。
process_used_memory 实例当前已使用的内存值,从OS top命令RES列取得。如process_used_memory已经或马上要超过max_process_memory,说明当前内存使用已经超限,或马上就要超限。
max_dynamic_memory 实例可使用的最大动态内存
dynamic_used_memory 实例当前已使用的动态内存
dynamic_peak_memory 实例从启动后到目前为止的动态内存峰值
dynamic_used_shrctx 当前已使用的共享内存上下文内存量,也记录在dynamic_used_memory内
dynamic_peak_shrctx 共享内存上下文峰值。如减去sctpcomm_peak_memory后超过1G,说明共享内存没有释放,存在泄漏。
max_shared_memory 最大共享内存,主要为shared_bubffers。
shared_used_memory 实例当前已使用的共享内存,从OS top命令SHR列取得
max_cstore_memory 列存buffer可使用的最大内存,由guc参数cstore_buffers控制。
cstore_used_memory 实例当前已使用的列存buffer.
max_sctpcomm_memory 通信模块可使用的最大内存。
sctpcomm_used_memory 通信模块已使用的最大内存
sctpcomm_peak_memory 通信模块峰值内存
other_used_memory 其他内存占用,为OS  RES- dynamic_used_memory- shared_used_memory- cstore_used_memory后的值。一般为系统中不受memory context管理的第三方组件所占用的内存。如果过大,也有可能是内存泄漏。

 

pv_session_memory_detail ☆☆☆☆☆

查看内存上下文级别的内存占用详细信息

SELECT * FROM pv_session_memory_detail ORDER BY totalsize desc LIMIT 100;

视图中各字段含义如下:

名称 类型 描述
sessid text 线程标识+线程启动时间。使用substr可以将线程号过滤出来,方便和上述其他视图进行关联。
sesstype text 线程名称。
contextname text 内存上下文名称。
level smallint 当前内存上下文的层级。
parent text 父内存上下文名称。
totalsize bigint 当前内存上下文的内存总数,单位字节。指的是分配给当前内存上下文的内存总数,为freesize+usedsize之和。
freesize bigint 当前内存上下文中已释放的内存总数,单位字节。是指当前你内存上下文中预留的内存,只有这个内存上下文可以使用,其他线程及其他内存上下文都不能使用,实际还是当前内存上下文中占用的。
usedsize bigint 当前内存上下文中已使用的内存总数,单位字节。

内存问题定位方法及解决措施

  • Memory is temporary unavailable问题
  1. 当出现memory is temporary unavailable报错后,首先确认是哪个实例报错,是CN还是DN。
  2. 使用gsql登录到报错的实例上,查询pv_total_memory_detail,重点查看以下信息:
    • 当前是否还存在内存不足问题。方法为查看process_used_memory和max_process_memory的关系,如已经大于或比较接近,则说明当前内存使用已经或即将超限。如明显小于,则说明占用内存大的语句已经跑完或者被杀掉。当前系统已经恢复。这时可查看对应的peak_memory值,如peak_memory值过高,说明确实曾经出现过内存使用过大。
    • 当前是哪个类型的内存过大。最常见的是dynamic_used_memory过大,说明动态申请的内存过大,这类问题可能和客户正在运行的SQL强相关。
  3. 如通过2发现当前内存占用仍过高,则进一步使用pv_session_memory_detail继续分析,看内存占用过高是哪个内存上下文引起的。视图中有线程号信息及内存上下文信息,通过这些信息可以判定是什么语句的什么操作占用了过多内存,进而可以cancel此语句,并给客户提出语句优化建议

    常见语句问题为:

    • SQL不下推。如内存问题在CN上出现,很大程度上是因为某个SQL的不下推导致。通过explain确认语句不下推后,将语句进行修改使其下推。
    • 中间结果集倾斜。GaussDB DWS在进行表关联时,优先使用hash join,需要对一张表创建哈希表,当哈希表大小超过work_mem限制时,会进行下盘避免内存占用过多,但如果原始表里或中间结果集中在join列上存在大量重复数据,是无法下盘的,必须全部载入内存中进行计算,会造成内存大量占用。如pv_session_memory_detail中占用内存最大的内存上下文为hash context,则大概率是此问题。这时应对客户的表和SQL进行分析,对重复值进行处理后,再进行关联。
  4. 如通过3没有发现内存占用过高的单个语句,但系统整体内存占用仍过高,则问题原因为参数配置不合理或用户语句并发设置不合理。
    • 局点上线后,或局点业务量增大后频繁报内存不足,很可能是因为max_active_statements设置过高,高并发的语句加起来后超出了系统可用内存上线,此时如检查第一点中参数都合理后,应将max_active_statements调小,让语句排序进行,避免一起运行时报错。
    • 局点新上业务后报内存不足,很可能是因为新业务较为复杂,有多个表join、sort或group by。此时如分析不存在中间结果集倾斜,则需要将并发调小,或将work_mem调小。以上操作都可能导致业务响应时间变长,需要和客户确认。
    • max_process_memory设置过小,导致内存不能充分利用而提前报错。
    • shared_buffer/cstore_buffer设置过大:shared_buffer设大可以增大缓存空间,提高数据读取效率,但如设置过大,会导致语句运行时无法申请到足够的动态内存,导致报错。
    • work_mem/maintainence_work_mem设置过大:在高并发场景下,work_mem设置过大可能导致所有语句的work_mem加起来超过可用动态内存的最大值,从而导致报错。
    • 参数配置不合理。需评估系统关键内存参数是否设置合理。如用户将POC环境直接转为生产。POC环境为了追求极致性能,一般内存参数设置比较激进。而生产系统需要长期稳定运行,内存参数设置应相对保守,此时应调整相关参数。
    • 语句并发设置不合理。此问题与参数配置不合理问题相关。语句并发高,则内存参数配置应较小;反过来说,如内存参数配置较大,则可支撑的语句并发也就相应的要变低。
  5. 如分析时已没有现场,则有3个方法来确认什么语句导致了问题。

    到报错的节点日志中搜索全部memory is temporary unavailable报错,分析可能是哪个语句导致的。

    • 重新让客户运行业务,或等下次业务高峰期时进行分析。
    • 打开active sql。打开后会将内存相关信息记到系统表中。
      执行如下语句打开active sql开关来分析某一时间段并发量和单个sql执行使用的内存信息(如果enable_resource_track和enable_resource_record为off表示该功能关闭)。

      gs_guc reload -Z coordinator -Z datanode -N all -I all -c 'enable_resource_track =on' ;
      gs_guc reload -Z coordinator -Z datanode -N all -I all -c 'enable_resource_record =on' ;
  6. Active sql分析方法如下:

    查询2018-11-9峰值内存使用top10的SQL。

    1. SELECT * FROM pgxc_wlm_session_info WHERE start_time like '%2018-11-9%' ORDER BY nodename,max_peak_memory DESC limit 10;
    2. 查询2018-11-9CPU使用top10的SQL。
      SELECT * FROM pgxc_wlm_session_info WHERE start_time like '%2018-11-9%' ORDER BY nodename,total_cpu_time DESC limit 10;
    3. 查询2018-11-9查询时间最长的top10的SQL。
      SELECT * FROM pgxc_wlm_session_info WHERE start_time like '%2018-11-9%' ORDER BY nodename,duration DESC limit 10;
    4. 查询2018-11-9SQL执行失败,错误信息为“memory is temporarily unavailable”且最大峰值内存超过1G的SQL。
      SELECT * FROM pgxc_wlm_session_info WHERE start_time like '%2018-11-1%' and status='aborted' and abort_info like '%memory is temporarily unavailable%' and max_peak_memory >1000 ORDER BY max_peak_memory desc;
    5. 查询不下推的SQL。
      SELECT * FROM pgxc_wlm_session_info WHERE start_time like '%2018-11-9%' and query_plan like ‘%_REMOTE_TABLE_QUERY_ %’;
    6. 查询不下盘的SQL。
      SELECT * FROM pgxc_wlm_session_info WHERE start_time like '%2018-11-9%' and warning like‘%spill%’;
  • 操作系统OOM问题
  1. 查看/var/log/messages目录下的OS日志,搜索oom-killer,确认是否为gaussdb进程触发的OOM。
  2. 分析数据库内存参数,确认设置是否合理,特别是max_process_memory。

查看集群配置情况和关键参数常用语句

  1. 集群每个物理节点内存、每个节点dn个数。
    SELECT sessid, contextname, level,parent,totalsize,freesize,usedsize,  datname,query_id  FROM pv_session_memory_detail a , pg_stat_activity b  WHERE  split_part(a.sessid,'.',2) = b.pid and b.state='active' ORDER BY usedsize desc limit 20 ;
  2. 监控session total memory size占用最多的TOP20 session 。
    SELECT sessid, sum_total, sum_free,sum_used, query_id, query_start, state, waiting, enqueue,query from (select sessid, sum(totalsize) as sum_total, sum(freesize) as sum_free, sum(usedsize) as sum_used from pv_session_memory_detail group by sessid  ORDER BY sum_total desc limit 20 ) a , pg_stat_activity b  WHERE  split_part(a.sessid,'.',2) = b.pid;
  3. 监控session中占用内存最多的context TOP20 session。
    SELECT sessid, contextname, level,parent, pg_size_pretty(totalsize),pg_size_pretty(freesize),pg_size_pretty(usedsize),  datname,query_id, query  from pv_session_memory_detail a , pg_stat_activity b  WHERE  split_part(a.sessid,'.',2) = b.pid  order by totalsize desc limit 20 ;
  4. 监控当前实例总totalsize memroy大小。
    SELECT pg_size_pretty(sum(totalsize)) FROM pv_session_memory_detail;
  5. 监控当前实例总usedsize memroy大小。
    SELECT pg_size_pretty(sum(usedsize)) FROM pv_session_memory_detail;
  6. 监控当前实例内存总体使用情况。
    SELECT * FROM pg_total_memory_detail;
  7. 监控共享内存实时使用情况。
    SELECT * FROM pg_shared_memory_detail;