前言
在日常数据库的使用中,难免会遇到一些内存问题。此次博文主要向大家分享一些华为云数仓GaussDB(DWS)内存的基本框架以及基本视图的使用,以便遇到内存问题后可以有一个基本的判断。
注意,本篇博文基于华为云数仓GaussDB(DWS) 8.0版本,其他版本细节上或许稍有不同。
内存常用视图
1. PV_TOTAL_MEMORY_DETAIL视图
该视图会展示当前数据库节点的内存使用信息,单位为MB。
视图中个字段的含义:nodename:节点名称,memorytype:内存类型,memorymbytes:对应内存类型的大小。
常用的内存类型有以下几种:
- max_process_memory:取自GUC参数max_process_memory的配置,表示一个数据库节点最大可使用的物理内存。
- process_used_memory:取自/proc/pid/statm(第二个值) * pagesize,pid替换为当前节点所在的进程号。表示当前节点所处进程已使用的内存。
- max_dynamic_memory:由下面公式计算而来,表示Gaussdb内核所能使用的最大内存。
- max_dynamic_memory = max_process_memory- max_cstore_memory - udf_reserved_memory - max_shared_memory ;
- dynamic_used_memory:GaussDB内核已使用内存,由GaussDB内存管理在申请内存时统计而来。
- dynamic_peak_memory:GaussDB内核使用内存峰值,由GaussDB内存管理在申请内存时统计而来。
- dynamic_used_shrctx:GaussDB内核已使用线程间共享内存上下文内存大小,由GaussDB内存管理在申请内存时统计而来。
- dynamic_peak_shrctx:GaussDB内核已使用线程间共享内存上下文内存峰值,由GaussDB内存管理在申请内存时统计而来。
- max_shared_memory:进程间最大共享内存大小
- shared_used_memory:进程间已使用共享内存大小,由/proc/pid/statm(第三个值) * pagesize值统计而来。
- max_cstore_memory:列存允许的最大使用内存,由GUC参数cstore_buffers配置。
- cstore_used_memory:列存已使用内存,一般包含列存或HDFS使用过程中所消耗的内存。
- other_used_memory:通常表示除去GaussDB内核使用的内存以外的内存使用,通常是三方库使用所消耗的内存,例如LLVM,Kerberos等。
postgres=# select * from PV_TOTAL_MEMORY_DETAIL;
nodename | memorytype | memorymbytes
--------------+-------------------------+--------------
coordinator1 | max_process_memory | 12288
coordinator1 | process_used_memory | 240
coordinator1 | max_dynamic_memory | 11564
coordinator1 | dynamic_used_memory | 229
coordinator1 | dynamic_peak_memory | 234
coordinator1 | dynamic_used_shrctx | 1
coordinator1 | dynamic_peak_shrctx | 1
coordinator1 | max_shared_memory | 211
coordinator1 | shared_used_memory | 139
coordinator1 | max_cstore_memory | 512
coordinator1 | cstore_used_memory | 0
coordinator1 | max_sctpcomm_memory | 0
coordinator1 | sctpcomm_used_memory | 0
coordinator1 | sctpcomm_peak_memory | 0
coordinator1 | other_used_memory | 0
coordinator1 | gpu_max_dynamic_memory | 0
coordinator1 | gpu_dynamic_used_memory | 0
coordinator1 | gpu_dynamic_peak_memory | 0
coordinator1 | pooler_conn_memory | 0
coordinator1 | pooler_freeconn_memory | 0
coordinator1 | storage_compress_memory | 0
coordinator1 | udf_reserved_memory | 0
(22 rows)
2. PV_SESSION_MEMORY_DETAIL视图
华为云数仓GaussDB(DWS)的内存管理框架沿用了之前的内存上下文的思路。在PV_SESSION_MEMORY_DETAIL的视图中,将会统计各线程的内存上下文维度统计的内存使用情况。
视图中个字段的含义如下:
Sessid:表示Session ID,由线程启动时间+线程标识拼接而来。
Sesstype:线程名称
Contextname:内存上下文名称。
Level:内存上下文层级。
Parent:父内存上下文名称。
Totalsize:当前内存上下文内存大小
Freesize:当前内存上下文已释放内存大小
Usedsize:当前内存上下文已使用大小。
postgres=# select * from PV_SESSION_MEMORY_DETAIL order by totalsize desc;
sessid | sesstype | contextname | level | parent | totalsize | freesize | usedsize
----------------------------+-------------------------+------------------------------+-------+------------------------------+-----------+----------+----------
0.140169093357952 | postmaster | Postmaster | 1 | TopMemoryContext | 26566912 | 23912 | 26543000
0.140169093357952 | postmaster | gs_signal | 1 | TopMemoryContext | 4272464 | 2050224 | 2222240
1594694378.140168361137920 | WLMCollectWorker | CacheMemoryContext | 1 | TopMemoryContext | 1455032 | 268488 | 1186544
1594694378.140168296134400 | WLMarbiter | CacheMemoryContext | 1 | TopMemoryContext | 1455032 | 266696 | 1188336
1594694378.140168465999616 | JobScheduler | CacheMemoryContext | 1 | TopMemoryContext | 1455032 | 239584 | 1215448
1594708276.140168270964480 | postgres | CacheMemoryContext | 1 | TopMemoryContext | 1455032 | 316392 | 1138640
1594694438.140168207001344 | postgres | CacheMemoryContext | 1 | TopMemoryContext | 1455032 | 329944 | 1125088
1594694378.140168344356608 | WLMmonitor | CacheMemoryContext | 1 | TopMemoryContext | 1455032 | 269528 | 1185504
1594708276.140168270964480 | postgres | TempSmallContextGroup | 0 | | 550592 | 160320 | 114
1594694438.140168207001344 | postgres | TempSmallContextGroup | 0 | | 530816 | 148256 | 107
1594708276.140168270964480 | postgres | SRF multi-call context | 5 | FunctionScan_140168270964480 | 496704 | 8032 | 488672
3. PG_SHARED_MEMORY_DETAIL视图
华为云数仓GaussDB(DWS)除了通用内存上下文以外,还包含共享内存上下文类型用于线程间共享数据。由于共享内存上下文是属于一个进程的,故该视图相比PV_SESSION_MEMORY_DETAIL,不存在sessid,其他的字段含义相同。
postgres=# select * from PG_SHARED_MEMORY_DETAIL order by totalsize desc;
contextname | level | parent | totalsize | freesize | usedsize
----------------------------------------+-------+----------------------------------------+-----------+----------+----------
Workload manager memory context | 1 | ProcessMemory | 1056832 | 6080 | 1050752
PoolerAgentContext | 2 | PoolerMemoryContext | 57344 | 36000 | 21344
PoolerCoreContext | 2 | PoolerMemoryContext | 57344 | 30544 | 26800
ProcessMemory | 0 | | 57344 | 28304 | 29040
wlm iostat info hash table | 2 | Workload manager memory context | 24576 | 10832 | 13744
WaitCountGlobalContext | 1 | ProcessMemory | 24576 | 9984 | 14592
wlm user info hash table | 2 | Workload manager memory context | 24576 | 10832 | 13744
OBS connector cache | 1 | ProcessMemory | 24576 | 15056 | 9520
Resource pool hash table | 2 | Workload manager memory context | 17984 | 2704 | 15280
Dummy server cache | 1 | ProcessMemory | 8192 | 2832 | 5360
Node Pool | 3 | PoolerCoreContext | 8192 | 768 | 7424
内存相关数据收集
通过前面讲述的几个内存视图,我们可以对华为云数仓GaussDB(DWS)内存有一个整体的理解。下面将分享几个内存相关数据收集的功能。
注意: 鉴于论坛中的问题多是release版本,故debug版本的各种内存相关功能将不再此次介绍以免混淆。同时收集数据就会带来一些消耗,避免长期大规模的使用下面的方案,仅用作问题诊断数据分析使用。
1. pv_session_memctx_detail函数
通过上面的视图介绍我们了解到了PV_SESSION_MEMORY_DETAIL视图的作用。我们可以通过pv_session_memctx_detail打印出该线程内存上下文的详细信息。注意第一个参数表示线程ID,我们根据上线的介绍得知sessid的后半部分就是线程ID。第二个参数表示需要打印内存上下文的名称,在release为空才可以生效即由TopMemoryContext开始递归打印内存上下文信息。Release版本不包含chunk的详细信息。
例如:
select * from pv_session_memctx_detail(140168207001344,'');
生成的文件默认在/tmp/dumpmem下,文件中三列分别表示内存上下文名称,总大小,剩余大小。
文件内容样例:
140168207001344_1594695418.log
TopMemoryContext, 460808, 24728
Record information cache, 24576, 14928
TableSpace cache, 8192, 2304
set params hash table, 8192, 2832
VecFuncHash, 122272, 20928
MaskPasswordCtx, 8192, 8144
RowDescriptionContext, 8192, 7104
MessageContext, 8192, 7104
Operator class cache, 8192, 768
smgr relation table, 24576, 8880
2. memory_tracking_mode参数
除了上面的内存上下文数据统计,我们还可以通过memory_tracking_mode设置内存信息统计的模式,共支持四种模式:
none:不启动内存统计功能。
normal:仅做内存实时统计,不生成文件。
executor:生成统计文件,包含执行层使用过的所有已分配内存的上下文信息。当为executor模式时,将在GaussDB进程(取决于在哪个数据节点最终执行了该算子)的pg_log目录下生成cvs格式文件,命名方式为:memory_track_<DN名称>_query_<queryid>.csv。作业执行时,执行器postgres线程和所有stream线程执行的算子信息,都将输入该文件。其中各字段分别为:输出顺序号、线程内分配内存上下文的顺序号、当前内存上下文的名称、父内存上下文的输出顺序号、父内存上下文的名称、内存上下文树形层次级别号、当前内存上下文使用的内存峰值、当前内存上下文及其所有子内存上下文使用的内存峰值、当前线程所在query的plannodeid。
fullexec:生成文件包含执行层申请过的所有内存上下文信息。当设置为fullexec模式时,输出信息和executor模式相同,但可能增加部分内存上
下文分配信息,因为所有申请内存(无论是否申请成功)相关的信息都会被打印出来。由于仅记录内存申请信息,故记录中内存上下文使用的峰值均为0。
csv文件内容样例:
memory_track_datanode1_query_72339069014639220.csv
0, 0, ExecutorState, 0, (null), 0, 8K, 656K, 4
1, 4, CStoreScan_139944754403072, 0, ExecutorState, 1, 272K, 625K, 4
2, 9, cstore scan per scan memory context, 1, CStoreScan_139944754403072, 2, 24K, 24K, 4
3, 8, cstore scan memory context, 1, CStoreScan_139944754403072, 2, 328K, 328K, 4
4, 2, VecToRow_139944754403072, 0, ExecutorState, 1, 23K, 23K, 4
0, 0, ExecutorState, 0, (null), 0, 8K, 144K, 0
1, 13, Stream_72339069014639220_4, 0, ExecutorState, 1, 72K, 72K, 0
2, 10, Sort_72339069014639220_3, 0, ExecutorState, 1, 8K, 40K, 0
3, 16, TupleSort, 2, Sort_72339069014639220_3, 2, 32K, 32K, 0
4, 2, Agg_72339069014639220_2, 0, ExecutorState, 1, 24K, 24K, 0
一些诊断方案:
1. 内存膨胀
在release版本调试工具以及信息比较受限,基本都是先通过前面介绍的三种视图初步定位大致功能。首先查看PV_TOTAL_MEMORY_DETAIL视图确定是哪一块内存出现了膨胀或者泄露。若是other_used_memory则要考虑三方仓的场景。若是dynamic_used_memory较大,则要查PV_SESSION_MEMORY_DETAIL视图,查看哪个线程,哪个内存上下文占用内存过多。根据这些信息推断出大致问题场景。
2. 内存不足
在内核发现内存不足的时候会有memory is temporarily unavailable的日志提示。首先观察日志,若日志里是reaching the database memory limitation则说明内核使用内存到达了max_dynamic_memory,则需要根据PV_SESSION_MEMORY_DETAIL视图分析是那个内存上下文占用内存较多,分析出业务场景。若日志里是reaching the OS memory limitation,则表示是操作系统分配内存失败导致,需要看操作系统参数配置以及内存硬件等情况。
小结:
生产环境出现内存问题一般会比较棘手,而且release版本内存检测工具以及数据信息使用都比较受限,遇到问题需要通过上述的方案以及手段快速定位出出现内存问题的相关业务场景。有了业务场景,后面通过debug版本使用ASAN地址消毒技术以及Jemalloc Profiling便可以较快的定位出来。
来源:oschina
链接:https://my.oschina.net/u/4526289/blog/4465597