这条路径解决什么
应用报 500 或者响应变慢时,线索往往分散在四层:应用自身日志、服务管理层的启动与重启记录、系统层的全局日志、内核层的硬件与 OOM 事件。有效的方法是用同一个时间窗加同一个实体(PID、文件名、端口、容器 ID)把四层证据串起来,而不是在四层里各翻一遍。
基本信息
| 适用场景 | 应用报错、进程被杀、请求变慢需要跨层定位 |
|---|---|
| 四层 | 应用日志 → 服务管理(systemd/journal)→ 系统层(journal 全局)→ 内核层(dmesg) |
| 串联方法 | 先取时间点与关键实体,再用同一条件逐层回溯 |
| 常用实体 | PID、文件名、端口、容器 ID、请求 ID |
| 时间对齐 | dmesg 用 -T 转可读时间,容器内 PID 要换算成宿主 PID |
典型使用场景
- 应用进程莫名重启:服务层与内核层对照,区分是被 OOM 杀还是自己崩
- 请求偶发变慢:应用日志定位时间点,系统层看同期是否有高负载或 IO 异常
- 连接被拒:应用日志报错时间点与系统层防火墙、内核丢包日志对齐
- 磁盘相关报错:应用报写失败,内核层常有 IO error 的原始记录
- 内核参数事故:某次重启后才出问题,diff 启动参数与 dmesg 提示
第 1 层:应用日志
第 1 层:应用日志
tail -n 100 /var/log/app/app.log # 最近现场
grep -n 'ERROR' /var/log/app/app.log | tail -n 20 # 定位报错行号与时间
awk '/2026-10-13 02:1[0-9]/' /var/log/app/app.log | head -n 30 # 锁定时间窗服务与 journal
服务与 journal
systemctl status myapp --no-pager | head -n 15 # 是否重启过、退出码
journalctl -u myapp --since '15 min ago' --no-pager | tail -n 40
systemctl show myapp -p NRestarts -p ExecMainStatus # 重启次数与退出状态系统与内核层
系统与内核层
journalctl --since '15 min ago' -p warning --no-pager | tail -n 30
sudo dmesg -T | tail -n 30 # OOM、磁盘错误、网卡异常
sudo dmesg -T | grep -Ei 'oom|i/o error|segfault' | tail
journalctl -k --since '15 min ago' --no-pager # 内核消息的另一入口四层各查什么
| 层 | 典型问题 | 常用命令 |
|---|---|---|
| 应用层 | 业务报错、异常堆栈、请求耗时 | 应用日志文件加 grep 与时间窗 |
| 服务层 | 是否重启、退出码、启动失败原因 | systemctl status 与 journalctl -u |
| 系统层 | 同期的全局告警、认证与资源事件 | journalctl -p warning 加时间窗 |
| 内核层 | OOM、IO 错误、段错误、驱动异常 | dmesg -T 与 journalctl -k |
串联技巧:先拿到应用的 PID 与精确时间点,再用 journalctl 的字段过滤精确回溯,例如 _PID=12345 或 --since 与 --until 卡时间窗,避免全量翻日志。拿到 PID 后还能顺着它找到 cgroup、启动方式与所属单元。
容器里看到的 PID 是命名空间内的编号,与宿主 PID 不同:用 docker top 或宿主上的 ps 先取宿主 PID,再拿它去查 journal 与 dmesg,否则会查不到任何记录。另外 journald 是否持久化取决于配置,若 /var/log/journal 不存在,重启后日志就没了,排查前先确认这点。