华为云数仓GaussDB(DWS)内存知识梳理
前言
在日常数据库的使用中,难免会遇到一些内存问题。此次博文主要向大家分享一些华为云数仓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 1594694378.140168465999616 | JobScheduler | TempSmallContextGroup | 0 | | 489152 | 120672 | 102 1594694378.140168361137920 | WLMCollectWorker | TempSmallContextGroup | 0 | | 477184 | 118168 | 98 1594694378.140168344356608 | WLMmonitor | TempSmallContextGroup | 0 | | 477184 | 118280 | 98 1594694378.140168296134400 | WLMarbiter | TempSmallContextGroup | 0 | | 477184 | 118136 | 98 1594694438.140168207001344 | postgres | TopMemoryContext | 0 | | 460808 | 24728 | 436080 1594708276.140168270964480 | postgres | TopMemoryContext | 0 | | 452616 | 5352 | 447264 1594694378.140168361137920 | WLMCollectWorker | TopMemoryContext | 0 | | 411528 | 3272 | 408256 1594694378.140168296134400 | WLMarbiter | TopMemoryContext | 0 | | 411528 | 3032 | 408496 1594694378.140168344356608 | WLMmonitor | TopMemoryContext | 0 | | 411528 | 3272 | 408256 1594694378.140168465999616 | JobScheduler | TopMemoryContext | 0 | | 255240 | 10552 | 244688 0.140169093357952 | postmaster | TopMemoryContext | 0 | | 140680 | 7856 | 132824 1594694438.140168207001344 | postgres | VecFuncHash | 1 | TopMemoryContext | 122272 | 20928 | 101344 1594708276.140168270964480 | postgres | VecFuncHash | 1 | TopMemoryContext | 122272 | 20928 | 101344 1594694378.140168539399936 | CheckPointer thread | TopMemoryContext | 0 | | 116104 | 5944 | 110160 1594694378.140168482780928 | WalWriter thread | TopMemoryContext | 0 | | 107848 | 7224 | 100624 1594694378.140168505317120 | BackgroundWriter thread | TopMemoryContext | 0 | | 107848 | 7144 | 100704 1594694378.140168394700544 | TwoPhaseCleaner thread | TopMemoryContext | 0 | | 107848 | 8280 | 99568 1594694378.140168377919232 | FaultMonitor thread | TopMemoryContext | 0 | | 107848 | 8280 | 99568 1594694378.140168442930944 | PgstatCollector | TopMemoryContext | 0 | | 107848 | 6696 | 101152 1594694378.140168482780928 | WalWriter thread | Timezones | 1 | TopMemoryContext | 83488 | 2832 | 80656 1594694378.140168465999616 | JobScheduler | Timezones | 1 | TopMemoryContext | 83488 | 2832 | 80656 1594694378.140168505317120 | BackgroundWriter thread | Timezones | 1 | TopMemoryContext | 83488 | 2832 | 80656 0.140169093357952 | postmaster | Timezones | 1 | TopMemoryContext | 83488 | 2832 | 80656 1594694378.140168296134400 | WLMarbiter | Timezones | 1 | TopMemoryContext | 83488 | 2832 | 80656 1594694438.140168207001344 | postgres | Timezones | 1 | TopMemoryContext | 83488 | 2832 | 80656 1594694378.140168377919232 | FaultMonitor thread | Timezones | 1 | TopMemoryContext | 83488 | 2832 | 80656 1594694378.140168539399936 | CheckPointer thread | Timezones | 1 | TopMemoryContext | 83488 | 2832 | 80656 1594694378.140168442930944 | PgstatCollector | Timezones | 1 | TopMemoryContext | 83488 | 2832 | 80656 1594694378.140168361137920 | WLMCollectWorker | Timezones | 1 | TopMemoryContext | 83488 | 2832 | 80656
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 dywlm register hash table | 2 | Workload manager memory context | 8192 | 2704 | 5488 node group hash table | 2 | Workload manager memory context | 8192 | 2832 | 5360 sql count lookup hash | 2 | WaitCountGlobalContext | 8192 | 8000 | 192 wlm session info hash table | 2 | Workload manager memory context | 8192 | 2704 | 5488 wlm collector hash table | 2 | Workload manager memory context | 8192 | 2704 | 5488 DFS connector cache | 1 | ProcessMemory | 8192 | 768 | 7424 PoolerMemoryContext | 1 | ProcessMemory | 8192 | 5456 | 2736 operator collector hash table | 3 | Operator resource track memory context | 8192 | 640 | 7552 operator running hash table | 3 | Operator resource track memory context | 8192 | 640 | 7552 Query resource track memory context | 2 | Workload manager memory context | 8192 | 8144 | 48 bad block stat global hash table | 2 | bad block stat global memory context | 8192 | 2704 | 5488 global info hash table | 2 | Workload manager memory context | 8192 | 2832 | 5360 StreamInfoContext | 1 | ProcessMemory | 0 | 0 | 0 Operator resource track memory context | 2 | Workload manager memory context | 0 | 0 | 0 bad block stat global memory context | 1 | ProcessMemory | 0 | 0 | 0 ProcSubXidCacheContext | 1 | ProcessMemory | 0 | 0 | 0 (27 rows)
内存相关数据收集
通过前面讲述的几个内存视图,我们可以对华为云数仓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 tokenize file cxt, 0, 0 hba parser context, 3072, 480 TransactionAbortContext, 32768, 32720 bad block stat thread hash table, 8192, 1664 bad block thread memory context, 0, 0 Portal hash, 8192, 768 PortalMemory, 8192, 8144 Partcache by OID, 8192, 2832 Relcache by OID, 24576, 11904 CacheMemoryContext, 1455032, 329944 pg_index_indrelid_index, 3776, 280 pg_toast_2618_index, 5824, 1760 pg_prepared_xacts, 31744, 3488 pg_db_role_setting_databaseid_rol_index, 5824, 1808 pg_opclass_am_name_nsp_index, 5824, 1768 pg_directory_name_index, 3776, 328 pg_foreign_data_wrapper_name_index, 3776, 328 pg_enum_oid_index, 3776, 328 pg_class_relname_nsp_index, 5824, 1760 pg_foreign_server_oid_index, 3776, 328 pg_statistic_relid_kind_att_inh_index, 5184, 760 pg_cast_source_target_index, 5824, 1808 pg_language_name_index, 3776, 328 pg_collation_oid_index, 3776, 328 pg_amop_fam_strat_index, 5184, 760 pg_index_indexrelid_index, 3776, 280 pg_ts_template_tmplname_index, 5824, 1808 pg_ts_config_map_index, 5824, 1768 pg_partition_partoid_index, 5824, 1768
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便可以较快的定位出来。
- 点赞
- 收藏
- 关注作者
评论(0)