一个代码托管站点的访问量很高,并不一定意味着开发者正在高频浏览页面。Linux 内核维护者 Konstantin Ryabitsev 在 kernel.org 官方博客的文章《Creepy crawlies》中披露,git.kernel.org 每天接收约 600 万个请求,其中约 98% 并非来自人类用户,而是自动化爬虫。
这组数据把一个经常被低估的问题摆到了台面上:AI 爬虫不只是抓取几篇文档,它们可能持续访问随机的 Git 提交,并要求服务器把提交内容渲染成 HTML。对于维护者来说,真正昂贵的不是单个请求,而是大量没有明确用户意图、难以缓存、持续占用计算资源的请求。
600 万次请求为什么值得警惕
Git 提交本身是结构化数据,但很多爬虫访问的却是面向人类阅读的 HTML 页面。服务器需要解析提交、生成差异视图、组织元数据,并返回完整页面。一次请求看起来并不重,数百万次请求叠加后,CPU、连接数、日志存储和带宽都会受到影响。
更麻烦的是,随机提交页面通常具有几个特征:
- 请求路径分散,缓存命中率可能很低。
- 爬虫访问节奏稳定,容易形成全天候背景流量。
- User-Agent 不足以准确区分不同模型或代理系统。
- 单个客户端可能不明显超限,但多个出口地址合计后会形成集中压力。
“98% 不是人类”也不等于 98% 都是恶意流量。搜索引擎、归档程序、代码分析工具和 AI 数据采集器都可能属于自动化访问。但对站点运营者而言,自动化流量仍然需要被识别、限速、缓存或拒绝,否则它会和真实开发者争夺同一组资源。
AI 爬虫带来的新压力
传统爬虫通常围绕链接发现和搜索索引工作,访问路径相对集中。面向大模型的数据采集则可能试图尽量覆盖更多页面,包括大量历史提交、差异页面和不常访问的对象。站点因此会遇到一种反直觉现象:热门页面不一定是压力最大的页面,随机、分散、难以预测的访问反而更难通过缓存缓解。
此外,HTML 页面通常比原始 Git 对象更昂贵。一个需要展示的提交可能涉及:
- 从对象存储中读取提交及其父提交。
- 计算或读取文件差异。
- 生成语法高亮、链接和页面布局。
- 写入访问日志并通过网络发送结果。
如果采集方只是为了训练或检索而收集代码,直接反复请求渲染后的页面并不是最高效的方式,却会把渲染成本转嫁给服务提供者。这也是维护公开基础设施时需要重新讨论访问边界的原因。
可以怎样实践:给公开 Git 页面加一道限流层
下面是一个可以改造的 Nginx 示例。它假设公开 Git 页面位于 /commit/ 路径,并以客户端 IP 为基本维度限速。请把配置放在你自己的站点上测试,不要直接套用到 kernel.org;真实部署还需要结合 CDN、反向代理、IPv6、可信代理头和业务白名单进行调整。
# http {} 级别配置
limit_req_zone $binary_remote_addr zone=git_pages:10m rate=2r/s;
limit_conn_zone $binary_remote_addr zone=git_conn:10m;
server {
listen 443 ssl;
server_name git.example.org;
location /commit/ {
# 平均每秒 2 个请求,允许短时突发 10 个
limit_req zone=git_pages burst=10 nodelay;
limit_conn git_conn 8;
# 为昂贵的 HTML 页面设置短期缓存
proxy_cache git_html;
proxy_cache_valid 200 60s;
proxy_pass http://git_renderer;
}
}
部署前需要确认两点。第一,$binary_remote_addr 只有在 Nginx 能看到真实客户端地址时才有意义;如果前面有 CDN 或负载均衡器,应先正确配置真实 IP,否则可能把所有用户错误地限到同一个地址。第二,不能只看 User-Agent 做放行或拦截,因为自动化客户端很容易伪装浏览器。
可以用下面的命令快速验证限流行为。将域名替换为自己的测试站点,并确认该路径不会触发生产环境中的昂贵操作:
for i in $(seq 1 20); do
curl -sS -o /dev/null -w '%{http_code} %{time_total}\n' \
'https://git.example.org/commit/example'
done
对于无需实时渲染的内容,还可以提供更适合机器读取的出口,例如 Git bundle、归档文件、批量 API 或静态快照。关键不是简单地把所有机器人拒之门外,而是让不同类型的客户端使用匹配其用途的接口。
运营者应该观察哪些指标
单独统计请求总数不够。要判断自动化流量是否正在消耗不合理的资源,至少应该按以下维度拆分:
- 路径:提交页、差异页、仓库首页、静态资源分别统计。
- 状态码:区分成功、限流、未找到和服务器错误。
- User-Agent:用于线索分析,但不要作为唯一身份依据。
- 客户端网络:IP、自治系统号、地理区域和代理层来源。
- 缓存:命中率、回源率和每个路径的平均响应时间。
- 资源:请求对应的 CPU 时间、渲染耗时、数据库或对象存储读取次数。
一个简单的日志分析可以先找出访问量最高的路径:
# 假设 access.log 的第 7 列是请求路径
awk '{print $7}' access.log \
| sort \
| uniq -c \
| sort -nr \
| head -20
生产环境更适合把日志送入结构化分析系统,并将“请求量”和“资源成本”关联起来。一个每天访问数很低但单次渲染很重的路径,可能比高缓存命中的静态文件更值得优先治理。
结论:公开服务也需要明确的自动化访问策略
git.kernel.org 的这组数字提醒维护者,公开可访问不等于无限制抓取。面对自动化流量,可以按以下顺序推进:
- 先确认流量构成,区分搜索索引、开发工具、归档程序和大规模采集。
- 为昂贵页面增加缓存、限速和并发控制。
- 为机器使用提供稳定、低成本、可批量获取的数据接口。
- 对异常模式保留封禁能力,但避免仅凭 User-Agent 做粗暴判断。
- 持续监控回源率、渲染耗时和真实用户错误率。
AI 爬虫是否有价值,是数据提供方和采集方之间需要协商的问题;但基础设施成本不会因为请求来自机器人而消失。把自动化客户端当作一等流量类型来管理,已经从优化项变成了公开代码服务的运行基础。