没有不值得去解决的问题,也没有不值得去学习的技术!

Cloudflare 缓存 HIT 很快,MISS 却不稳定:回源阿里云杭州的一次真实优化

【图 3:Cloudflare Smart Tiered Cache 已启用】

作者:

A Tour of Go 多语言翻译项目

图3:访问过去的 Go Tour 简体中文站 tour.go-zh.org 时,当前已经无法正常建立连接。

(1) 从「A Tour of Go 中文版」这个搜索词开始:我决定做一个持续维护的 Go Tour 中文版

本地运行的 A Tour of Go「Methods continued」课程页面,左侧为课程说明,右侧为 Go 代码编辑器及运行结果。

(2) A Tour of Go 中文版项目设计冻结:从 101 页到 103 页,从 Gin 转向 Cobra CLI

A Tour of Go 中文版开发实战:英文基线、在线运行与 101 页上游同步体系

(3) A Tour of Go 中文版开发实战:英文基线、在线运行与 101 页上游同步体系

go-tour-i18n 项目完成首个简体中文课程页面 welcome/1 的整页翻译、结构校验和本地预览。

(4) A Tour of Go 多语言翻译项目实录:完成首个 zh-CN 页面翻译闭环

图 1:DeepSeek 官方更新日志显示,本次只更新 DeepSeek-V4-Flash,DeepSeek-V4-Pro API 与 APP、Web 模型均未更新

(5) A Tour of Go 中文翻译项目进展:完成前 8 页、修复 present 语法,并暂缓 DeepSeek 对比

图 1:generics/1 简体中文页面本地预览

(6) 一个页面重试五次:使用 GLM-5.2 翻译 A Tour of Go 时遇到的 Token 与 Present 结构问题

图 1:methods/16 简体中文页面浏览器预览

(7) A Tour of Go 中文翻译实录:如何只翻译教学代码注释,而不破坏 Go 代码

图 2:A Tour of Go methods/20「练习:错误」中文候选页面最终渲染效果

(8) A Tour of Go 多语言翻译:当正确的中文语序被受保护标记顺序校验误判

图 3:methods/24 中文页面,静态代码、Bounds 行内代码和链接内的 image.Rectangle 均正确渲染

(9) A Tour of Go 中文翻译完成 7 个代表页校准:最后 3 页又发现了哪些真实问题

图 2:首批 10 个普通页面经过试跑与流程校准后全部进入 ready

(10) A Tour of Go 多语言翻译项目:首批 10 个普通页面试跑,从 2 个 blocked 到全部 ready

图 2:flowcontrol/6 最终中文页面,return 与 v 为适应自然中文语序发生整体换位

(11) A Tour of Go 中文翻译第二批实跑:从 Inline Code 顺序误判到历史响应重新验证

图 1:flowcontrol/6 首次原始输入实验直接通过统一自动校验

(12) A Tour of Go 多语言翻译项目:从 swap 问题重新审视 Token 保护,原始输入与最小保护的一次真实实验

图 7:moretypes/1 最终中文页面预览。左侧课程正文、静态代码块、行内代码和教学注释均正常渲染,右侧官方 Go 示例继续保持原样。

(13) A Tour of Go 多语言翻译实战:第三批 10 页全部 Ready,继续校准 Protected Token 的结构角色

图 4:上游源码确认共有 103 个课程页面,zh-CN 最终达到 ready=103、pending=0、blocked=0

(14) A Tour of Go 多语言翻译项目:zh-CN 103 个课程页面全部 ready,课程正文翻译阶段完成

图 4:GitHub 与 ChatGPT 已成功连接

(15) ChatGPT 连接 GitHub 实测:让 AI 直接读取 go-tour-i18n 仓库参与译文审核

图 3:中文 Go 术语校准完成后,将确定的译法写入 zh-CN glossary

(16) 为什么 channel 最终选择“通道”:A Tour of Go 中文术语统一的一次实践

图 1:技术含义基本正确,但“返回一个返回……”已经明显影响阅读,因此仍被列入 C 类修订

(17) 103 页逐页审核后,只返修 16 页:A Tour of Go 中文正文发布前质量审计

图 2:中文课程页面以及已经完成本地化的编辑器控制区

(18) A Tour of Go 多语言翻译项目:公共 UI 本地化完成,从课程译文走向完整中文界面

图 2:完整 zh-CN 正式投影成功生成,103 个课程页面被重新组装为 7 个 .article

(19) 从 103/103 ready 到完整站点验收:A Tour of Go 中文版补齐正式投影与课程元数据本地化

图 3:从 production bundle 独立启动的 A Tour of Go 简体中文页面,课程正文、公共 UI 和官方 Go 示例均已进入最终发布形态。

(20) A Tour of Go 多语言翻译项目:103 页全部完成后,我终于生成了可独立部署的 zh-CN Production Bundle

图 1:A Tour of Go 简体中文版正式生产页面,远程运行已经成功输出“Hello, 世界”。

(21) A Tour of Go 多语言翻译项目:zh-CN 正式上线,从生产发布到 go.dev Playground 的完整部署记录

图 1:新生产域名 go-dev.shuijingwanwq.com 已正常访问,Go 示例远程运行成功

(22) A Tour of Go 多语言翻译项目:从 go-tour 到 go-dev,完成 EdgeOne、Nginx 与 HTTPS 生产域名迁移

图 1:A Tour of Go 多语言翻译项目正式生产首页

(23) A Tour of Go 多语言翻译项目正式上线:从项目首页、公共 Footer 到生产发布元数据的完整收尾

图 3:GA4 g/collect 请求返回 HTTP 204,并携带当前课程页面地址,确认 Google Analytics 已产生真实事件上报

(24) A Tour of Go 多语言翻译项目:接入 Google Analytics 与百度统计,从 systemd 注入到 EdgeOne 与真实上报验证

图 1:生产环境 robots.txt 与 sitemap.xml 已正确对外提供,Sitemap 共包含 104 个规范 URL。

(25) A Tour of Go 中文站上线后:补齐 robots.txt、Sitemap,并完成五大搜索引擎提交

图 4:发布生产并刷新 EdgeOne 缓存后,再次通过真实手机访问,顶栏项目名称已经完整保持在一行,最终移动端验收通过。

(26) A Tour of Go 多语言翻译项目:修复手机端首页顶栏标题换行,并完成真机验证

图 3:生产自动部署脚本第一次真实运行时,systemd 已经显示 active,但首次 localhost 探测仍然得到 HTTP 000;随后连续 3 次同时满足 active + HTTP 200 后,脚本才判定部署成功,并继续完成公网 HTTP 200 验收。这次真实运行验证了连续应用层健康检查的必要性。

(27) A Tour of Go 多语言翻译项目:从一次 203/EXEC 故障到生产自动部署脚本落地

图 1:阿里云生产环境访问 go.dev Playground 时出现 TLS 握手超时

(28) A Tour of Go 多语言翻译项目:为 Playground 搭建独立的 ZgoCloud 执行代理

图 3:清除 /tour/script.js 缓存后,Run 已直接请求 ZgoCloud /compile 并返回 HTTP 200

(29) A Tour of Go 多语言翻译项目:将生产 Run / Format 切换到 ZgoCloud 执行节点

【图 1:微信中运行 Go 示例时出现 Error communicating with remote server.】

(30) A Tour of Go 中文版手机端运行与格式化偶发失败排查:从间歇性报错到补强 Nginx 可观测性

【图 4:向 golang-dev 公开邮件列表发送 Playground 使用告知邮件并投递成功】

(31) A Tour of Go 多语言项目:为 Playground 代理增加唯一 User-Agent,并主动告知 Go 官方

【图 3:百度剩余 9 个核心 URL 提交成功,remain 归零】

(32) A Tour of Go 搜索引擎收录实测:从 Google 自然索引到百度主动提交与 Bing IndexNow

【图 1:当前正式中文 methods/24 页面,右侧示例代码运行成功】

(33) A Tour of Go 中文翻译完成后,我为什么重新评估 minimal-protect 翻译模式

【图 3:5 个页面 Request SHA256 完全一致,但 Response SHA256 全部不同】

(34) A Tour of Go 翻译实验:更多原始上下文为什么没有更好?从 157 个保护标记到 30 次重复盲评

图 3:3 个代表页 × 4 个评审模型,共 12 次匿名评审的完整排名与第一名票数。

(35) A Tour of Go 翻译质量再评估:minimal-protect 未达预期后,我开始比较 ChatGPT、Codex 与 GLM-5.2

图 2:GitHub 中的 chatgpt-zh-CN-008 重译批次。一个 Batch 同时保存 inputs、raw-responses、candidates、validation 和 retry 记录,GitHub 成为 ChatGPT 与本地翻译流水线之间的数据交接层。

(36) 没有 OpenAI API,我如何用 ChatGPT + GitHub 完成 A Tour of Go 103 页全量重译

图 1:103 个正式课程页面完成最终语义质量审核,结果为 A=103、B/C/D=0,同时不存在缺失、重复或额外页面。A/B/C/D 是本轮项目内部语义质量分级,并不是自动结构 validator 的结果。

(37) 103 页翻完还不能发布:A Tour of Go ChatGPT 译文的语义审核与 Canonical Promotion

图 3:7 个 article endpoint 的 production origin 与 EdgeOne 公网响应全部 exact match,同时新的 ChatGPT 译文标记存在,旧版译文标记已经消失。

(38) 103/103 与 7/7 Exact Match:A Tour of Go ChatGPT 新译文的最终线上验收

【图 2:upstream source preview】

(39) A Tour of Go 多语言翻译项目首次实现 upstream 同步机制:从一次性翻译到长期维护

图 2:A/B/C/D 质量评级规则,展示正式质量 rubric 与 Promotion gate。

(40) A Tour of Go 多语言翻译项目引入 Translation Quality Review:从自动验证到 AI 翻译质量控制

图 4:翻译后 Playground Example,展示中文注释与保持不变的 Go 代码结构。

(41) A Tour of Go 多语言翻译项目实现 Playground Example 本地化:从代码注释翻译到完整学习体验

图 5:公网页面验证广告脚本输出

(42) A Tour of Go 多语言翻译项目接入广告系统:从 AdSense 专用配置到通用 HTML 注入架构

图 3:百度统计单页应用设置

(43) go-dev 单页网站接入统计与 Google AdSense Auto Ads 验证记录

图 1:GitHub 仓库中的多语言翻译项目结构

(44) A Tour of Go 多语言翻译项目:选择日语作为第二语言并启动翻译验证

图 5:模型身份描述不一致

(45) A Tour of Go 多语言翻译项目中的 AI 协作异常排查:一次长期工程会话失效分析

【图 1:ChatGPT GitHub 写入流程调整说明截图】

(46) go-tour-i18n 翻译流程调整:从 ChatGPT GitHub 写入到本地 artifact 导入

图 4 展示了本次异常状态。

(47) go-tour-i18n 翻译自动化流程复盘:已验证的 ChatGPT 翻译能力在新任务中的稳定性问题

【图 6:全部评审结束以后才读取 secret key,完成最终揭盲】

(48) A Tour of Go 翻译质量再评估:Codex High 已接近 ChatGPT High,我决定调整默认翻译引擎

图 4:ja-JP 生产课程页实际运行 Go 示例

(49) A Tour of Go 日语版正式上线:第二门语言 ja-JP 完成生产发布

图 1:ja-JP 上线以后,先提交“新增语言标准化流程”

(50) A Tour of Go 多语言扩展复盘:为第三门语言建立标准化流程

图 1:课程正文结束以后,页面左侧仍然存在大块视觉空白,但 AdSense 并没有在这里插入展示广告。

(51) A Tour of Go 明明有大片空白,为什么 AdSense 就是不显示展示广告?

图 2:golang/website 当前的 _content/tour/。课程内容、静态资源和模板都在这个上游目录中持续维护。

(52) 为了 AdSense,要不要放弃 SPA?A Tour of Go 页面架构的一次取舍

图 4:最终的手动课程广告真实展示在课程内容区域内,而不是 footer 之后。

(53) 保留 SPA 以后,广告应该放在哪里?从 AdSense 预览到方案 B

图 1:Google Search Console 中,多个不同的 A Tour of Go 课程 URL 被判断为“重复网页,用户未选定规范网页”。

(54) SPA 的 SEO 老问题:为什么最后还是给 103 个 A Tour of Go 课程页生成了 Prerender HTML

图 2:方案 B 生产环境中,源码已经正常,但课程主体高度异常缩短,footer 提前进入第一屏。

(55) 从源码空白到 AdSense 高度污染:A Tour of Go 方案 B 的生产收尾

图 1:A Tour of Go 德语版 de-DE 已正式运行在生产环境

(56) A Tour of Go de-DE 上线复盘:第三门语言用了约 16 小时,下一门如何压到 8 小时?

图 1:fr-FR 首次 production 验收完成后,我没有立即开始 ko-KR,而是先连续完成新增语言与首次生产流程的优化

(57) 法语版上线后,我没有马上开始韩语:A Tour of Go 新增语言流程的一轮完善与简化

图 1:根据 ko-KR 期间 76 次 Git 提交估算实际工作时间

(58) 原本预计 6 小时,最后用了约 16~18 小时:A Tour of Go 韩语版上线复盘

图 2:英文 source 与当时发生 validation failure 的 ko-KR candidate 对比

(59) Validator 报错,到底该改译文还是改规则?一次 A Tour of Go 韩语翻译实战

图 2:法语 A Tour of Go 仓库目前已经归档,页面仍保留 553 Commits 和 61 Contributors 的历史

(60) 从法语 553 次提交到韩语两代离线:A Tour of Go 社区翻译为什么难以长期维护

【图 4:es-ES 首次 Production 收口后连续完成的流程优化 commit】

(61) 从 es-ES 首次上线复盘:我把 A Tour of Go 新增语言的 Production 流程又收敛了一轮

图 1:旧公网验收链路连续出现 curl 28 超时,最终导致 public-machine 阶段失败

(62) A Tour of Go Production 公网验收踩坑:从跨境 SOCKS 链路改为 zgocloud direct

图 1:两次 Production Machine Acceptance 都已经通过,但 Headless Chrome 分别在 / 和 /tour/ 判定页面没有完成渲染

(63) 页面明明能打开,为什么 Headless Chrome 仍然判定 Production 失败?

图 3:Bing 从 Google Search Console 中识别到新的 it-IT 站点,并同时发现已有的 1 个 sitemap

(64) GSC → Bing Webmaster Tools:多语言站点如何减少重复验证

图 3:英文站 3 小时内出现 565 个 Cloudflare 来源 URL

(65) IndexNow 实战:手工提交长期不显示,Cloudflare Crawler Hints 却很快出现在 Bing Webmaster Tools

【图 1:A Tour of Go 项目首页目前的语言版本列表】

(66) 从 nl-NL 到 tr-TR:A Tour of Go 连续上线三门语言后,我又优化了哪些流程

【图 4:Go local 页面中已经出现 French、German、Korean、Simplified Chinese】

(67) 从邮件无人回复到进入 Go 官方 Go local:我的 4 个 A Tour of Go 翻译站终于被收录

图8:最终只保留一把启用的新 API Key

(68) 腾讯云 EdgeOne API 自动化:从 CAM 子用户到最小权限 API Key 的完整配置

【图 7:Production Release Batch 最终汇总】

(69) 从同步 Go 官方上游到一个命令发布 10 个语言站:A Tour of Go Production 流程的再次收敛

【图 3:Cloudflare Smart Tiered Cache 已启用】

(70) Cloudflare 缓存 HIT 很快,MISS 却不稳定:回源阿里云杭州的一次真实优化

最近在维护 A Tour of Go 多语言项目时,我遇到了一个很典型的问题:

网站平时访问很快,Cloudflare 缓存已经 HIT 的页面基本没有异常。

但只要发布新版本、清除缓存,或者访问一个还没有进入缓存的资源,出现 MISS,请求就可能突然变慢,甚至超时。

我的非中文语言站目前大多使用 Cloudflare 免费版,源服务器仍然位于中国大陆的阿里云杭州。

大致链路是:

Plaintext
用户

Cloudflare

阿里云杭州源站

缓存 HIT 时,源站甚至可能完全不参与。

真正的问题,往往只有在 cold MISS 需要回源之后才会暴露出来。

这次排查过程中,我一度已经考虑把源服务器迁到海外,或者把非中文站全部从 Cloudflare 切回 EdgeOne。

最终都没有这么做。

我最后开启的是 Cloudflare Smart Tiered Cache。

而它带来的改善,比我一开始预期的明显得多。


一开始,我主要是在提高自己的部署成功率

这个问题不是某一天突然发现,然后一次解决掉的。

从 Git 历史可以看到,我前期做的事情主要还是:

让 Production workflow 更能够容忍公网瞬态故障。

【图 1:Cloudflare 冷缓存问题处理时间线】
【图 1:Cloudflare 冷缓存问题处理时间线】

连续几次修改包括:

Plaintext
fix: 增强生产公网验收瞬态容错
fix: 完善生产冷缓存瞬态容错
fix: 分阶段执行多语言生产维护
fix: 完善生产恢复预检与 CDN 隧道重试
fix: 增强生产浏览器错误诊断
docs: 记录 Smart Tiered Cache 生产基线

最开始这些修改的目的其实非常明确:

提高我自己一次 Production 发布成功完成的概率。

比如:

  • curl exit 28 这种 transport timeout 做 bounded retry;
  • Cloudflare 522525 等短暂网络错误允许有限重试;
  • browser navigation 增加有限 convergence;
  • 长时间任务加入恢复状态;
  • failure 时保留更明确的网络 evidence。

这些优化本身都有价值。

假设一次发布要验收 10 个语言站,而其中某一个请求恰好因为公网波动第一次失败,就让整个发布立即中止,确实不太合理。

但做到后面,我逐渐意识到:

这些优化主要解决的是“我的部署是不是容易失败”,并没有改善真正的网站用户在 cold MISS 时的访问体验。

比如,我把 timeout 从 15 秒增加到 25 秒,可以让 verifier 更有机会等到请求最终成功。

但是用户打开网页时:

他仍然可能在那里等 20 多秒。

我的部署脚本可以:

Plaintext
第一次失败
→ 等 1 秒
→ 再试一次
→ 成功

于是 Production 通过了。

但普通用户并不会因为我的部署脚本变聪明,就自动获得更好的第一次访问体验。

所以这件事其实需要拆成两个问题:

Plaintext
部署侧:
怎样避免短暂网络波动导致整个 Production 批次失败?

用户侧:
怎样真正改善 Cloudflare cold MISS 回源阿里云杭州时的体验?

前者可以通过 bounded retry 改善。

后者必须处理真实网络路径。


一个 cold MISS 曾经等了约 21.8 秒

真正让我开始认真看待回源链路的,是一次 cold MISS。

正式 Production 中曾经观察到:

一个请求大约 21.8 秒之后才最终成功。

【图 2:当时观察到约 21.8 秒才成功的 cold MISS】
【图 2:当时观察到约 21.8 秒才成功的 cold MISS】

也正因为这个真实结果,我后来把部分 Production readiness 的单次请求上限调整到了 25 秒。

这里很容易产生误解。

把 timeout 调高,并不是说:

网站请求 25 秒才返回也可以接受。

它只是为了防止真实请求在第 21.8 秒成功时,Production verifier 第 15 秒就提前判定失败。

这解决的是自动化验收的误判问题。

它没有解决真正的访问速度问题。

也就是从这里开始,我越来越明确地区分:

Plaintext
HIT 的速度

和:

Plaintext
MISS 的回源速度

如果平时打开的是一个已经缓存好的页面,Cloudflare 可能很快就返回。

这根本不能证明:

Cloudflare 到阿里云杭州的真实回源路径同样很快。


HIT 很快,并不代表回源很快

缓存 HIT 时,可以非常粗略地理解成:

Plaintext
用户

Cloudflare Edge

缓存

用户

阿里云杭州源站可能完全没有收到这个请求。

但是没有 Tiered Cache 时,一个 cold MISS 更接近:

Plaintext
用户

Cloudflare Edge

本地缓存 MISS

阿里云杭州

Cloudflare

用户

真正不稳定的很可能就是:

Plaintext
某个 Cloudflare Edge

阿里云杭州

所以我当时看到的是一种很典型的现象:

Plaintext
缓存已经热起来:
很快

刚刚 purge:
可能很慢

某个冷门 Angular partial 第一次访问:
可能很慢

再访问:
又很快

如果只是日常刷新一个已经 HIT 的首页,很容易误以为:

网站完全没有问题。


当时我已经开始考虑两个更大的方案

做到这里时,我其实已经不只是想调 timeout 了。

如果 Cloudflare 回中国大陆源站这条链路本身长期不稳定,那么更直接的做法就是改变架构。

我当时主要考虑过两个方案。

方案一:把源服务器迁到海外 zgocloud

第一个想法是:

直接把 Production origin 从阿里云杭州迁到海外的 zgocloud。

这样可以从根本上改变:

Plaintext
Cloudflare

中国大陆源站

这条跨区域回源路径。

从网络角度看很直接。

但它不是换一个配置,而是迁移整个 Production origin。

涉及:

Plaintext
Nginx
systemd
release 目录
部署流程
证书
备份
安全
监控
故障恢复

而且我还有一个当时没有确认清楚的问题:

备案与接入关系。

工信部现行规则明确要求,在中华人民共和国境内提供非经营性互联网信息服务应依法履行备案手续。(工业和信息化部)

但如果我把现有实际 origin 迁到境外,同时还保留部分境内基础设施,现有备案、接入商以及后续变更应该如何处理,我当时并没有确认清楚。

所以我不愿意为了一个 CDN cold MISS 问题,直接引入一整套新的政策和架构不确定性。


方案二:非中文站全部切回 EdgeOne

另一个方案是:

既然源服务器本来就在阿里云杭州,那么非中文语言站是不是也不要继续使用 Cloudflare,而是全部切回 EdgeOne?

这个方案技术上也很自然。

中文站本来就在使用 EdgeOne。

如果全部改成更适合中国大陆源站的 CDN 架构,也许可以直接规避现在这条 Cloudflare 回源路径。

但这个方案还有一个非常现实的问题:

成本。

我现在这些非中文 community locale 使用的是 Cloudflare 免费版。

随着语言数量继续增长:

Plaintext
10 个站
20 个站
30 个站
……

如果全部切换到持续产生实际费用的 CDN,长期运营成本会同步增加。

而目前 A Tour of Go 多语言项目的广告收入仍然很低。

除此之外,现在的:

Plaintext
Cloudflare Cache Rule
hostname purge
shared assets
Production verifier
新增 locale Production baseline

都已经围绕 Cloudflare community locale 形成了稳定流程。

全部切回 EdgeOne,也意味着现有 Production 架构需要重新迁移。


所以,我先找 Cloudflare 自己有没有更小的解决方案

当时真正的选择其实变成:

Plaintext
方案 A:
迁到海外 origin
→ 改动最大
→ 备案与接入边界需要确认

方案 B:
全部切回 EdgeOne
→ 技术可行
→ 长期 CDN 成本更高

方案 C:
继续使用 Cloudflare
→ 优先优化 Cloudflare 自己的回源拓扑

在真正做前两个大改动之前,我决定先试第三种。

于是开始认真看:

Smart Tiered Cache。


Smart Tiered Cache 到底改变了什么?

在 Cloudflare Dashboard:

Plaintext
缓存
→ Tiered Cache

我最终启用了:

Plaintext
Smart Tiered Cache

当前显示:

Plaintext
Tiered Cache Topology: Active
【图 3:Cloudflare Smart Tiered Cache 已启用】
【图 3:Cloudflare Smart Tiered Cache 已启用】

Cloudflare 官方对 Tiered Cache 的解释是:

把数据中心分成 lower tier 和 upper tier。

如果 lower tier 没有内容,并不会立即访问 origin,而是先去询问 upper tier。

只有 upper tier 也没有内容,才由 upper tier 访问真正的 origin。(Cloudflare Docs)

所以链路变成:

Plaintext
用户

Lower-tier Edge

Upper Tier

Origin

看起来反而比以前多了一层。

这也是我一开始最困惑的地方:

明明多经过一个节点,为什么反而更快了?


三层网络为什么可能比两层更快?

没有 Tiered Cache 时,一个 MISS 可能是:

Plaintext
用户

某个 Cloudflare Edge

阿里云杭州

真正决定回源质量的是:

Plaintext
这个 Edge

阿里云杭州

如果这条路径质量不好,节点再少也没有意义。

开启 Smart Tiered Cache 后,路径可能变成:

Plaintext
用户

Lower Tier

Cloudflare 网络

选定的 Upper Tier

阿里云杭州

虽然多了一跳,但新增的主要是 Cloudflare 自己网络内部的一段。

更重要的是:

真正有资格去访问 origin 的节点被收敛到了 upper tier。

Smart Tiered Cache 还不是随机选一个 upper tier。

Cloudflare 官方说明,它会使用自己的性能和路由数据,并收集各数据中心访问 origin 时的 latency,然后为 origin 动态选择连接延迟较低的 upper tier。(Cloudflare Docs)

所以:

Plaintext
节点更少

并不等于:

Plaintext
一定更快

网络真正重要的是:

Plaintext
整条路径的质量

如果增加的是一段 Cloudflare 内部网络,却把:

Plaintext
任意 Edge → 阿里云杭州

变成:

Plaintext
更适合访问这个 origin 的 Upper Tier → 阿里云杭州

那么整体完全可能反而更快。


更重要的是:Lower Tier MISS,不再等于 Origin MISS

这其实是我后来觉得 Tiered Cache 最重要的一点。

开启之后,一个请求可能是:

Plaintext
Lower Tier:MISS

Upper Tier:HIT

直接返回

这种情况下:

阿里云杭州根本不会收到请求。

Cloudflare 官方也明确说明,Tiered Cache 的目标之一就是让 lower tier MISS 先查询 upper tier,从而提高整体缓存命中率并减少真正到达 origin 的请求。(Cloudflare Docs)

更有意思的是:

如果 lower tier 自己没有缓存,但 upper tier 已经 HIT,那么最终用户看到的:

Plaintext
CF-Cache-Status

仍然可以直接是:

Plaintext
HIT

Cloudflare 官方文档明确提到:第一次从 upper tier 填充本地数据中心缓存时,响应可以显示 HIT;这个 HIT 反映的是 upper-tier 命中,而不是这个 local Edge 原来已经有缓存。第一次这种响应甚至可能还没有 Age,之后真正从 local cache 命中时才出现。(Cloudflare Docs)

这意味着一个非常重要的区别:

Plaintext
Local Edge MISS

Origin MISS

以前某个 Edge 第一次访问某个 URL,很可能意味着:

Plaintext
重新访问一次阿里云杭州

现在则可能只是:

Plaintext
Lower Tier MISS
→ Upper Tier HIT
→ 根本不访问阿里云杭州

一个 URL 是不是只需要一次真正 MISS?

在理想情况下,可以这么理解,但必须加限定。

假设:

  • cache key 完全相同;
  • 内容仍然 fresh;
  • upper tier 没有被 eviction;
  • 没有 purge;
  • Smart Tiered Cache 的 upper-tier assignment 没变化;

那么可能出现:

Plaintext
第一次请求:

东京 Lower Tier MISS
→ Upper Tier MISS
→ 阿里云杭州
→ 用户看到 MISS

之后另外一个地区第一次访问:

Plaintext
洛杉矶 Lower Tier MISS
→ Upper Tier HIT
→ 用户看到 HIT

德国:

Plaintext
德国 Lower Tier MISS
→ Upper Tier HIT
→ 用户看到 HIT

法国:

Plaintext
法国 Lower Tier MISS
→ Upper Tier HIT
→ 用户看到 HIT

于是从 origin 的角度看:

同一个 cache key 在这一轮缓存生命周期里,可能只需要第一次真正回源阿里云杭州。

后面虽然不同 lower-tier Edge 都经历过自己的 local MISS,但它们可以直接从 upper tier 获得内容。

这也正是 Tiered Cache 能大幅减少 origin request 的原因。(Cloudflare Docs)

当然,这不代表一个 URL 永远只会有一次真正 MISS。

以下情况都可能再次触发真正回源:

  • 主动 purge;
  • TTL 到期;
  • upper tier 缓存被 eviction;
  • cache key 改变;
  • upper tier assignment 发生变化;
  • origin / DNS / topology 变化。

Cloudflare 也明确说明,如果 Smart Tiered Cache 重新选择了 upper tier,新 upper tier 需要重新填充缓存,因此可能暂时增加 MISS rate。(Cloudflare Docs)


这也解释了为什么我自己的 Production 会突然快很多

我的 Production verifier 并不是普通用户。

它会从正式公网 runner 请求:

Plaintext
首页
课程页面
Angular partial
sitemap 中的 105 个 URL
缓存状态
browser 页面

没有 Tiered Cache 时可能是:

Plaintext
verifier

某个 Cloudflare Edge

MISS

直接回源阿里云杭州

于是每碰到一个新的 Edge / cold object,都可能重新经历一次不稳定的跨区域回源。

Smart Tiered Cache 开启后则可能有两种情况。

第一种:

Plaintext
Lower Tier MISS
→ Upper Tier HIT
→ 根本不访问杭州

第二种:

Plaintext
Lower Tier MISS
→ Upper Tier MISS
→ 由选定的 Upper Tier 回源杭州

第二种虽然仍然真正访问源站,但已经不是任意 lower-tier Edge 去访问,而是 Cloudflare 为这个 origin 选择的 upper tier。

所以 Production verifier 自己也直接受益。

不过这里我不想凭现有 evidence 断言:

之所以变快,主要是因为 Upper Tier 已经全部 HIT。

我没有逐个请求掌握足够 evidence 去计算:

Plaintext
多少请求是 Upper Tier HIT
多少请求是真正由 Upper Tier 回源

能够确认的是:

开启 Smart Tiered Cache 之后,同类 fresh MISS 的表现明显改善。


开启之后:之前失败的 fresh MISS 变成了 10/10 成功

开启 Smart Tiered Cache 后,我重新测试了此前出问题的 Angular partial fresh MISS。

结果:

Plaintext
10/10 HTTP 200

单次大约:

Plaintext
0.3~0.4 秒
【图 4:Smart Tiered Cache 优化后的正式记录】
【图 4:Smart Tiered Cache 优化后的正式记录】

这与此前真实观察到:

Plaintext
约 21.8 秒才成功

形成了非常明显的反差。

后来我把 Smart Tiered Cache 正式记录进当前 Production baseline。

不过这里还是需要保持一个边界:

21.8 秒,是之前实际出现过的一次异常 cold MISS;

0.3~0.4 秒,是开启之后那一轮 10 次 fresh MISS 复测。

这足以让我判断:

Smart Tiered Cache 非常值得保留。

但不能因此写成:

Smart Tiered Cache 永久把访问延迟从 21.8 秒优化成了 0.3 秒。

这不是严格控制变量的 benchmark。


我没有配置 Alibaba Cloud 的 Cloud Region Hint

Cloudflare 现在还支持针对部分 public cloud origin 设置 cloud region hint。

这样可以直接告诉 Smart Tiered Cache:

origin 属于哪一家云厂商、哪个 region。

但 Cloudflare 当前官方列出的 provider 是:

  • AWS
  • GCP
  • Azure
  • Oracle Cloud

没有 Alibaba Cloud。(Cloudflare Docs)

所以我的阿里云杭州源站没有配置:

Plaintext
Alibaba Cloud Hangzhou

之类的 region hint。

当前就是让 Smart Tiered Cache 使用 Cloudflare 自己采集的 latency / routing data 去选择 upper tier。

从目前实际结果看,这已经够用了。


Smart Tiered Cache 不会消灭 MISS

开启之后,真实 Production 发布仍然可以看到:

Plaintext
CDN /: MISS -> HIT -> HIT PASS
CDN /tour/welcome/1: MISS -> HIT -> HIT PASS
【图 5:真实 Production 中的 MISS → HIT → HIT】
【图 5:真实 Production 中的 MISS → HIT → HIT】

这是很正常的。

我每次发布新的 release 后都会正式 purge 对应 hostname cache。

Cloudflare 官方说明,按 hostname purge 后,后续请求通常会重新出现 MISS;使用 Tiered Cache 时也可能出现 EXPIRED,具体取决于 lower tier、upper tier 的状态以及请求落到哪里。(Cloudflare Docs)

所以:

Plaintext
MISS
→ HIT
→ HIT

本身并不说明 Tiered Cache 没有作用。

真正要关注的是:

这个 MISS 最后有没有真的到 origin。

有了 Tiered Cache 之后:

Plaintext
Lower Tier MISS

已经不能简单理解成:

Plaintext
必须回源阿里云杭州

开启 Smart Tiered Cache 后,为什么仍然会有 curl exit 28?

更有意思的是:

Smart Tiered Cache 已经开启之后,今天真实 Production 中还是发生了一次:

Plaintext
curl exit 28
HTTP-000

出现在荷兰语站 nl-NL 的 sitemap verification。

【图 6:开启 Smart Tiered Cache 后仍发生的一次瞬态 timeout】
【图 6:开启 Smart Tiered Cache 后仍发生的一次瞬态 timeout】

第一次:

Plaintext
attempt=1/5
reason=curl-exit-28
HTTP-000

第二次:

Plaintext
attempt=2/5 PASS

最终:

Plaintext
sitemap URLs: 105/105
host mismatch: 0
HTTP failure: 0

PRODUCTION MACHINE ACCEPTANCE: PASS

这正好说明:

Smart Tiered Cache 不是网络稳定性的魔法开关。

Internet 上依然可能存在:

Plaintext
连接建立超时
短暂丢包
节点瞬态异常
路由变化
CDN 内部波动

因此我之前做的 bounded retry 并没有失去意义。

只是它和 Smart Tiered Cache 解决的是两个不同层次的问题。


Smart Tiered Cache 与 bounded retry,是两层完全不同的优化

现在我更倾向于把它们这样理解。

第一层:

改善真实用户也会经历的网络架构。

Smart Tiered Cache:

Plaintext
减少真正可以访问 origin 的 Edge 数量
+
提高 Upper Tier HIT 概率
+
由更适合 origin 的 Upper Tier 负责真正回源

第二层:

让 Production 自动化能够容忍不可避免的瞬态错误。

bounded retry:

Plaintext
短暂失败
→ 有限次数重试
→ 恢复则继续
→ 耗尽仍然 fail closed

前者能够真正改善网站用户面对 cold MISS 时的体验。

后者主要提高我自己的部署与验收成功率。

两者不能互相替代。


为什么我没有继续无限增加 timeout?

理论上还有一种最简单的解决办法:

Plaintext
25 秒不够
→ 改成 60 秒

5 次 retry 不够
→ 改成 10 次

总有机会成功。

但这种做法我现在越来越不喜欢。

如果真正的问题是:

Plaintext
CDN 配错
源站挂了
证书错误
Nginx 异常
release 错误

等得更久并不会增加可靠性。

只会让真正的故障更晚暴露。

所以当前原则仍然是:

Plaintext
bounded timeout
+
bounded retry
+
fail closed

瞬态错误可以吸收。

确定性错误不能靠不停重试蒙过去。


为什么最终没有迁服务器,也没有换 CDN?

回过头看,这次其实是一次很典型的工程取舍。

我原本已经在考虑:

Plaintext
A. 把源服务器迁到海外 zgocloud

B. 非中文语言站全部从 Cloudflare 切回 EdgeOne

这两个方案并不是错误方案。

在某些情况下,它们甚至可能才是最终解。

但是对我目前这个项目来说:

迁移海外 origin 改动太大,还涉及我没有完全确认清楚的备案与接入问题;

全部切回 EdgeOne,则意味着放弃当前 Cloudflare Free 的成本优势,随着语言数量增加,长期 CDN 开销也会继续增加。

相比之下:

Plaintext
继续保留当前架构
+
开启 Smart Tiered Cache

几乎没有改变我的 Production 基线。

而真实结果已经明显改善了最困扰我的 cold MISS。

所以至少在当前阶段,我没有必要为了这个问题立刻做更大的架构迁移。


这个问题为什么特别容易被日常监控忽略?

我觉得这次最值得记录的,不只是 Smart Tiered Cache 这个开关。

而是:

CDN 会让源站网络问题变得非常不明显。

假设网站绝大多数请求都是:

Plaintext
HIT

日常看到的可能一直是:

Plaintext
HTTP 200
很快
很稳定

但真正影响:

Plaintext
发布之后
缓存 purge 之后
新 URL 第一次访问
冷门资源第一次访问
缓存自然失效之后

的是 MISS。

所以现在如果我要判断一个 CDN 架构是否真的稳定,不会只测试:

Plaintext
已经 HIT 的首页

还会专门观察:

Plaintext
fresh MISS

因为二者测试的根本不是完全相同的东西。

HIT 更多是在测试:

Plaintext
Cloudflare Edge 提供已有缓存的能力

MISS 才真正可能暴露:

Plaintext
Cloudflare 整个缓存层级
+
Cloudflare 到我的真实 origin

发生了什么。


从“两层”变成“三层”,反而让我重新理解网络优化

以前我很自然会觉得:

Plaintext
用户 → Edge → Origin

一定比:

Plaintext
用户 → Lower Tier → Upper Tier → Origin

更直接,所以应该更快。

这次之后我越来越觉得:

这种理解太简单了。

网络性能真正重要的不是:

Plaintext
一共经过几个节点

而是:

Plaintext
每一段路径质量如何
最差的路径在哪里
能不能避免真正走到最差路径

如果新增的那一跳主要发生在 Cloudflare 自己网络内部,却换掉了一个质量不稳定的:

Plaintext
任意 Edge → 阿里云杭州

那么多一跳完全可能反而更快。

而且如果 Upper Tier 已经 HIT:

Plaintext
Origin 请求甚至直接消失

这才是 Tiered Cache 真正有意思的地方。


最后:Lower Tier MISS,不代表源站一定被访问

如果要从这次排障中留下两句话,我现在会选择:

Cloudflare HIT 很快,并不代表 Cloudflare 回源同样稳定。

以及:

开启 Tiered Cache 后,Lower Tier MISS 已经不再等于 Origin MISS。

我的实际过程大概是:

Plaintext
Cloudflare HIT:
平时看起来完全正常

cold MISS:
曾出现约 21.8 秒才成功

不断增加 retry:
提高了自己的 Production 成功率
但无法真正改善网站用户体验

考虑迁海外 origin:
改动大,还有备案/接入问题需要确认

考虑全部切 EdgeOne:
技术可行,但长期成本更高

最终:
继续使用 Cloudflare Free
开启 Smart Tiered Cache

开启之后:

Plaintext
此前出问题的 Angular partial fresh MISS
→ 10/10 HTTP 200
→ 单次约 0.3~0.4 秒

而 Tiered Cache 带来的变化不只是:

Plaintext
减少直接回源的 Edge 数量

还包括:

Plaintext
Lower Tier MISS
→ Upper Tier HIT
→ 用户仍可看到 HIT
→ Origin 根本不参与

以及:

Plaintext
Lower Tier MISS
→ Upper Tier MISS
→ 由 Smart Tiered Cache 选择的 Upper Tier
→ 真正访问阿里云杭州

当然,它依然不会让 Internet 永远没有故障。

真实 Production 中仍然偶尔会看到:

Plaintext
curl exit 28
→ bounded retry
→ recovered

所以我最终保留的是三层思路:

Plaintext
Smart Tiered Cache
改善回源架构

bounded retry
吸收短暂公网波动

fail closed
保证真正错误不会被自动化掩盖

对于我目前这个“Cloudflare Free + 中国大陆阿里云杭州源站”的多语言项目来说,这已经是一次改动很小、成本几乎不变,但实际效果非常明显的优化。

从同步 Go 官方上游到一个命令发布 10 个语言站:A Tour of Go Production 流程的再次收敛

A Tour of Go 多语言翻译项目

本系列完整记录 A Tour of Go 多语言翻译项目从架构设计、整页翻译、结构保护、自动校验,到生产发布与后续维护的实际开发过程。

项目入口:
Brazilian Portuguese — Português (Brasil)
Dutch — Nederlands
French — Français
German — Deutsch
Italian — Italiano
Japanese — 日本語
Korean — 한국어
Simplified Chinese — 简体中文
Spanish — Español
Turkish — Türkçe
✅ 项目源码:GitHub:shuijingwan/go-tour-i18n

项目正在持续扩展更多语言版本,并长期维护翻译质量、生产发布与后续更新。项目属于非官方社区多语言翻译项目,与 Go 官方无隶属或授权关系。