TT Lab
开始
学习 学习路径 课程

Tomcat 与 nginx 运维

用日志把故障原因收窄

在 TT Lab 中继续学习

目标

从生产日志(catalina.out、GC 日志、访问日志、nginx 错误日志)中提取依据, 缩小故障原因的范围,并编写带有数字的故障报告。

为什么重要

故障响应中最常见的失败,是遇到 502 却去加大超时。 502 是“收到了无效的响应”,而 504 是“没有在规定时间内响应”。 把二者混为一谈,会浪费好几个小时。此外,OOM 的处理方式因类型(Java heap space / Metaspace / unable to create native thread)而完全不同, 如果不读消息就只是调高 -Xmx,反而可能更糟。 有了从日志中提取数字的本领,这种判断就会从猜测变成依据。

步骤

  1. 创建 /root/ts,并把 /opt/lab/fixtures/tomcat/logs/ 中的四个文件原样复制过来。 (catalina-oom.log、gc.log、access.log、nginx-error.log) 内容必须与原件完全相同。
  2. 在 catalina-oom.log 中找到 OutOfMemoryError,创建 /root/ts/oom.txt。 共两行,格式必须与下面完全一致。
    time=<로그에 적힌 타임스탬프>
    type=<OOM 종류 문자열>
    
    (占位符依次为日志中记录的时间戳、OOM 类型字符串。) type 取 Java heap space / Metaspace / GC overhead limit exceeded / unable to create native thread 之一。
  3. 分析 gc.log,创建 /root/ts/gc.txt。共两行。
    fullgc=<Full GC 발생 횟수>
    maxpause=<가장 긴 정지 시간, 밀리초, 소수점 포함 그대로>
    
    (占位符依次为 Full GC 发生次数、最长停顿时间——单位毫秒,小数点部分原样保留。)
  4. 从 access.log 中提取处理时间最长的前 5 个 URL, 创建 /root/ts/slow.csv。首行为 url,count,max_ms, 按 max_ms 降序排列。
  5. 在 access.log 中按 URL 统计 5xx 响应,创建 /root/ts/5xx.csv。 首行为 url,status,count,按次数降序排列。
  6. 在 nginx-error.log 中按原因统计上游错误, 创建 /root/ts/upstream.csv。首行为 code,cause,count。 code 为 502 或 504,cause 为 connection refused 或 timeout。
  7. 启动 Tomcat,导出线程转储并保存到 /root/ts/threads.txt, 然后创建 /root/ts/threadstat.txt。共两行。
    total=<덤프에 있는 전체 스레드 수>
    waiting=<WAITING 상태 스레드 수>
    
    (占位符依次为转储中的线程总数、处于 WAITING 状态的线程数。) 这两个值必须与 threads.txt 的内容一致。
  8. 编写 /root/ts/rca.md。 必须包含 ## 현상、## 원인、## 조치、## 재발방지 这四个 h2 标题(韩文,依次意为“现象”“原因”“措施”“防止复发”), 正文中要原样引用第 2 步的 OOM 类型字符串和第 3 步的 fullgc 数值。

参考

保留日志副本

创建 /root/ts,并把 /opt/lab/fixtures/tomcat/logs/ 中的四个文件原样复制过来。 (catalina-oom.log、gc.log、access.log、nginx-error.log) 内容必须与原件完全相同。

故障分析的第一个动作是保留原件。分析过程中日志被轮转或被覆盖的事,真的会发生。

确认 OOM 的发生时刻和类型

在 catalina-oom.log 中找到 OutOfMemoryError,创建 /root/ts/oom.txt。 共两行,格式必须与下面完全一致。

time=<로그에 적힌 타임스탬프>
type=<OOM 종류 문자열>

(占位符依次为日志中记录的时间戳、OOM 类型字符串。) type 取 Java heap space / Metaspace / GC overhead limit exceeded / unable to create native thread 之一。

OutOfMemoryError 的处理方式因类型而完全不同。类型写在消息的后半部分。

分析 GC 日志

分析 gc.log,创建 /root/ts/gc.txt。共两行。

fullgc=<Full GC 발생 횟수>
maxpause=<가장 긴 정지 시간, 밀리초, 소수점 포함 그대로>

(占位符依次为 Full GC 发生次数、最长停顿时间——单位毫秒,小数点部分原样保留。)

只需统计 Full GC。停顿时间是每行末尾的毫秒值。其中有小数点,所以请注意排序方式。

提取最慢的 URL

从 access.log 中提取处理时间最长的前 5 个 URL, 创建 /root/ts/slow.csv。首行为 url,count,max_ms, 按 max_ms 降序排列。

访问日志的最后一个字段是处理时间。需要按 URL 分组求最大值。使用 awk 的关联数组,一次扫描就能完成。

5xx 的发生分布

在 access.log 中按 URL 统计 5xx 响应,创建 /root/ts/5xx.csv。 首行为 url,status,count,按次数降序排列。

必须准确指出状态码字段。只挑出以 5 开头的三位数,按 URL 统计。

区分 502 和 504 的原因

在 nginx-error.log 中按原因统计上游错误, 创建 /root/ts/upstream.csv。首行为 code,cause,count。 code 为 502 或 504,cause 为 connection refused 或 timeout。

nginx 错误日志中的措辞会告诉你原因。连接本身被拒绝,与超时,留下的是不同的措辞。

分析真实的线程转储

启动 Tomcat,导出线程转储并保存到 /root/ts/threads.txt, 然后创建 /root/ts/threadstat.txt。共两行。

total=<덤프에 있는 전체 스레드 수>
waiting=<WAITING 상태 스레드 수>

(占位符依次为转储中的线程总数、处于 WAITING 状态的线程数。) 这两个值必须与 threads.txt 的内容一致。

在运行中的 Tomcat 上导出转储,然后按状态统计线程数。转储中线程状态以大写关键字表示。

编写故障报告

编写 /root/ts/rca.md。 必须包含 ## 현상、## 원인、## 조치、## 재발방지 这四个 h2 标题(韩文,依次意为“现象”“原因”“措施”“防止复发”), 正文中要原样引用第 2 步的 OOM 类型字符串和第 3 步的 fullgc 数值。

报告的价值在于数字。请原样引用前面步骤中提取出的值。防止复发的条目中,不要写“加以注意”,而要写具体的配置或监控项目。