我本来不想写这篇文章的,因为 Cloudflare 的文档写得太漂亮了,而且网上到处是推荐 R2 的软文。 但作为把公司图片服务从 S3 搬到 R2 再搬回来的人,我觉得有些事实必须说出来。 我们做的是一款面向海外用户的图片社区产品,每天上传大约 80 万张原图,读取缩略图超过 3 亿次。 在 AWS 上,最头疼的就是 S3 的流量费,高峰时一个月要为此付 4 万多美元。 所以当听说 R2 出口流量免费时,我几乎连夜写了迁移方案。
迁移的第一步就踩了坑。 R2 宣称兼容 S3 的 API,但我们用的 aws-sdk-go-v2 上传大文件时,一开始就遇到 ?partNumber 非法的问题。 查了半天才发现 R2 的分片上传并发限制和 S3 不一样,我们原来的并发数跑得飞起,在 R2 这边直接 500。 后来我把每片大小从 8MB 提到 32MB,并发从 12 降到 4,才算稳定。 这还没完,R2 对 ListObjectsV2 的排序规则与 S3 略有出入,导致我们之前依赖的游标分页出现重复项,最后不得不在应用层做去重。 总之,所谓兼容只是'能用',不是'一样'。
第二点是性能。 我们在 EC2 与 R2 之间上传一个 1GB 的测试文件,平均耗时 122 秒,而同样的文件传到 S3 只要 89 秒。 下载方面,从 EC2 下载 R2 的对象 TTFB 在 150ms 左右,S3 是 60ms,尤其致命的是我们很多场景需要直接让用户的浏览器访问 R2 的 URL,但 R2 的边缘缓存对 Cache-Control: no-cache 的响应特别容易回源,导致首字节时间直接飙到 1s 以上。 后来我试着在 R2 上开启 Cache Everything,可依然没法像 CloudFront 那样精确控制边缘行为。
然后是我新算的成本账。 R2 对外声称零出口费,但它的操作费用分 A/B 类,A 类是 PUT, POST, LIST,100 万次 4.50 美元;B 类 GET, HEAD,100 万次 0.36 美元,比 S3 的相应请求价格高了大约 30%。 存储单价也比 S3 标准存储贵 0.005 美元/GB。 我拿我们的真实数据做了 12 个月预测:如果月流量 10TB,R2 的总成本是 2350 美元,而 S3 + CloudFront 因为流量阶梯价格,总成本是 2870 美元,只差 18%。 但如果月流量到了 50TB,CloudFront 的流量价格降到 $0.03/GB,S3 方案反而比 R2 便宜 15%。 所以'零流量费'只是把费用藏到了别处。
现在如果你问我 R2 适合谁,我的答案和官方文档完全相反:适合那些读量极小、写一次就冷掉的存档数据,而不是热对象存储。 对于我们的缩略图场景,热点集中在前 5% 的图片,这 5% 贡献了 70% 的流量。 R2 的边缘缓存设计更适合静态大文件,而不是频繁变化的访问头。 我最后的做法是,把 R2 留作异地备份,S3 当主存储,CloudFront 做边缘缓存。 这样一个没有任何亮点的组合,反而比任何一个都稳。 可能这就是所谓的大厂技术 '所有美好的承诺都有后门',但我觉得不自己踩一遍,永远不知道门的钥匙在哪。