GPDB-疑难杂症-使用资源组入库OOM

来源:这里教程网 时间:2026-03-14 20:53:46 作者:

GPDB-疑难杂症-使用资源组入库OOM

1、问题

GPDB6资源组可以使业务在事务级别控制资源的使用,业务侧启用资源组后,入库时查看数据库日志发现大量OOM报错: ERROR...Out of memory...Resource group memory limit reached...INSERT INTO ... SELECT... 业务连接用户具备 superuser权限,使用admin_group资源组。对memory_limit等资源组属性配置进行调整,仍持续报错。 gp_resgroup_memory_policy为eager_free,gp_ressource_group_memory_limit为0.7,statement_mem为200MB,gp_resource_group_bypass为off。 memory_limit调整后,查看gp_toolkit.gp_resgroup_status_per_segment视图,发现全局可用内存memory_available还剩余很多,高达46GB,slot配额剩余36GB,资源组共享区没有使用。

2、分析

视图中可以看到资源组可用内存还剩余很多,为什么还会报错 OOM呢?前文我们分析过,bypass模式下,QE上限制仅10MB,若INSERT数据量特别大并且复杂时,倒是有可能超过10MB。但是,通过对资源组机制进行分析,仅SET、RESET、SHOW语句才会bypass模式,通过日志可以看到时INSERT语句OOM。所以又是什么原因呢? 我们找到 OOM报错日志的位置: gp_failed_to_alloc函数中:   也就是错误码是 MemoryFailure_SystemMemoryExhausted 。根据该错误码向上回溯:该错误码由 gp_malloc_internal函数调用VmemTracker_ReserveVmem时的返回值。进一步看代码,可知是VmemTracker_ReserveVmemChunks的返回值。VmemTracker_ReserveVmemChunks函数中返回该错误码的分支为:   也就是 ResGroupReserveMemory函数返回false时才会报该错误。 前文已分析,返回 false的场景也就两种,一种是bypass模式下的10MB限制,另一种是资源组定义的内存。 我们分别在这两个分支处添加打印日志,看下到底是哪个场景导致 OOM的。 经测试复现, 确实是 INSERT语句,走bypass模式分支报的错 Bypass模式只能是SET、RESET、SHOW语句才会用,前文我们也分析了,同一个事务内的SQL语句都使用同一个资源组,业务会不会将INSERT语句和SET/RESET/SHOW放在一起了? 返回来,查看业务的 SQL,发现执行INSERT前确实有个SET statement_mem语句。询问业务侧,是否将这两个语句放到一个事务里了,但人家回应两个在单独事务里。有时候不能太相信业务端,还真得深究他们的代码: 他们通过 JDBC连接GPDB,默认情况下为自动提交,也就是说这两个是独立的两个事务 始终怀疑,这两个语句在同一个事务中,好了,继续验证:修改代码,让 jdbc连接服务后执行SET语句前sleep 30秒,这段时间足够我们ps看到服务端的进程ID,gdb跟踪该PID,在QD端StartTransaction和CommitTransaction处都打上断点,以及QE端资源组分配函数 SwitchResGroupOnSegment 上打断点。 业务 JDBC执行后,StartTransaction仅执行了一次,QE端先执行SET语句,确实走的bypass模式,然后再执行INSERT,它确实在SET事务内,同样走bypass模式。 到此,十分清楚了, SET和INSERT在同一个事务内,而SET语句在前,它的事务分配资源组bypass模式,后续的INSERT命令继续使用该资源组,同样继续走bypass模式,所以限制仍旧是10MB 那出问题的就是 JDBC了,使用默认自动提交情况下,将SET命令和INSERT语句一起发送时,成为了一个事务。有可能是JDBC的bug。 怎么解决?将 SET命令单独放在显式事务中:BEGIN;SET...;COMMIT;然后再执行INSERT,这样将其分开,INSERT独立一个事务,让其走资源组属性的限制。Ok,问题解决!

相关推荐