求助大佬,MogDB/openGauss 动态内存不足,idle_totalsize占用很高不释放

跑批过程中,出现MogDB动态内存不足,导致空间不可用,发现空闲连接占用动态资源占比很大,高达24G多,active_totalsize才2G,是不是数据库那些参数没设置导致,空闲连接资源不释放?求助大佬,相同的应用代码在自己搭建的MogDB则没有出现内存不可用问题

答案内容由AI生成,仅供参考:

:white_check_mark: 总结

问题 原因 解决方案
idle 占用内存达 24G 长连接堆积 + 缓存不释放 设置 idle_session_timeout
内存不释放 local_syscache_threshold 未限制 设置缓存上限
动态内存不足 多会话累积超过系统容量 优化连接池、限制并发
环境差异 生产 vs 自建配置不同 统一连接管理策略
点击此处查看详细分析解答

MogDB/openGauss 动态内存不足与 idle 连接内存不释放问题分析

根据您提出的问题,MogDB/openGauss 在运行批处理任务时出现动态内存不足,且观察到 idle 状态连接占用的动态资源高达 24G,而 active 连接仅占 2G。这表明大量空闲连接(idle)未及时释放其占用的内存资源,进而导致系统整体可用内存紧张甚至不可用。

以下将结合知识库中的相关信息进行综合分析,并提供解决方案。


:magnifying_glass_tilted_left: 问题核心:idle 连接为何占用大量内存且不释放?

在 openGauss/MogDB 中,每个会话(session)在建立时都会分配一定的内存上下文(Memory Context),用于执行期间的各种操作。即使会话处于 idle 状态(无活跃 SQL 执行),其已分配的内存并不会自动立即释放,这是数据库行为的默认机制,尤其是当:

  • 会话内执行过复杂查询、大结果集操作或使用了临时表;
  • 客户端保持长连接但未主动清理会话资源;
  • 缓存机制未触发清理。

:pushpin: 关键线索:您提到“相同的应用代码在自己搭建的 MogDB 上没有该问题”,说明可能是生产环境和测试环境的配置参数、负载模式或连接管理方式不同所致。


:puzzle_piece: 可能原因分析

1. 连接池配置不当导致长连接堆积

应用若使用连接池(如 HikariCP、Druid 等),若配置最大连接数过高、连接空闲超时(idle_timeout)设置过长或未启用连接测试机制,则可能大量连接保持 open 状态但长时间未使用,形成“僵死”的 idle 会话。

  • 这些 idle 会话仍持有内存资源(如 local syscache、临时内存等),即使无活跃 SQL
  • 您提到 idle_totalsize 高达 24G,说明这种累积效应非常严重。

2. 缺少合理的超时控制机制

Database加固实战指南 中提到了:

超时控制 是配置连接超时以防止空闲或卡住的连接占用系统资源。

缺少如下超时设置可能导致问题:

  • idle_in_transaction_session_timeout:事务中空闲超时,避免事务一直不提交。
  • statement_timeout:SQL 执行超时。
  • idle_session_timeout:会话空闲超时,强制断开长时间 idle 的会话。

:white_check_mark: 建议设置

-- 设置会话空闲 30 分钟后自动断开
ALTER SYSTEM SET idle_session_timeout = '30min';

-- 设置事务中空闲 10 分钟即终止
ALTER SYSTEM SET idle_in_transaction_session_timeout = '10min';

3. 本地系统缓存不释放:local_syscache_threshold 参数

在 MogDB/openGauss 中,每个会话维护一份本地系统缓存(local syscache),用于加速元数据访问。如果此缓存未设置上限或未及时清理,会长期占用内存。

您可检查参数:

SHOW local_syscache_threshold;
  • 默认为 -1 表示不限制,可能造成缓存堆积。
  • 建议设置合理阈值(如 10MB),使缓存能自动清理。

:white_check_mark: 建议调整

ALTER SYSTEM SET local_syscache_threshold = '10MB';

4. max_dynamic_memory 设置是否合理?

从日志可见:

Set max backend reserve memory is: 348 MB, max dynamic memory is: 8121 MB

这表示单实例最大动态内存为 约 8GB。而您反馈 idle 占用已达 24GB,远超 max_dynamic_memory

:warning: 矛盾点:理论上动态内存不能超过 max_dynamic_memory 的限制。

可能解释:

  • 您的数据来源是 gs_session_memory_detail,其中统计的可能是 所有会话内存总和,包括非动态内存(如共享内存、本地缓存等);
  • 或您所查看的是多个节点的汇总数据(集群部署);
  • max_dynamic_memory 被后续修改过。

:backhand_index_pointing_right: 建议检查当前实际内存参数

SHOW max_process_memory;
SHOW max_dynamic_memory;
SHOW shared_buffers;

同时查看动态内存使用情况:

-- 查看动态内存使用
SELECT * FROM gs_total_memory_detail WHERE type = 'dynamic';

5. 应用层未正确关闭连接

您提到“相同代码在自建环境无此问题”,说明应用层行为一致,但环境差异是主因

可能原因:

对比项 生产环境 自建环境
连接池最大连接数 高(如 200+) 低(如 20)
idle_timeout 未设置或很长 较短
应用重启频率 频繁
是否有连接泄漏

:magnifying_glass_tilted_right: 建议使用 pg_stat_activity 分析 idle 连接来源:

SELECT client_addr, count(*) 
FROM pg_stat_activity 
WHERE state = 'idle' 
GROUP BY client_addr 
ORDER BY count(*) DESC;

定位客户端 IP 后,进一步排查应用配置。


:white_check_mark: 排查与解决建议

:magnifying_glass_tilted_right: 步骤 1:查看当前内存分布

-- 查看各状态会话占用内存
SELECT state, pg_size_pretty(SUM(totalsize)) AS total_memory
FROM gs_session_memory_detail s, pg_stat_activity a
WHERE substring_inner(sessid, position('.' in sessid) + 1) = a.sessionid
GROUP BY state
ORDER BY SUM(totalsize) DESC;

:magnifying_glass_tilted_right: 步骤 2:找出高内存占用的会话

-- 查看 top 10 内存占用会话
SELECT 
  sessid, 
  a.usename, 
  a.client_addr, 
  pg_size_pretty(SUM(totalsize)) AS total,
  query 
FROM gs_session_memory_detail s, pg_stat_activity a
WHERE substring_inner(sessid, position('.' in sessid) + 1) = a.sessionid
GROUP BY sessid, a.usename, a.client_addr, query
ORDER BY SUM(totalsize) DESC 
LIMIT 10;

:magnifying_glass_tilted_right: 步骤 3:设置超时策略(强制释放 idle 资源)

-- 设置全局会话空闲超时(推荐 30min)
ALTER SYSTEM SET idle_session_timeout = '1800s';

-- 设置事务中空闲超时(推荐 10min)
ALTER SYSTEM SET idle_in_transaction_session_timeout = '600s';

-- 设置单条语句超时(防慢 SQL 占用)
ALTER SYSTEM SET statement_timeout = '300s';

修改后需重启数据库或执行:

SELECT pg_reload_conf();

:magnifying_glass_tilted_right: 步骤 4:优化 local_syscache_threshold

-- 限制每个会话本地缓存大小
ALTER SYSTEM SET local_syscache_threshold = '10MB';

:magnifying_glass_tilted_right: 步骤 5:应用端优化连接管理

  • 启用连接池的 testOnBorrow / validationQuery 确保连接可用;
  • 设置合理的 maxIdleminEvictableIdleTimeMillis
  • 确保业务逻辑中 Connection.close() 被正确调用;
  • 定期重启应用,释放累积内存。

:hammer_and_wrench: 其他监控建议

-- 实时监控动态内存使用
SELECT 
  used_memory / 1024 / 1024 AS used_mb, 
  max_memory / 1024 / 1024 AS max_mb
FROM gs_dynamic_memory_pool();

used_memory 接近 max_memory,则可能发生 OOM。


:white_check_mark: 总结

问题 原因 解决方案
idle 占用内存达 24G 长连接堆积 + 缓存不释放 设置 idle_session_timeout
内存不释放 local_syscache_threshold 未限制 设置缓存上限
动态内存不足 多会话累积超过系统容量 优化连接池、限制并发
环境差异 生产 vs 自建配置不同 统一连接管理策略

:books: 参考资料

  • MogDB/openGauss 故障排查流程:提出动态内存不足时应检查 max_dynamic_memorydynamic_used_memory
  • Database加固实战指南:推荐配置超时控制防止资源泄露。
  • 知识图谱实体 dbe_perf.statement_complex_runtime 中的 memory_skew_percent 字段可用于分析内存倾斜。

如上述配置调整后仍存在问题,请提供:

  1. gs_om -t status --detail 输出;
  2. SHOW max_dynamic_memory, max_process_memory 结果;
  3. pg_stat_activity 中 idle 连接数及来源 IP;
    以便进一步定位是否为集群或参数配置问题。

请问你用的是哪个版本

MogDB 5.0.10 build ea11cc2e

可以查一下内存上下文,看哪一部分占用得多:

select contextname,count(*) context_cnt,pg_size_pretty(sum(totalsize)::numeric(100,0)) total_size,pg_size_pretty(sum(freesize)::numeric(100,0)) free_size,pg_size_pretty(sum(usedsize)::numeric(100,0)) used_size from gs_shared_memory_detail group by contextname order by sum(totalsize) desc limit 10;