在蜘蛛池里,CDN 经常被当成单纯的加速器来用,但它真正的作用更接近于把入口页的访问请求挡在离蜘蛛最近的一层。配得好,回源压力小、响应稳定;配得不好,蜘蛛看到的可能是缓存里的旧副本,甚至拿到 5xx。这篇文章只聊缓存与 CDN 相关的取舍。
先确认 CDN 适不适合你的入口页
蜘蛛池入口页大多结构简单、更新不频繁,用 CDN 承载本身是合理的。但 CDN 会改变蜘蛛实际拿到的东西——它拿到的是边缘节点返回的副本,而不是源站实时生成的页面。所以在调缓存之前先问自己一句:入口页的内容多久变一次。长期不动的模板页,缓存时间长一点没坏处;需要跟着目标页轮换的页面,缓存时间设长了就会出现蜘蛛抓到的还是上一批链接的情况。
先把角色分开看
CDN 负责的是最近的那一次请求,源站负责的是第一次和最真实的那一次。蜘蛛的第一次访问通常不会命中缓存,命中之后才会走边缘节点。所以调优时不要只盯着面板上的命中率,也要看源站在回源那一刻的表现。
缓存头具体怎么设
决定边缘节点是否缓存、缓存多久的,主要是响应头里的几个字段。它们对蜘蛛和普通访客一视同仁,蜘蛛不会因为 UA 不同就绕开缓存。
Cache-Control
- max-age:边缘节点和浏览器都会读。入口页内容稳定时可以给到几小时到一天;需要跟着轮换的页面建议压到几分钟,或者干脆让节点每次回源校验。
- s-maxage:只作用于共享缓存,也就是 CDN。想单独控制 CDN 的缓存时长就写这个,比 max-age 更精准。
- no-store:完全不留副本。入口页一般用不到,除非页面内容是按请求实时拼接的。
- private:只允许浏览器缓存,CDN 不存。如果发现 CDN 缓存了不该缓存的页面,检查是不是漏了这个。
ETag 与 Last-Modified
这两个是校验用的。节点缓存过期后会带 If-None-Match、If-Modified-Since 回源,源站返回 304 就不用重传正文。对入口页这种体积小但数量多的页面,304 能省下不少回源带宽。要注意源站生成 ETag 的规则保持一致,否则每次回源都变成 200,缓存等于白设。
回源与响应表现
CDN 不命中时会回源,回源那一刻的速度由源站决定。源站本身 TTFB 就高的话,CDN 只能改善命中之后的表现,改善不了第一次抓取。蜘蛛第一次访问通常都是不命中的,所以源站该做的精简还是得做。
另一个容易忽略的点是回源超时。源站偶尔慢一下,节点等不到响应就会返回 5xx 或 504,蜘蛛记到的就是一次失败。把回源超时设得合理一些,配合源站自身的重试,往往比反复调缓存时间更有用。
常见的几个坑
- 缓存了带参数的 URL:入口页如果带查询参数,而缓存键又包含全部参数,同一条内容会被拆成很多份缓存,命中率很低。可以考虑在 CDN 侧忽略掉没有实际意义的参数。
- 缓存了错误页:源站返回 404 或 500 时,如果 CDN 也把这些状态码按普通响应缓存下来,蜘蛛在缓存有效期内会一直看到错误页。
- 节点间内容不一致:不同地区节点缓存时间不同步,蜘蛛从不同出口访问可能拿到新旧不一的内容。对入口页来说通常不算大问题,但如果页面里的链接需要统一,就得留意。
- 日志被 CDN 吃掉:源站访问日志只记录回源请求,蜘蛛的访问记录在 CDN 侧。要分析抓取情况得把 CDN 日志拉下来,不然容易误判成蜘蛛没来。
调整时的顺序
- 先确认入口页的更新节奏,据此定缓存时长。
- 再看回源是否稳定,重点关注 5xx 和超时的比例。
- 然后看命中率。命中率低不一定代表配置错了,也可能只是页面太多、访问太散。
- 最后才是压缩、HTTP/2 这类传输层优化,优先级放在后面。
CDN 和缓存只能改变页面被取走的效率,改变不了页面本身有没有价值。入口页的内容和链接关系没理清,缓存调得再细,也只是让一批普通页面被更快地取走。
总的来说,入口页的 CDN 配置不需要多复杂:把缓存时长和更新节奏对上,把回源的错误率压住,把日志留住能看,基本就够用了。剩下的精力,建议放回入口页本身的结构和链接组织上。