⭐ 推荐:社区规则条款 V1.0

蜘蛛爬虫分析中怎么统计抓取的并发连接数和峰值?

juming
juming 归队站长新人站长
发布于 2026-10-14 16:15 ·3 浏览 ·3 回复
内容摘要

统计爬虫并发连接数与峰值应先用扫描线算法将请求起止时间排序求前缀和最大值,无耗时字段则按QPS和平均响应时间用利特尔法则估算;需区分TCP连接数与HTTP请求数口径,也可用ss采样取最大值。

统计爬虫并发连接数和峰值的标准做法只有一条:把每条请求还原成「开始时间—结束时间」的区间,用扫描线算法把所有区间端点排序后逐个累加,累加过程中的最大值就是并发峰值;日志里没有耗时字段时,只能退化成按秒聚合 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),先按连接去重再算,得到的是连接并发;不区分直接算,得到的是请求并发。

收尾:先定口径(连接还是请求),再选方法(有耗时用扫描线,没耗时用利特尔法则估算),最后注明时间精度与采样频率。三件事写清楚,峰值数字才站得住。

蜘蛛爬虫分析中怎么统计抓取的并发连接数和峰值?,本文转载自 GJ站长论坛,原文地址:https://www.gj0.com/thread-1962.html
转载请注明出处,版权归原作者所有。
他们都看过 1 人浏览过
GJ论坛站长
—/ 5暂无评分
还没有评分,来打第一分吧

全部回复 3

域名注册
域名注册 版主归队站长新人站长 👑年卡会员 1楼 2026-10-14 16:36

结论先给:扫描线算法本身没问题,但真正决定这份统计准不准的,是时间戳取的是请求开始还是结束,以及爬虫身份怎么认定——这两点比算法本身更容易翻车。

Nginx 的 $time_local / $time_iso8601 记的是请求结束时间,不是开始时间。你直接用 ts + $request_time 去还原区间,整条区间会整体右移,短请求密集的时段峰值还会虚高。正确做法是 start = ts - $request_time,end = ts。更稳的是日志里直接加 $msec(毫秒精度开始时间)和 $connection_requests,字段齐了后面怎么算都对,事后拿日志硬凑最费劲。

ss 按 1 秒采样那条,对平均 50–100ms 的抓取请求命中率很低,短连接大并发场景下会明显低估峰值,只能当趋势看。要么把间隔压到 100–200ms(注意 ss 自身开销),要么用 conntrack / eBPF 做持续观测,别用 1s 采样出来的最大值去写容量报告。

爬虫识别也别只信 UA。Googlebot、Bingbot 这类必须做 forward-confirmed reverse DNS,反查 PTR 再正查回 IP;否则统计出来一多半是扫站工具和伪造 UA 的采集器,峰值口径直接失真。

最后提一句:连接数和请求数两套口径建议分开出报表,封禁策略看连接数,容量和抓取速率评估看请求数,报告里把采样方式、时间精度、爬虫判定规则一起写清楚。

liulian
liulian 归队站长新人站长 #1509 2楼 2026-10-14 16:45
域名注册:结论先给:扫描线算法本身没问题,但真正决定这份统计准不准的,是**时间戳取的是请求开始还是结束**,以及**爬虫身份怎么认定**——这两点比算法本身更容易翻车。…

补充和纠正各一点——你抓的这两个变量确实是翻车重灾区,但 $msec 那个说法得纠一下。

$msec 也不是开始时间。 它和 $time_local / $time_iso8601 一样在 log phase 求值,记的都是响应写出、日志落盘那一刻,也就是结束时间,区别只是精度到毫秒。所以正确公式是 start = $msec - $request_time,$msec 的价值在精度不在语义。别单独拿它当区间左端,否则整条区间又右移一次,等于把 $time_local 的坑原样踩第二遍。真正想拿到开始时刻,只能在 rewrite 阶段用 set $t0 $msec 提前取样,或者干脆接受"结束时间 - 耗时"这个还原方式。$connection_requests 建议加上,它直接标出当前连接上第几个请求,keep-alive 连接数的口径靠它能算干净。

另外三个点补充:一是扫描线排序时,同一时间戳要让 -1 排在 +1 前面(ORDER BY ts, delta 正好是这样),否则结束和开始同刻会被算成重叠,短请求密集时峰值虚高;跑完顺手检查计数是否归零,不为零说明区间跨了日志文件、有事件丢失。二是 conntrack 统计并不干净,连接关闭后条目还要在表里停留到 TIME_WAIT 结束,只数 established 仍会偏高,eBPF 挂 tcp_connect / tcp_close 才准。三是 FCrDNS 别实时硬查,PTR 结果按 TTL 缓存、正查改成批量校验,不然高并发下 DNS 自己先成为瓶颈。

域名注册
域名注册 版主归队站长新人站长 👑年卡会员 #1511 3楼 2026-10-14 16:53
liulian:补充和纠正各一点——你抓的这两个变量确实是翻车重灾区,但 `$msec` 那个说法得纠一下。 **`$msec` 也不是开始时间。** 它和 `$time_l…

这几条纠正都成立,尤其 $msec 那条——把「精度高就当左端用」这个误解摁死,比单纯说 $time_local 是结束时间更有杀伤力,因为高频采样下毫秒精度最容易被误当成开始时间。

实操上我再补两个细节:一是统一到整数毫秒再排序,start_ms = int($msec*1000) - int($request_time*1000),别让 $request_time 的小数字段参与浮点比较,区间端点排序时 0.1ms 级的浮点误差会让扫描线在密集短请求处抖出假峰值;二是「-1 先于 +1」最好显式写死,ORDER BY ts, delta 依赖 delta 值恰好是 -1/+1 才能正序生效,一旦未来口径改成加权计数就会失效。归零检查建议按天分片跑,跨文件丢事件多半是 rotate 那几秒的窗口。

$connection_requests 那条同意,但要提一句:它只标序号,真要算 keep-alive 连接数还得配 $connection 去重,或者直接筛 $connection_requests == 1 当新连接看,否则你把请求序号当连接数加起来会重复计。

eBPF 比 conntrack 干净这个判断没问题,不过注意挂点选 tracepoint/sock:inet_sock_set_state 比自己拼 tcp_connect/tcp_close 更稳,容器场景下还要按 netns 过滤,不然会混进宿主机的连接。最后提醒一句最大的坑:连接口径和请求口径算出来的峰值能差两个数量级,报告里不写清用哪个,数字就没法解释。