达梦数据库容器内存占用排查:为何统计值远超Pod限制却无OOM?
1. 问题背景
某天在Kubernetes上监控达梦数据库容器时,发现了一个令人困惑的现象:
- Pod内存限制为 2GiB
- 通过达梦内部视图查询内存使用,计算出的结果约为 3GB
- 然而监控平台显示内存使用率 87.9%,且并没有发生OOM Kill
这明显存在矛盾:内部统计的内存已经超过了Pod限制,按理说早就该被OOM Killer干掉了,为什么容器还活得好好的?
这促使我对达梦数据库的内存统计口径、容器内存监控指标以及真实物理内存占用进行了一次完整的排查和梳理。
2. 排查过程
2.1 达梦内部内存统计SQL
首先,我通过达梦数据库的两个核心动态视图 V$BUFFERPOOL 和 V$MEM_POOL 来统计内存使用:
SELECT
(SELECT SUM(N_PAGES * PAGE_SIZE) / 1024 / 1024 FROM V$BUFFERPOOL) || 'MB' AS BUFFER_SIZE,
(SELECT SUM(TOTAL_SIZE) / 1024 / 1024 FROM V$MEM_POOL) || 'MB' AS MEM_POOL,
((SELECT SUM(N_PAGES * PAGE_SIZE) FROM V$BUFFERPOOL) +
(SELECT SUM(TOTAL_SIZE) FROM V$MEM_POOL)) / 1024 / 1024 || 'MB' AS TOTAL_SIZE
FROM DUAL;
⚠️ 注意:这里的
PAGE_SIZE是V$BUFFERPOOL视图自带的列,不要误写成PAGE_SIZE()函数,后者在达梦中不存在,或也可以写成SF_GET_PAGE_SIZE()。
查询结果:TOTAL_SIZE ≈ 3093 MB
也就是说,达梦内部认为它管理着约 3GB 的内存。
2.2 容器真实物理内存占用
进入容器,查看cgroup的真实物理内存占用:
cat /sys/fs/cgroup/memory/memory.stat | grep total_rss
结果:
total_rss 1677365248
total_rss_huge 1621098496
换算后:total_rss ≈ 1.56 GiB
这才是我真正关心的数值——进程实际占用的物理内存(RSS)。
2.3 Kubernetes监控平台的指标
查看K8s监控面板:
| 实例 | 角色 | 规格 | 内存使用率 |
|---|---|---|---|
| osier-5b767c847b-dmdb-0 | standby | 1.0C2.0Gi | 76.5% |
| osier-5b767c847b-dmdb-1 | primary | 1.0C2.0Gi | 87.9% |
这个 87.9% 是K8s的 Working Set 指标,计算公式为:
Working Set = total_rss + total_cache(活跃文件缓存)
推算一下:
- Pod限制:2.0 GiB
- 87.9% × 2.0 GiB ≈ 1.758 GiB(Working Set)
- total_rss ≈ 1.56 GiB
- 活跃文件缓存 ≈ 1.758 - 1.56 ≈ 0.198 GiB ≈ 203 MiB
所以,监控平台显示的87.9% = (1.56 GiB RSS + 0.2 GiB 文件缓存) / 2.0 GiB,数据完全对得上。
2.4 为什么没有OOM?
因为 Working Set(1.758 GiB)< Pod限制(2.0 GiB),还有约 240 MiB 的余量。
虽然看起来接近上限,但文件缓存部分是可回收的——当内存紧张时,操作系统会主动释放这部分缓存,所以风险相对较低。
3. 三个内存指标的区别与联系
| 指标 | 数据来源 | 实际含义 | 是否计入OOM判定 |
|---|---|---|---|
| 达梦内部统计(~3GB) | V$BUFFERPOOL + V$MEM_POOL | 逻辑上申请的虚拟内存地址空间,不代表实际物理占用 | ❌ 否 |
| RSS(~1.56GB) | /sys/fs/cgroup/memory/memory.stat | 进程实际占用的物理内存 | ✅ 是 |
| Working Set(~1.76GB) | K8s监控平台 | RSS + 活跃文件缓存,K8s OOM判定的真实依据 | ✅ 是 |
关键结论:
达梦内部统计的内存 ≈ 数据库自己管理的“虚拟地址空间”,不等于容器实际占用的物理内存。
判断是否触发OOM,一定要看 Working Set,或者describe pod有没有oom killer,而不是达梦内部视图的统计值。
4. 达梦内存组成部分解析
达梦数据库的内存主要由以下两部分构成:
🧱 缓冲区(Buffer Pool)
- 作用:数据页的读写缓存,相当于Oracle的Buffer Cache
- 来源:
V$BUFFERPOOL视图 - 关键参数:
BUFFER、RECYCLE、KEEP等
🧠 内存池(Memory Pool)
- 作用:SQL执行、会话管理、排序、哈希等运行时内存
- 来源:
V$MEM_POOL视图 - 关键参数:
MEMORY_POOL、MEMORY_TARGET、MEMORY_N_POOLS等
这两部分的和就是达梦内部统计的内存总量。但它并不等同于进程的RSS,因为操作系统会按需分配物理页,虚拟内存并不一定会全部驻留物理内存。
5. 日常监控建议
基于本次排查经验,建议大家在监控达梦容器时重点关注以下指标:
-
K8s Working Set(最核心)
# 查看Pod内存使用率 kubectl top pod <pod-name> -
容器真实RSS
cat /sys/fs/cgroup/memory/memory.stat | grep total_rss -
达梦内部内存统计(作为参考)
SELECT ... FROM V$BUFFERPOOL, V$MEM_POOL ... -
查看是否发生过OOM
kubectl describe pod <pod-name> | grep -i oom
附文:达梦数据库核心内存参数详解与调优建议
一、核心内存参数一览
达梦数据库的内存管理主要由 dm.ini 配置文件控制,以下是需要重点关注的内存参数:
| 参数名称 | 默认值 | 参数说明 | 调优建议 |
|---|---|---|---|
| BUFFER | 100 MB | 数据缓冲区,缓存磁盘数据页,是最大的内存区域 | 数据量小于内存时设为数据量大小;否则设为总内存的 2/3 左右比较合适 |
| MAX_BUFFER | 100 MB | 数据缓冲区可扩展的最大值 | 建议和 BUFFER 值设置一致(静态参数,改后需重启) |
| MEMORY_POOL | 200 MB | 共享内存池初始大小,数据库启动时向OS申请 | 高并发时应调大,避免频繁向OS申请内存;物理内存较大(如>64G)时可设为2048MB |
| MEMORY_TARGET | 0 MB | 共享内存池扩展上限,0表示不限制 | 建议设置上限,防止内存池无限膨胀 |
| MAX_OS_MEMORY | 95% | 主内存池扩展上限,表示占总内存的百分比 | 建议设为 70-90;若服务器还有其他应用可适当调低。取值范围40-100,低于40会被自动置为40 |
| DICT_BUF_SIZE | 5 MB | 数据字典缓存 | 系统中对象个数较多时适当加大 |
| SORT_BUF_SIZE | 2 MB | 排序缓冲区(会话级) | 大量排序操作时建议调大,有效值范围1-2048MB |
| RECYCLE | 64 MB | 回收缓冲区,缓存被淘汰的数据页 | 高并发或大量使用WITH、临时表、排序时应调大 |
| BUFFER_POOLS | 4 | BUFFER分区数 | 并发较大时应配置,建议为质数,减少数据缓冲区并发冲突 |
参数类型说明:静态参数(SYS)需修改后重启生效;动态参数可在线修改,系统级影响所有会话,会话级仅影响新建会话。
二、参数配置的核心原则
1. BUFFER 是最关键的参数
数据缓冲区是达梦最大的内存区域,直接影响磁盘I/O频率。设置原则:
- 太小 → 缓冲页命中率低,磁盘I/O频繁
- 太大 → 占用过多内存,可能导致操作系统内存不足
2. 会话连接数也是隐性内存消耗
达梦没有直接限制单会话内存的参数,但每个会话都会消耗内存。社区经验值参考:
| 内存大小 | 建议最大连接数 |
|---|---|
| 8G | 50-100 |
| 16G | 100-200 |
| 32G | 200-300 |
| 64G | 300-800 |
| 128G | 800-1500 |
| 256G | 1500-3000 |
| 512G | 3000-5000 |
每个会话的内存消耗与实际执行的SQL密切相关,复杂查询可能单个SQL就占用20MB+。
三、容器环境下的特殊考量
1. 容器内存限制优先
在容器中运行达梦时,必须确保 BUFFER + MEMORY_POOL 等参数总和明显小于容器内存限制,否则极易触发OOM Killer。
2. 操作系统级配置
容器内部需要关注以下内核参数:
vm.swappiness = 10:减少交换倾向vm.overcommit_memory = 0:按正常策略分配内存vm.min_free_kbytes:内存≤32G时可保持默认
3. 多实例场景注意
如果宿主机上运行多个达梦实例,MAX_OS_MEMORY 的配置需特别注意。该参数最小值为40,意味着每个实例至少要预留40%的OS内存,多实例可能导致启动失败。
四、监控组合建议(完整版)
结合正文的排查经验与附文的参数知识,建议在日常监控中关注以下组合指标:
| 监控层级 | 指标/视图 | 用途 |
|---|---|---|
| K8s层 | Working Set(kubectl top pod) | OOM判定依据 |
| 容器层 | total_rss(/sys/fs/cgroup/memory/memory.stat) | 真实物理内存 |
| 达梦统计层 | V$BUFFERPOOL + V$MEM_POOL | 逻辑内存统计 |
| 达梦参数层 | V$PARAMETER 查询核心参数实际值 | 确认配置是否合理 |
查询核心参数的SQL:
SELECT NAME, TYPE, VALUE
FROM V$PARAMETER
WHERE NAME IN (
'BUFFER', 'MAX_BUFFER', 'MEMORY_POOL', 'MEMORY_TARGET',
'MAX_OS_MEMORY', 'DICT_BUF_SIZE', 'SORT_BUF_SIZE', 'RECYCLE'
);
五、总结
- 达梦内部统计的内存 ≠ 容器实际物理内存。判断OOM风险请以Working Set和RSS为准。
- 达梦内存管理以
BUFFER和MEMORY_POOL为核心,配置时需要结合物理内存总量和业务负载。 - 容器环境中必须确保核心参数总和明显小于Pod限制,为文件缓存和会话内存预留空间。
MAX_OS_MEMORY参数取值范围40-100,不能设低于40,多实例场景需格外注意。- 监控要分层,K8s层、容器层、数据库层各司其职,避免单一指标误导判断。
- 会话连接数是隐性内存消耗,高并发场景需合理规划连接池大小。
📚 参考文档与官方链接
以下是本文涉及到的达梦数据库官方文档及相关社区技术文章,供进一步查阅:
| 序号 | 文档/文章名称 | 内容简介 | 来源 |
|---|---|---|---|
| 1 | DM8 系统管理员手册 | 达梦数据库最核心的官方手册,涵盖dm.ini全部参数详解、内存架构、系统视图说明 | 达梦官网(英文版)[-12](https://en.dameng.com/upload/file/20251201/DM8 System Administrator Manual.pdf#112#4) |
| 2 | DM数据库运行参数优化说明 | 详细介绍内存池、数据缓冲区等核心参数的含义与调优建议 | 达梦社区 -1 |
| 3 | 数据库配置中的dm.ini文件和dm_svc.conf文件 | 涵盖dm.ini文件位置、参数分类(静态/动态)、修改方式及最佳实践 | 达梦社区 -3 |
| 4 | DM数据库实例配置与参数管理 | 包含DM实例完整内存架构图及各内存区域参数说明 | 达梦社区 -5 |
| 5 | 数据库参数(官方文档) | 官方参数文档,包含MAX_OS_MEMORY、BUFFER等核心参数的属性与调优建议 | 达梦文档中心 -9 |
| 6 | DM8数据库参数文件及数据库初始化常用参数介绍 | 参数类型(READ ONLY/SYS/SESSION/IN FILE)详解及修改方式说明 | 达梦社区 -10 |
| 7 | 达梦8内存使用情况 | 内存监控SQL合集:总量查询、内存池紧张判断、BUFFER空闲判断 | 达梦社区 -2 |
| 8 | 关于内存调优相关SQL | 内存池与BUFFER使用状态监控SQL,包含N_EXTEND_EXCLUSIVE等关键指标解读 | 达梦社区 -6 |
| 9 | DM8容器化运维:Docker部署DM8数据库 | 容器化部署达梦的完整流程及常见运维问题解决方案 | 达梦社区 -8 |
| 10 | Docker制作达梦数据库单机容器化部署 | Dockerfile编写、静默安装配置及容器启动参数说明 | 达梦社区 -4 |
| 11 | docker部署达梦8.1单库 | Docker部署实操,包含镜像导入、容器启动、进入容器内部等命令示例 | 达梦社区 -11 |
温馨提示:
作者:Rodri
时间:2026年8月
环境:达梦数据库 v8 + Kubernetes 容器化部署
更多推荐


所有评论(0)