流计算场景下DolphinDB发生OOM,如何排查具体的内存使用的情况?如何释放内存?如何优化流计算内存?

主要用DolphinDB做流计算,多人同时在使用,通过subscribeTable提交了一些订阅,一部分subscribeTable的handler中会用到了自定义函数,另一部分用的是流引擎。运行一段时间后出现OOM,请问如何排查内存具体的使用情况,以及如何释放掉不必要的内存占用?如何优化流计算内存?

请先 登录 后评论

1 个回答

Yating Xie

1、查看当前所有数据节点内存使用情况(maxMemSize 是程序的实际最大内存限制,oom的情况下memoryUsed应该已经基本打满至maxMemSize了)

select site, maxMemSize, memoryUsed\1024\1024\1024 as memoryUsed, memoryAlloc\1024\1024\1024 as memoryAlloc from rpc(getControllerAlias(),getClusterPerf)


程序的实际最大内存限制,取决于license里授权的内存大小和.cfg配置文件中的maxMemSize值中的较小值。如果不符合您的预期,可以确认一下license授权和内存配置参数。

a. 查看授权的内存大小(社区版license限制4G;可以在官网申请企业版试用license,更多节点、CPU核数、内存。)

license() 

b. 查看.cfg配置文件中maxMemSize参数

getConfigure(`maxMemSize)


2、释放所有节点的缓存(定义变量占用的内存不会释放)

pnodeRun(clearAllCache)


3、查看变量占用内存大小

pnodeRun(objs) //查询每个节点定义变量占用内存(不共享的),bytes字段
pnodeRun(objs{true}) //查询每个节点定义变量占用内存(共享的),bytes字段

查看每个数据节点上定义的变量和占用的内存:使用undef()、undef all、变量名=NULL释放非共享变量占用内存;使用 undef("sharedTable", SHARED)释放共享变量占用内存;使用dropStreamTable()删除流数据表。如果流数据表启用了持久化,该函数也会将磁盘上持久化的数据删除。


4、查看流引擎占用内存大小

getStreamEngineStat().CrossSectionalEngine // 查看CrossSectionalEngine 的内存
getStreamEngineStat().ReactiveStreamEngine // 查看ReactiveStreamEngine 的内存
getStreamEngineStat().AsofJoinEngine // 查看AsofJoinEngine 的内存: memoryUsed字段,单位Byte,其他引擎查询方式类似

查看每个流计算引擎占用的内存大小,这里的内存主要是引擎中用于保存状态而使用的内存。

删除引擎即可释放引擎占用的内存:a.使用dropStreamEngine()释放指定的流数据引擎的定义; b.使用变量名=NULL 从内存中释放流数据引擎的句柄的定义(若内存中存在这个变量则需要这一步)


5、查看正在运行的作业

pnodeRun(getRecentJobs)  //查看后台在运行的作业
pnodeRun(getConsoleJobs) //查看前台在运行的作业

排查是否有正在运行且可能消耗大量内存的作业


6、流订阅也会占用内存

subscribeTable中handler使用自定义函数定义时,在流计算过程中调用handler而占用的内存目前不方便查询。如果在经过1-5点确认和释放后,仍还有大量内存无法定位到具体的用途,则可能是使用自定义函数的handler占用了这部分内存,可以通过unsubscribeTable反订阅掉相关的订阅,来释放这部分内存。getStreamingStat().pubTables可以查看subscribeTable提交的所有订阅关系。


流计算内存优化:

1、引擎流水线级联

流引擎均实现了数据表(table)的接口,因此只要将后一个引擎作为前一个引擎的输出,即可实现多个引擎流水线处理。相较于通过中间表来串联多个引擎的实现方法,使用引擎级联可以大大减少对中间表的内存管理。

级联的实现脚本可参考:多个引擎级联使用 问题中的第二个回答


2、引擎参数调优

如果通过getStreamEngineStat()查看流引擎占用内存过大,可以通过调整createEngine时的部分参数来适当减少引擎的内存占用。

以asofjoin引擎为例,其主要的内存占用为存放在内存中的历史数据。如果在订阅过程中发现asofjoin引擎的内存过大,可以通过参数garbageSize,清理不再需要的历史数据。garbageSize的大小需要根据实际情况设置,大致可以按照每个小时每个key会有多少条数据设置。

原理如下:首先garbageSize是针对key的,即每个key分组内数据到了才清理。garbageSize过小,会频繁清理历史数据带来不必要的开销;garbageSize过大,可能会一直达不到garbageSize这个阈值而无法触发清理,造成asofjoin中不再需要的历史数据一直没有被清理。所以建议按照一个小时清理一次,估计一下具体情况每个小时每个key会有多少数据,来设置garbageSize值。


3、handler自定义函数优化



请先 登录 后评论