注册
达梦实例"夜间反复崩溃"根因分析方法
专栏/技术分享/ 文章详情 /

达梦实例"夜间反复崩溃"根因分析方法

文橘本可 2026/09/18 224 0 0
摘要

适用对象:DM 实例出现"隔一段时间崩一次"“日志戛然而止”“凌晨固定时间挂”,含内核 OOM 与达梦自 halt 两种死法


一、先建立认知:达梦"崩溃"只有两条路径

排查前先给死亡方式分类,两类死法的取证方向完全不同:

死亡方式 日志特征 谁杀的 取证重点
A. 静默死亡 日志戛然而止,无任何 ERROR/FATAL Linux 内核 OOM killer(SIGKILL,不可捕获) 内核日志 /var/log/messages、journalctl -k
B. 自报崩溃 日志写满 [FATAL],并生成 dmhalt_*.dump 达梦自身内存分配失败 → dm_sys_halt 达梦日志 FATAL 块 + dmhalt dump

关键结论(本案例):两类死法同源 —— 主机物理内存 + swap 被同时打满,达梦是"最大的住户",不是"原因"。


二、总体思路:从"死法"倒推"谁把内存吃光"

现象
   ↓ ① 分类死法:有无 FATAL?有无 dmhalt?
   ↓ ② DB 侧:最后一条日志是什么?前后有无线程风暴?
   ↓ ③ 内核侧:OOM 记录是否与 DB 日志同秒?Kill 了谁?score 多少?
   ↓ ④ 内存账:物理内存多大?swap 用了多少?谁占最多(anon-rss)?
   ↓ ⑤ 配额墙:ulimit / cgroup / systemd 是否设了限制?(常见误判方向)
   ↓ ⑥ 触发器:谁在固定时间制造压力?(crontab / 定时任务 / 同步工具)
   ↓ ⑦ 结论:容量问题 or 调度问题 or 二者叠加

时序对齐是第一原则:内核日志时间戳与达梦日志时间戳必须能对上。若 dmesg -T 与 messages 偏移,以 messages/journalctl 为准。


三、七个入手方向

# 方向 要回答的问题 关键命令/文件
1 死法分类 有没有 FATAL / dmhalt? tail、grep FATAL、ls dmhalt_*
2 崩溃时刻的 DB 现场 崩前几秒发生了什么? sed -n 'X,Yp' 定位崩溃前 N 行
3 线程/连接风暴 是否突发大量连接? grep dthrd_info_add
4 内核 OOM 谁触发、杀了谁、score? journalctl -k、awk '/oom-killer/,/reaped/'
5 内存账 物理/swap 余量、内存大户 free -h、swapon --show、ps aux --sort=-%mem
6 配额墙排除 是否进程级限制? /proc/$PID/limits、cgroup、ulimit -a
7 定时触发源 为什么总在凌晨同一时刻? crontab -l、/etc/cron.d/、systemctl list-timers、任务脚本

四、语句/命令库

4.1 达梦侧:崩溃现场

# 进程最后几条日志(判断"有声/无声"死亡) tail -5 /soft/dmdbms/log/dm_DMSERVER_202609.log tail -20 /soft/dmdbms/log/dm_DMSERVER_*.log # 事件1:FATAL 块 sed -n '18580,18601p' /soft/dmdbms/log/dm_DMSERVER_1_202609.log # 崩溃前 16 秒现场 sed -n '202300,202313p' /soft/dmdbms/log/dm_DMSERVER_202609.log # dmhalt 崩溃转储(自 halt 才有) ls -l /soft/dmdbms/log/dmhalt_* cat /soft/dmdbms/log/dmhalt_DMSERVER_1_24613_202609005_021027.dump # 线程风暴量化:看线程号跳变速度 grep "dthrd_info_add" /soft/dmdbms/log/dm_*.log | tail -30

4.2 内核侧:OOM 证据

dmesg -T | grep -iE "oom|killed process|reaped" journalctl -k --since "2026-09-05 01:20" --until "2026-09-05 01:35" | grep -iE "oom|killed" # 完整 OOM 段(从触发者到 reaper 回收目标进程) awk '/dm_sql_thd invoked oom-killer/,/oom_reaper: reaped process 16254/' /var/log/messages \ | grep -A15 "Killed process" # 内存耗尽细节(swap 是否为 0、物理内存多大) awk '/dm_sql_thd invoked oom-killer/,/oom_reaper: reaped process 16254/' /var/log/messages \ | grep -E "Free swap|Total swap|Mem-Info" # 崩溃瞬间"谁在吃内存"(Tasks 表 = 内存大户排行) awk '/oom-killer/,/oom_reaper: reaped process/' /var/log/messages | grep -A60 "Tasks state"

4.3 内存账与进程归属

free -h swapon --show ps aux --sort=-%mem | head -15 ps -eo pid,ppid,rss,comm --sort=-rss | head -20

4.4 排除"配额墙"

PID=$(pgrep -x dmserver | head -1); cat /proc/$PID/limits cat /sys/fs/cgroup/memory/*/memory.limit_in_bytes systemctl cat DmServiceDMSERVER_1 | grep -iE "limit|memory" su - dmdba -c 'ulimit -a'

判读:出现 Max address space unlimited / cgroup limit ≈ 无限制 / systemd 无 MemoryMax → 不存在可调的"内存墙",调 ulimit 无效,问题在整机内存总量。

4.5 定时触发源审计

crontab -l # root crontab -l -u dmdba ls /etc/cron.d/; systemctl list-timers cat /soft/D3/YD03.sh # 看有没有 for 循环 + 行尾 & 并发 grep -n "&" /soft/D3/YD03.sh # 并发点最常见的写法

达梦侧定时作业(需 SYSDBA):

SELECT * FROM SYSJOB.SYSJOBS; -- 若报 -2103 无效模式名,说明库未建作业系统,任务在应用侧

4.6 时间复核(怀疑时钟偏移时)

date; timedatectl; date -r /soft/dmdbms/log/dmhalt_*.dump

五、分步处置流程(Step by Step)

Step 1:先分类死法

  • tail -5 看最后一条:有明显 FATAL → 路径 B(自 halt);戛然而止无报错 → 路径 A(内核 OOM)。
  • ls /soft/dmdbms/log/dmhalt_*:有 dump 说明是路径 B。

Step 2:路径 A → 直接查内核

  • 在 /var/log/messages 或 journalctl -k 里按崩溃时刻 ±5 分钟搜 oom|Killed process。
  • 记录三件事:谁触发(XXX invoked oom-killer)、杀了谁(Killed process <pid> (dmserver) score N)、触发者身份(本例 dm_sql_thd 是达梦连接线程、AWT-XAWT 是 Java 图形线程 → 直指 DataX JVM)。
  • 读 Mem-Info:Free swap = 0kB、物理内存大小 → 确认"整机耗尽"而非"进程超限"。

Step 3:路径 B → 读 FATAL 记录

  • FATAL 块通常是三连击:
    mem_malloc_ex2(2097208) out of memory!, fail to allocate memory from OS.
    [for dem]SYSTEM SHUTDOWN ABORT.
    pthread_create error in os_thread_create with errno 11
    code = -1, dm_sys_halt now!!!
    
  • 判读要点:连 2MB 都 malloc 失败 → 进程此刻已无任何可用内存/swap(不是撞配额墙,见 Step 5)。

Step 4:看"崩前几秒"在忙什么

  • grep dthrd_info_add 看线程创建节奏:本例 16 秒新建约 5000 线程(T4517 → T9531)→ 典型连接风暴。
  • 连接风暴的来源通常不是数据库自己,而是外部批量任务(同步工具、并发脚本)。

Step 5:排除配额墙

  • cat /proc/<dmserver>/limits + cgroup + systemd 一起看,确认无 MemoryMax。
  • 这一步能省掉大量"调参数"的无效工作。

Step 6:找"固定时间"的触发器

  • 崩溃集中在 01:30~02:10 → 必然有定时任务。查 crontab、/etc/cron.d/、systemctl list-timers。
  • 打开脚本看并发写法:循环内行尾 & = 一次性并发拉起 N 个任务(本例 YD03.sh 约 150 张表 → 150 个 DataX JVM)。
  • 交叉印证:DataX 每个任务 = 一个独立 JVM,任务表里 40+ 个 java 进程(各 rss≈150MB)↔ 崩溃瞬间内存大户。

Step 7:做内存账,给人看

  • 物理内存 + swap 总量 vs 常驻负载(几套实例 + 桌面 + GUI)vs 尖峰负载(150 JVM × 100~300MB)。
  • 本例两条硬伤:167 = 31GB 跑 3 套达梦 + 桌面;168 = 仅 8GB 还要叠桌面与调度。

Step 8:解释"白天为什么没超 80%"

  • 尖峰是秒级事件,常规分钟级监控抓不到;
  • swap 全天已占用 2GB,余量本就不健康;
  • 结论要写清"监控看不见尖峰",否则客户会拿白天的 free 反驳你。

Step 9:给处置优先级(先止血、再扩容、后重构)

  1. 改脚本禁并发(最关键):去掉行尾 &,或 xargs -P4 限流 ≤4,或拆时段执行;DataX "speed":{"channel":1},调小 JVM -Xms/-Xmx。
  2. 降频:每 2~5 分钟的同步任务改 15~30 分钟。
  3. 补自动拉起:本例 crontab 引用的 Dm_restart.sh 文件不存在(每天静默失败)→ 改 systemd Restart=on-failure 托管。
  4. 扩容:168 扩到 ≥16GB(建议 32GB)。
  5. 减负:关桌面/X11VNC/GUI,数据库无头化。
  6. 监控:oom-killer|Out of memory 关键字 + 进程存活探活 + swap 水位告警。
  7. 架构:同步改常驻进程 + 连接池,或独立同步服务器,不与数据库同机争内存。
  8. 核对各实例 dm.ini(BUFFER / MAX_SESSIONS)合计内存预算。

六、判读速查表

现象 指向 下一步
日志戛然而止、无任何报错 内核 SIGKILL 查内核 OOM 日志
有 FATAL + dm_sys_halt + dmhalt dump 达梦自 halt 读 FATAL 块与 dump
mem_malloc_ex2(...) out of memory! 连 2MB 都失败 整机内存/swap 耗尽 排除配额墙后查谁吃光
pthread_create ... errno 11 线程创建失败(EAGAIN,也是资源耗尽) 同上
崩前 dthrd_info_add 密度剧增 连接风暴 找外部批量任务
invoked oom-killer 是 java 线程(AWT-XAWT 等) Java 进程群触发 查 DataX/同步工具
Free swap = 0kB swap 耗尽 整机容量问题
/proc/<pid>/limits 全 unlimited 非配额墙 别再调 ulimit
崩溃时间集中在固定时刻 定时任务 审计 crontab 与脚本并发
Dm_restart.sh 不存在 自动拉起从未生效 改 systemd 托管
白天 free 显示很空 尖峰被监控漏掉 用秒级/分钟级采集或历史 sar

七、容易踩的坑

  1. 只查达梦日志就下结论 → 无声死亡(OOM SIGKILL)在达梦日志里什么都不会留,必须查内核。
  2. 把 dmserver 当内存元凶 → 本案 168 上 dmserver 仅 ~300MB(anon-rss 298560kB);要看是谁触发的 OOM。
  3. 拿 ulimit/cgroup 当解释 → 本案实测全 unlimited,调它无效。
  4. 用白天监控数据否定夜间尖峰 → 采样粒度问题,不是没问题。
  5. 忽略 crontab 里"引用了但不存在的脚本" → 这解释了"为什么崩了 55 小时没人发现"。
  6. dmesg -T 时间戳直接采信 → 存在内核时间偏移,需与 messages/journalctl 对齐后再定案。
  7. 把 SIGKILL 当"数据库 bug" → SIGKILL 不可捕获,日志无报错是正常表现,不是产品缺陷。

评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服