统计爬虫并发连接数和峰值的标准做法只有一条:把每条请求还原成「开始时间—结束时间」的区间,用扫描线算法把所有区间端点排序后逐个累加,累加过程中的最大值就是并发峰值;日志里没有耗时字段时,只能退化成按秒聚合 QPS 做估算。
并发连接数和并发请求数有什么区别?
结论:并发连接数按 TCP 连接计数,并发请求数按 HTTP 请求计数,HTTP/1.1 keep-alive 下一条连接串行处理多个请求,HTTP/2 下一条连接可并行复用上百条请求流,两者可以差出两个数量级。
统计前必须先定口径:你要的是「同一时刻有几条 TCP 连接在传输」,还是「同一时刻有几个请求在等待响应」。判断抓取压力、封禁 IP 看连接数,评估抓取速率看请求数。口径不统一,后面算出来的峰值全是错的。
有耗时字段时,怎么算精确峰值?
结论:把每条请求拆成两个事件(start 记 +1,end 记 -1),按时间升序排序后求前缀和,前缀和的最大值就是峰值并发,时间复杂度 O(n log n)。
以 Nginx access log 为例,日志里带 $request_time(单位秒,含小数)时:
awk '{
gsub(/[\[\]]/,"",$4);
cmd="date -d \""$4"\" +%s.%N"; cmd|getline ts; close(cmd);
print ts" +1"; print ts+$NF" -1"
}' access.log | sort -k1,1n | awk '
{c+=$2; if(c>max){max=c; t=$1}}
END{print "峰值并发="max" 出现时间="t}'
数据已经在 ClickHouse / MySQL 里就更快,用窗口函数一步出结果:
SELECT max(cur) FROM (
SELECT ts, sum(delta) OVER (ORDER BY ts, delta) AS cur
FROM events -- events(ts, delta):start 为 +1,end 为 -1
) t;
时间精度建议保留到毫秒。1 秒粒度会低估峰值——同一条秒内起止的连接在秒桶里根本看不见。
没有耗时字段,怎么近似估算?
结论:用利特尔法则「并发数 = 到达速率 × 平均响应时间」估算。
先算每秒请求数峰值:awk '{print $4}' access.log | cut -c2-21 | sort | uniq -c | sort -rn | head,输出的最大值就是 QPS 峰值。若 QPS 峰值 500、平均响应时间 0.2 秒,平均并发约 100,再乘波动系数得到峰值估计。这是估算值,报告里必须写明口径,不能和实测并发混着用。
能直接从服务器上数连接数吗?
结论:可以,用 ss 按固定间隔采样,取采样序列的最大值,但精度受采样频率限制。
while true; do
n=$(ss -tanH state established '( sport = :80 or sport = :443 )' | wc -l)
echo "$(date +%s) $n"
sleep 1
done
只统计爬虫来源时,把过滤条件换成 ss -tanH state established dst 66.249.66.0/24。采样频率决定能看到的峰值:1 秒采样只能捕捉持续 1 秒以上的连接,瞬时抖动必然漏掉;把 sleep 1 改成 sleep 0.1 可提高分辨率,代价是 ss 自身 CPU 开销上升。
统计时最容易错在哪三点?
- 时间未对齐:多机日志必须 NTP 同步,否则跨机拼接的时间线会造出假峰值。
- 把平均并发当峰值:这两个数通常差 3~10 倍,报表里要分别标注。
- keep-alive 干扰:日志里若打了连接序号(如 Nginx 的
$connection),先按连接去重再算,得到的是连接并发;不区分直接算,得到的是请求并发。
收尾:先定口径(连接还是请求),再选方法(有耗时用扫描线,没耗时用利特尔法则估算),最后注明时间精度与采样频率。三件事写清楚,峰值数字才站得住。