问题出现得很突然,日志倒是留得挺全。一个月的 access.log 有八千万行,用 sort | uniq -c 统计 URL 请求量,跑到一半进程被 OOM killer 干掉,机器 16G 内存直接见底。

排查方向其实有限,先把可能性排一排。sort 默认把全部数据读进内存排序,数据量超过可用内存就被杀。也可能是日志没有按天切分,单文件过大。

少数情况下是统计脚本一次把所有字段都载入,实际只需要 URL 一列。

第一件事是按天切分减小单文件

zcat access.log.*.gz | awk '{print $4, $7}' | cut -c2-11 | sort | uniq -c | head

随后用 awk 关联数组替代 sort

awk '{c[$7]++} END {for (u in c) print c[u], u}' access.log | sort -nr | head -20

给 sort 指定临时目录和内存上限

sort -S 2G -T /data/tmp access.log | uniq -c | sort -nr | head

排查用的命令都是临时敲的,没有写成脚本,事后才整理。

手上没有现成的复现脚本,就照着线上请求手工拼了一个。

怎么算真的好了,看的是同一批现象。统计脚本能在十分钟内跑完且内存占用稳定在 2G 以内,输出的 URL 排名与抽样手工核对一致。

提醒一点。内存不够时优先换算法而不是加内存,awk 的哈希聚合比 sort 省一个量级。这类问题最好一次改到位,反复小改反而容易把原因搅混。

作者 9823189