Skip to content

日志与排故 ​

日志是服务器运行的"黑匣子"。没看日志就动手修 = 蒙眼做手术。本篇覆盖日志体系、journalctl 进阶和一套经过验证的排故方法论。

日志文件位置 ​

bash
# Debian/Ubuntu
/var/log/syslog           # 系统主日志(非内核)
/var/log/auth.log         # 认证日志(sudo、ssh 登录)
/var/log/kern.log         # 内核日志
/var/log/dpkg.log         # 包管理日志
/var/log/apt/             # APT 详细日志
/var/log/nginx/           # Nginx 日志(需单独安装)

# RHEL/Rocky/Alma
/var/log/messages         # 系统主日志
/var/log/secure           # 认证日志
/var/log/cron             # 定时任务日志
/var/log/yum.log          # 包管理日志

# 通用
/var/log/boot.log         # 启动日志
/var/log/dmesg            # 内核环缓冲日志
dmesg                     # 查看内核消息(实时)
dmesg -T                  # 带人类可读时间戳
dmesg | tail -50          # 最新 50 条

journalctl 进阶 ​

按时间段 ​

bash
journalctl --since "2026-07-26 10:00:00"
journalctl --since "2026-07-26 10:00" --until "2026-07-26 12:00"
journalctl --since "1 hour ago"
journalctl --since "2 days ago"
journalctl --since today

按服务 ​

bash
journalctl -u nginx
journalctl -u nginx -u postgresql           # 同时查看多个
journalctl _SYSTEMD_UNIT=nginx.service      # 等价 -u nginx

按优先级 ​

优先级从低到高:debug(7) → info(6) → notice(5) → warning(4) → err(3) → crit(2) → alert(1) → emerg(0)

bash
journalctl -p err        # emerg, alert, crit, err
journalctl -p warning    # 包括 warning 及以上的
journalctl -p 3          # 数字等价 err

高级过滤 ​

bash
# 按用户
journalctl _UID=1000

# 按可执行文件
journalctl _EXE=/usr/bin/sshd

# 按内核设备
journalctl _KERNEL_DEVICE=+usb

# 组合 + JSON 输出(方便程序处理)
journalctl -u nginx -p err --since "1 hour ago" -o json-pretty

# 查看磁盘用量
journalctl --disk-usage

日志持久化

默认 journald 只把日志存内存(/run/log/journal),重启就没了。改为持久化:

bash
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald

排故方法论 ​

核心原则 ​

  1. 一条链路查到底:从用户请求 → 网络 → 服务 → 数据库,按数据流方向排查
  2. 一次只改一处:改完验证,确认有效再改下一个。别一次改三个配置,然后不知道哪个起作用了
  3. 先看日志再操作:出问题时第一反应不是重启,而是 tail -100 看日志
  4. 记录变更:改了什么、为什么改。自己能回溯,别人能接手

排故流程 ​

1. 明确症状 → "哪个服务/功能的什么表现不正常?"
2. 缩小范围 → 最近改过什么?什么时间开始的?
3. 检查日志 → journalctl -u xxx -p err --since "当时"
4. 复现问题 → 能稳定复现才说明找到了根因
5. 验证修复 → 修完测试,确认症状消失且没引入新问题
6. 复盘记录 → 写原因+排查过程+修复方案,下次更快定位

实战案例 ​

logrotate 日志轮转 ​

日志不轮转会撑爆磁盘。logrotate 是标准方案:

bash
# 查看系统级 logrotate 配置
cat /etc/logrotate.conf

# 各应用独立的轮转规则
ls /etc/logrotate.d/
cat /etc/logrotate.d/nginx

自定义轮转规则 /etc/logrotate.d/myapp:

/var/log/myapp/*.log {
    daily                   # 每天轮转
    rotate 30               # 保留 30 个副本
    compress                # 压缩旧日志
    delaycompress           # 延迟一天压缩(当前轮出的不压,方便查看)
    missingok               # 日志文件不存在不报错
    notifempty              # 空文件不轮转
    create 640 myapp myapp  # 轮转后创建新文件,设权限
    sharedscripts
    postrotate
        systemctl reload myapp > /dev/null 2>&1 || true
    endscript
}
bash
# 手动测试轮转(-f 强制执行)
sudo logrotate -f /etc/logrotate.d/myapp

# 测试但不执行(-d debug 模式)
sudo logrotate -d /etc/logrotate.d/myapp

案例 1:服务起不来怎么查 ​

bash
# 症状:systemctl start myapp 失败

# 1. 看状态 + 最近日志
systemctl status myapp
# 输出通常包含退出码和最后几行日志

# 2. 查完整启动日志
journalctl -u myapp --since "2 min ago" -e
# -e 跳到末尾

# 3. 手动运行启动命令(模拟 systemd 环境)
# 注意:用服务的 User 身份运行
sudo -u myapp /opt/myapp/venv/bin/gunicorn app:app
# 这一步通常能直接看到错误信息

# 4. 常见原因排行榜:
# 第1名:配置文件路径不对/文件不存在(Permission denied/No such file)
# 第2名:端口已被占用(Address already in use)
# 第3名:环境变量缺失(数据库连接失败)
# 第4名:依赖服务没启动(Redis/PostgreSQL 连接超时)

案例 2:磁盘满了定位 ​

bash
# 1. 确认哪个分区满了
df -h

# 2. 找大目录(从根开始)
sudo du -sh /* 2>/dev/null | sort -hr | head -10

# 3. 通常是这几个地方:
# /var/log      → 日志没轮转
sudo du -sh /var/log/* | sort -hr | head -5

# /tmp          → 临时文件堆积
sudo du -sh /tmp/* | sort -hr | head -5

# Docker overlay → 镜像/容器/volumes 太多
docker system df
docker system prune -a    # 清理无用镜像和容器

# 4. 找大文件
sudo find / -type f -size +500M -exec ls -lh {} \; 2>/dev/null | awk '{print $NF": "$5}' | sort -k2 -hr

# 5. 如果删除了文件但磁盘没释放
# 原因:进程还持有文件句柄
sudo lsof | grep deleted
# 重启对应的进程即可释放

案例 3:网站 502 Bad Gateway 排查 ​

bash
# 502 = 上游服务(应用/PHP-FPM)没响应

# 1. 查 Nginx 错误日志
tail -100 /var/log/nginx/error.log

# 2. 检查上游服务是否在运行
systemctl status php8.1-fpm     # 或你的应用服务

# 3. 检查上游端口是否监听
ss -tlnp | grep :9000           # PHP-FPM 默认端口
ss -tlnp | grep :8000           # Gunicorn/Node 常用端口

# 4. 查看上游错误日志
journalctl -u php8.1-fpm -f
# 或应用日志

# 5. 检查系统资源(OOM 导致进程被杀?)
dmesg | grep -i "out of memory"
journalctl -k | grep -i oom

# 6. 确认连接数没打满
ss -tan | grep :80 | awk '{print $1}' | sort | uniq -c
# 大量 SYN_RECV → 可能被 SYN flood
# 大量 TIME_WAIT → 短连接太多

生产环境经验 ​

  • 集中日志:生产服务器不要各看各的,上 ELK/Loki/Graylog
  • 日志轮转:用 logrotate 定期压缩/删除旧日志,别让日志撑爆磁盘
  • 时间同步:所有服务器 NTP 同步,否则跨服务器日志时间线对不上
  • 关键日志告警:error 日志出现关键词(OOM、segfault、connection refused)自动告警
  • 排故心态:不要猜,用数据和日志说话。不要慌,越急越容易误操作

🎯 本章要点 ​

  • journalctl --since "2 days ago" 按时间筛选系统日志
  • 认证日志在 /var/log/auth.log(sudo、SSH 登录记录)
  • 排故原则:先看日志、逐层排查、一次只改一处
加载练习题中...