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

305 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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`,例如:
```sh
GRUB_CMDLINE_LINUX="... clocksource=kvm-clock"
```
也可用命令追加(避免手改出错):
```sh
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 引导)。
```sh
grub2-mkconfig -o /boot/efi/EFI/alinux/grub.cfg
```
### 步骤 3:重启实例
```sh
reboot
```
重启的必要性:只有重启后才会以新的启动参数引导,`MONOTONIC` 从 `kvm-clock` **重新开始计数**,`dmesg -T` 的时间显示随之恢复正常。
### 步骤 4:验证
```sh
# 当前时钟源,应显示 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` 工具做根因分析。
最短路径:
```bash
# 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)来在内核崩溃后接管系统。检查方式:
```bash
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 里补上,例如:
```bash
# /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 服务
```bash
# 安装(按发行版)
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 就绪
```bash
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 开关。
```bash
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 配套可调参数(按需)
```bash
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,生产环境务必评估影响,建议先在测试环境验证。
---
## 操作三:使配置生效
```bash
# 方式一:立即加载 sysctl.conf
sysctl -p
# 方式二:只加载某个 sysctl.d 文件
sysctl -p /etc/sysctl.d/99-kdump-panic.conf
# 方式三:重启(持久生效,也是兜底手段)
reboot
```
### 3.1 生效校验
```bash
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
```
```bash
ls -lh /var/crash/
cat /var/crash/<时间戳>/vmcore-dmesg.txt | tail -50 # 先看崩溃瞬间的 dmesg
```
### 4.2 用 crash 工具做根因分析
```bash
# 安装 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 可选:手动触发一次转储做演练
```bash
# 需确认 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` 调大、并在测试环境验证。