Files
baim0-learn/linux/00 小问题记录.md
T
Your Name 3b0f68a42c docs(linux): normalize markdown heading levels in 00 小问题记录
- 每个问题作为一级标题
- 问题内小节 / 操作章节统一为二级标题
- 操作子项、解决步骤统一为三级标题
2026-10-10 11:31:34 +08:00

11 KiB
Raw Blame History

ECS 实例 dmesg 时间与真实时间存在 10 分钟偏差

  • 记录日期:2026-09-24
  • 现象:dmesg -T 显示的时间戳与真实时间相差约 10 分钟(偏慢)。
  • 根因:系统默认时钟源(clocksource)为 tsc,该 TSC 频率偏慢 33.7ppm,累计 220 天 误差约 641 秒(≈ 10.7 分钟),导致系统时钟计数不准、dmesg 时间戳随之偏移。
  • 解决:GRUB 启动参数加入 clocksource=kvm-clock → 重新生成 grub 配置 → 重启实例,使 MONOTONIC 从 kvm-clock 重新起算。

1. 问题描述

ECS 实例 dmesg -T 打印的时间与真实时间(date)存在约 10 分钟偏差,且偏差随运行时长持续累积。内核日志自身的时序(先后顺序)是正确的,但时间戳的绝对刻度不准。

2. 原因分析

  • 内核中存在多个可选时钟源(TSC、kvm-clock、hpet、acpi_pm 等),启动时会按优先级选定一个作为当前时钟源。

  • 本实例默认选中了 tsc(Time Stamp Counter,CPU 内部计数器)。该 CPU 的 TSC 计数频率与标称频率存在偏差,实测偏慢 33.7ppm。

  • ppm = parts per million,1ppm 即百万分之一:

    累计误差 = 33.7e-6 × 220 天 × 86400 秒/天
             = 33.7e-6 × 19,008,000
             ≈ 640.5 秒 ≈ 641 秒 ≈ 10.7 分钟
    
  • 该 TSC 在虚拟化环境下不是可靠的授时基准(可能未与宿主机对齐、或缺少稳定/不变标志),误差会线性累积。

  • dmesg -T 的时间戳由内核 MONOTONIC 时钟换算而来,时钟源偏慢直接反映为 dmesg 时间显示不准。

  • kvm-clock 是 KVM 半虚拟化时钟源,直接读取宿主机提供的时钟信息,在同为虚拟机的 ECS 实例上精度显著更高,应优先使用。

3. 解决方案

步骤 1:修改 GRUB 启动参数

编辑 /etc/default/grub,在 GRUB_CMDLINE_LINUX 中追加 clocksource=kvm-clock,例如:

GRUB_CMDLINE_LINUX="... clocksource=kvm-clock"

也可用命令追加(避免手改出错):

sed -i 's/\(GRUB_CMDLINE_LINUX="[^"]*\)"/\1 clocksource=kvm-clock"/' /etc/default/grub
grep GRUB_CMDLINE_LINUX /etc/default/grub

步骤 2:重新生成 GRUB 配置文件

Alinux 的 grub 配置文件路径为 /boot/efi/EFI/alinux/grub.cfg(UEFI 引导)。

grub2-mkconfig -o /boot/efi/EFI/alinux/grub.cfg

步骤 3:重启实例

reboot

重启的必要性:只有重启后才会以新的启动参数引导,MONOTONIC 从 kvm-clock 重新开始计数,dmesg -T 的时间显示随之恢复正常。

步骤 4:验证

# 当前时钟源,应显示 kvm-clock
cat /sys/devices/system/clocksource/clocksource0/current_clocksource

# 可选时钟源列表,修改前可先确认 kvm-clock 在列
cat /sys/devices/system/clocksource/clocksource0/available_clocksource

# 确认启动参数已生效
cat /proc/cmdline

# 观察 dmesg 时间戳与 date 是否一致
dmesg -T | tail
date

4. 备注

  • 修改后 dmesg 中已有的历史日志时间戳会因 MONOTONIC 重新起算而重新计算,属正常现象。
  • 若实例主要用于对时间精度敏感的场景(如日志审计、分布式追踪),建议同时确认 NTP/chrony 正常同步,二者互补:NTP 校正的是墙上时钟(CLOCK_REALTIME),clocksource 决定的是时基精度。
  • 若 available_clocksource 中无 kvm-clock,说明宿主机/虚拟化环境不支持该时钟源,需改用其他精度更高的时钟源(如 hpet、acpi_pm)并排查宿主机侧问题。

kdump 实战:让 hung_task 与 softlockup 触发 vmcore

0. 总结(TL;DR)

目标是在内核出现 hung_task(进程长期 D 状态不切出)或 softlockup(CPU 上任务长时间不让出)时,自动 panic 并触发 kdump,把现场落到 /var/crash 下的 vmcore,供后续 crash 工具做根因分析。

最短路径:

# 1) 开启并确认 kdump 服务
systemctl enable --now kdump
systemctl status kdump

# 2) 配置两个 panic 开关
echo 'kernel.hung_task_panic=1'  >> /etc/sysctl.conf
echo 'kernel.softlockup_panic=1' >> /etc/sysctl.conf
sysctl -p

# 3) 复现后取证
ls -l /var/crash/
crash /usr/lib/debug/lib/modules/$(uname -r)/vmlinux /var/crash/<时间戳>/vmcore

前提:内核已预留 crashkernel 内存且 kdump 服务处于 active。若 crashkernel 没预留,需要改 GRUB 后重启。


操作一:开启 kdump 服务

1.1 确认内核已预留 crashkernel 内存

kdump 需要一个独立预留的内存区域(capture kernel)来在内核崩溃后接管系统。检查方式:

grep -o 'crashkernel=[^ ]*' /proc/cmdline
cat /sys/kernel/kexec_crash_size    # 非 0 表示已预留
  • 较新发行版通常默认 crashkernel=auto(RHEL/CentOS 7+)或 crashkernel=1G-4G:192M,4G-64G:256M,64G-:512M。
  • 若输出为空或 kexec_crash_size 为 0,需要在 GRUB 里补上,例如:
# /etc/default/grub
GRUB_CMDLINE_LINUX="... crashkernel=512M"

# 重新生成 grub 配置
grub2-mkconfig -o /boot/grub2/grub.cfg   # BIOS
grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg  # UEFI(路径按发行版调整)
# 然后重启

1.2 安装并启动 kdump 服务

# 安装(按发行版)
yum install -y kexec-tools        # RHEL/CentOS
apt install -y kdump-tools       # Debian/Ubuntu

# 开启并立即启动
systemctl enable --now kdump

# 校验
systemctl status kdump
kdumpctl status 2>/dev/null || true

1.3 确认 kdump 就绪

cat /sys/kernel/kexec_crash_loaded   # 期望 1
ls -l /var/crash/                     # 崩溃后 vmcore 落在这里

1.4 关键配置项(/etc/kdump.conf)

配置项 说明
path /var/crash vmcore 落盘目录
core_collector makedumpfile -l --message-level 1 -d 31 用 makedumpfile 压缩、并过滤掉全零页等无用页,显著减小 vmcore 体积
default reboot dump 完成后重启
ext4 /dev/vg/root 等 根分区未挂载时的兜底落盘目标

提示:-d 31 会过滤掉零页、缓存页等,排查时不要用 -d 0(体积巨大),也不建议过滤过多;若怀疑内存内容相关,保留默认即可。


操作二:配置 hung_task 与 softlockup 触发 panic

内核默认检测到 hung_task / softlockup 时只打印告警日志,不会 panic,所以现场不会产生 vmcore。需要打开 panic 开关。

cat >> /etc/sysctl.conf <<'EOF'
kernel.hung_task_panic=1
kernel.softlockup_panic=1
EOF

# 或使用 sysctl.d(推荐,语义更清晰)
# cat > /etc/sysctl.d/99-kdump-panic.conf <<'EOF'
# kernel.hung_task_panic=1
# kernel.softlockup_panic=1
# EOF

2.1 两个开关的含义

参数 含义 默认值
kernel.hung_task_panic 检测到 D 状态(不可中断睡眠)任务超时后,触发 panic 0(只告警)
kernel.softlockup_panic 检测到 softlockup(某 CPU 上任务长时间不调度)后,触发 panic 0(只告警)

2.2 配套可调参数(按需)

kernel.hung_task_timeout_secs = 120   # hung_task 判定超时,默认 120s
kernel.hung_task_warnings     = 10    # 告警打印条数,-1 表示不限
kernel.watchdog_thresh        = 10    # softlockup 检测阈值基数,默认 10s
kernel.nmi_watchdog           = 1     # Hardlockup 依赖 NMI 看门狗
kernel.hardlockup_panic       = 1     # 硬锁(中断被长时间关闭)也 panic,按需
kernel.panic_on_oops          = 1     # Oops 即 panic,按需

2.3 注意事项

  • softlockup 检测依赖 watchdog 线程本身能运行:若 CPU 长时间关中断,属于 hardlockup,需靠 nmi_watchdog + hardlockup_panic 捕获。
  • 部分内核 softlockup_panic 受编译选项约束;若写入失败,可检查 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC,或改用内核启动参数 softlockup_panic=1。
  • hung_task_panic=1 对合法长 D 状态(如大 IO、网络存储挂起)也会 panic,生产环境务必评估影响,建议先在测试环境验证。

操作三:使配置生效

# 方式一:立即加载 sysctl.conf
sysctl -p

# 方式二:只加载某个 sysctl.d 文件
sysctl -p /etc/sysctl.d/99-kdump-panic.conf

# 方式三:重启(持久生效,也是兜底手段)
reboot

3.1 生效校验

sysctl kernel.hung_task_panic kernel.softlockup_panic
# kernel.hung_task_panic = 1
# kernel.softlockup_panic = 1

# kdump 侧确认
systemctl is-active kdump
cat /sys/kernel/kexec_crash_loaded    # 1

建议同时确认 kdump 开机自启:systemctl is-enabled kdump。


操作四:复现后取证与分析

4.1 vmcore 落盘位置

问题复现后,系统会 panic → kexec 启动 capture kernel → 由 kdump 把内存镜像写入:

/var/crash/<时间戳>/vmcore
/var/crash/<时间戳>/vmcore-dmesg.txt
ls -lh /var/crash/
cat /var/crash/<时间戳>/vmcore-dmesg.txt | tail -50   # 先看崩溃瞬间的 dmesg

4.2 用 crash 工具做根因分析

# 安装 debuginfo(以 CentOS 为例)
debuginfo-install kernel-$(uname -r)

# 加载 vmcore
crash /usr/lib/debug/lib/modules/$(uname -r)/vmlinux \
      /var/crash/<时间戳>/vmcore

常用 crash 命令:

命令 用途
bt / bt -a 查看崩溃时各 CPU 的调用栈(hung_task/softlockup 常看这里)
log 崩溃前的内核日志缓冲
ps / foreach bt 进程状态与全量栈,定位 D 状态任务
vm 内存与页状态概览
sys 系统基本信息(版本、panic 原因等)
dis -l <addr> 反汇编定位到源码行

4.3 可选:手动触发一次转储做演练

# 需确认 kernel.sysrq=1 且 kdump 已就绪,演练会重启系统
echo c > /proc/sysrq-trigger

操作五:常见问题排查(Q&A)

  • /var/crash 下没有 vmcore
    • kdump 服务未运行或未开机自启:systemctl is-active kdump / is-enabled。
    • crashkernel 未预留:看 /proc/cmdline 与 /sys/kernel/kexec_crash_size。
    • panic 未触发:确认 hung_task_panic / softlockup_panic 已为 1,且告警类型确实是这两种。
  • 复现了但只看到告警日志、没有 panic
    • 说明只命中了 hung_task/softlockup 告警路径,检查 sysctl 是否被其他配置覆盖(sysctl -a | grep -E 'hung_task|softlockup')。
  • softlockup_panic=1 写入报不存在
    • 内核编译未开放该 sysctl,改用启动参数 softlockup_panic=1,或升级/更换内核。
  • vmcore 特别大,把磁盘写满
    • 确认 core_collector 使用 makedumpfile -d 31 过滤;必要时落盘到独立分区。
  • 生产环境慎用
    • hung_task_panic=1 可能把「可自愈的长 D 状态」也变成宕机,建议先用 hung_task_timeout_secs 调大、并在测试环境验证。