灰云还是橙云:anycast 路由把你的用户送去了地球另一端
站点挂在 Cloudflare 后面,国内访问要 15 秒,有时直接超时。但服务器自己 curl 同一个地址只要 1.4 秒,应用日志里每个请求都是 200。监控探针从另一个城市访问同一个域名却是正常的——这说明问题不在源站,也不在应用。
定位:是 IP 段的问题,不是域名的问题
在同一个客户端、同一条宽带上,测量若干个 Cloudflare 域名的 TCP 握手耗时:
| Cloudflare 分配的 IP 段 | 归属 | 握手耗时 |
|---|---|---|
| 104.16.x / 104.17.x / 104.18.x | 其他站点 | 2 – 12 ms |
| 104.21.11.110(我们这个 zone) | 本 zone | 276 ms |
| 172.67.191.230(我们这个 zone) | 本 zone | 307 ms |
Cloudflare 按 zone 分配独立的 anycast 前缀。我们这个前缀被国内运营商路由到了远端 PoP,而别人的前缀落在近端节点。响应头里的 CF-RAY 后缀就是边缘节点代号:我们看到的是 LAX、AMS、LHR 轮换——同一个站点,不同时间落到不同洲的节点。
这不是"CDN 变慢了",而是"你分到的这段 IP 被路由到了很远的地方"。换域名没用,换解析器也没用,因为决定落点的是运营商的 BGP 策略。
为什么免费版改不了
- anycast 前缀由 Cloudflare 分配,不能指定;
- 想把站点挂到子域名下的独立 zone,API 直接拒绝(错误码 1116,只接受根域);
- 中国大陆节点属于 Cloudflare 中国网络,需要 Enterprise 套餐;
- Argo 智能路由是付费项。
换句话说:免费版 + 中国大陆 + 保留 Cloudflare 加速,这三者不可兼得。唯一能自己动的变量是"要不要经过 Cloudflare"。
灰云之后要补的东西
切成灰云(只解析)意味着源站 IP 直接暴露,Cloudflare 提供的 DDoS 清洗、WAF、缓存全部消失。对内部工具来说这通常是划算的,但要自己补上:
- 反向代理层限流——按客户端 IP 限制请求速率和并发连接;
- 自动封禁——对扫描器、爆破行为做封禁;
- 敏感路径直接 404——
/wp-admin、/.git、/.env这类探测路径不必返回 403,返回 404 什么都不告诉对方; - 不暴露版本号;慢连接防护(slowloris);
- 真正想要 DDoS 清洗时,改用国内有节点的方案:阿里云 ESA 的源站防护可以把安全组收回成"只放行回源 IP",源站彻底不暴露公网。
另外一个坑:缓存不是免费的
橙云期间 HTML 是被边缘缓存的(实测 cf-cache-status: HIT),JS bundle 由边缘直接下发。切灰云后每次都回源,首字节时间取决于源站和应用。可以用 Cache-Control 控制,但如果站点有大量静态资源,自建 nginx 的 expires 指令要配好,否则每个资源都是一次完整往返。