6.3 日志体系与故障排查 本节摘要:日志是流水线的行车记录仪——事故复盘、性能分析、安全审计全靠它。本节讲访问日志的字段精讲与自定义格式(重点是把"耗时"记进去,让日志能回答性能问题)、错误日志的级别与阅读方法、日志轮转策略,最后交付一张覆盖第 1 章全部旅程站点的故障排查路线图:从"用户说打不开"到"定位到具体配置行"的系统化路径。 学习目标 阅读完本节,你应当能够: 设计一个含耗时与上游信息的自定义日志格式; 按错误日志级别分层响应:哪些要立刻处理、哪些可延后; 配置日志轮转并理解不轮转的后果; 按路线图把"现象"翻译成"站点",再落到"配置行"。 访问日志:让每条记录能回答问题 默认的 combined 格式记了时间、IP、请求、状态、字节数、来源页、浏览器标识。
本节摘要:日志是流水线的行车记录仪——事故复盘、性能分析、安全审计全靠它。本节讲访问日志的字段精讲与自定义格式(重点是把"耗时"记进去,让日志能回答性能问题)、错误日志的级别与阅读方法、日志轮转策略,最后交付一张覆盖第 1 章全部旅程站点的故障排查路线图:从"用户说打不开"到"定位到具体配置行"的系统化路径。
阅读完本节,你应当能够:
默认的 combined 格式记了时间、IP、请求、状态、字节数、来源页、浏览器标识。它够回答"谁来了、要什么、结果如何",但回答不了性能问题——因为缺一个关键字段:这次请求花了多久。
自定义格式(mod_log_config)把耗时与后端信息加进来:
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" \ %Dus %{X-Cache}o %T" perflog CustomLog ${APACHE_LOG_DIR}/example-access.log perflog
两个耗时字段:%D 微秒、%T 秒。%{X-Cache}o 顺手把第 5 章的缓存命中标记记下来——于是这条日志能同时回答"多慢"和"是否吃了缓存"。代理场景再加 %{BALANCER_WORKER_ROUTE}e 记录命中的后端成员,排查"某台后端拖后腿"时直接在日志里分组统计。
读日志的基本功是字段过滤与聚合。最慢的一批请求是谁:
# 按耗时倒序取前 20(字段位置按自己的格式调整) awk '{print $NF, $7}' access.log | sort -rn | head -20 # 某 URL 的延迟分布 grep "/api/orders" access.log | awk '{print $(NF-2)}' | sort -n | awk ' {a[NR]=$1} END {print "p50:", a[int(NR*0.5)], "p95:", a[int(NR*0.95)]}'
这两条命令产出的信息量,超过多数花哨的监控面板——前提是日志里有耗时字段。
错误日志按严重级别记录,处置纪律分三档:
emerg/alert:服务器已死或濒死(配错启动失败、磁盘满)。半夜叫醒级别。
error:单请求失败(段错误、模块异常、后端连接失败)。需要盯趋势:偶发可排查后置,突增立刻处理——特别是伴随 5xx 率上升时。
warn/notice/info/debug:上下文信息(子进程退出、优雅重启、模块提示)。不需要逐条读,但排查时是背景材料。
调级别看两层:全局 LogLevel warn 是生产基线;排障时按模块定向开高——第 3 章的 rewrite:trace3 就是范例,只放大重写模块,不放大全机。info 以上长期开着是日志洪水,既费磁盘又把真正重要的条目淹没。
错误日志阅读的一条高价值模式是时间线对照:把访问日志的异常时间戳与错误日志对齐——"08:31:07 的 502 集群"对应错误日志同一秒的"connection refused to backend",这种配对能直接命中根因,比看单边日志快得多。
日志无限增长,结局是磁盘写满——而磁盘满会让 httpd 连日志都写不进,服务以最不体面的方式罢工。轮转交给系统工具(logrotate 家族):
轮转配置错误的症状很有辨识度:切割后新文件存在但大小为零、磁盘空间不降——八成是没通知 httpd 重新打开文件。
⚠️ 常见坑:多站点共用一份日志。第 3 章强调过每站独立日志,这里补一刀理由:排错时你要的是"这个站的时间线",混写的日志每次都要先过滤再分析,事故现场多等一分钟就多一分钟焦灼。
把第 1 章旅程图的"站点"与排错动作对应起来,就是完整路线图:
症状:完全打不开(连接拒绝/超时)。 旅程第一站之前的问题。查:服务进程在吗(systemctl status)、端口在听吗(ss -tlnp)、防火墙与安全组放行了吗。本地 curl 通而外部不通,问题在网络层;本地也不通,问题在服务层。
症状:403。 控制区拦截。查目录权限(运行用户能否读)、IP 拒绝规则、无索引且禁列表、第 6.1 节的默认拒绝规则误伤。错误日志通常直书"client denied by server configuration"并给出匹配的配置段。
症状:404。 映射阶段失配。查文档根、重写规则的实际效果(rewrite:trace3)、别名配置。注意区分"资源真不存在"与"规则改错了路"——前者错误日志安静,后者能看到重写轨迹。
症状:500。 生成阶段内部错误。配置在运行期爆雷或模块崩溃。错误日志是唯一线索来源,第一时间看。
症状:502/504。 代理阶段后端问题。第 4 章的三板斧:直连后端、均衡器状态页、两侧日志时间线对照。
症状:慢但能打开。 性能问题不是故障问题,转第 6.2 节方法论:日志耗时字段分组,找慢的路径与时段规律。

日志的终极价值不在排错那一刻,而在日常积累出的"画像":延迟分位的日曲线告诉你性能何时开始劣化;爬虫与攻击源的占比帮你调限频策略;缓存命中率(X-Cache 统计)验证第 5 章策略的实际效果。把本节的自定义格式落地后,每周花十分钟跑几条聚合命令,你对这台服务器的了解会超过任何一次临时排查。
💡 一句话记住本节:访问日志告诉你"哪一站出的血",错误日志常常直接给出"哪一行的伤口"。
最后一节,把全书拼装成一台真正的生产服务器。