这事前后折腾了一个多月,最近终于算彻底结束了,简单记录一下。
我有一个开源的 WebRTC 项目,之前生产环境用过 Cloudflare RealtimeKit 。当时 RealtimeKit 还在 Beta ,官方 pricing 页面写的是 Beta 期间免费。8 月 19 日我发现 Cloudflare 账单里出现了 RealtimeKit participant usage ,一百多美元,于是开了一个 Urgent support case 。
我一开始以为这事应该很简单:既然 Beta 免费,为什么会产生账单?结果后来这个问题被一路拖进了 Engineering Investigation 。
因为费用还在继续增长,而且我没办法判断最终会涨到多少,我在那个周末把生产从 RealtimeKit 迁到了 Cloudflare Serverless SFU 。8 月 21 日之后,生产流量已经不再经过 RealtimeKit 。
比较奇怪的是,迁移以后 RealtimeKit 的 participant usage 还在继续增加,每天大约 $28-29 。
后来我直接调 RealtimeKit API ,把整个 App 的状态扫了一遍。一共是 2,440 个 Meetings 和 2,609 个 Sessions ,其中还有 12 个 Session 显示 LIVE ,里面正好有 10 个 live participants 。但是这 12 个 Session 对应的 Meeting 当时全部已经是 INACTIVE ,生产客户端也早就不存在了。有一些 Session 已经挂了很多天,最老的可以追溯到 8 月 1 日。
当时有一个数字很巧:
10 × 1,440 × $0.002 = $28.80 / day
而 Cloudflare 其中一天实际记出来的 participant usage 大约是 $28.76 。
这个当然只能说明高度相关,不能仅凭这个数字证明计费一定就是这些 stale participants 产生的。
最后我是自己调用 Cloudflare 官方的 active-session/kick-all 接口,把剩余的 participant 清掉。清理以后是 0 live participants ,所有 2,440 个 Meeting 都是 INACTIVE 。
后面 Cloudflare Engineering 确认过,客户端已经断开、Meeting 已经 INACTIVE ,但 Session 仍然保持 LIVE ,这不是 expected behavior 。客服还转述过 Engineering 的说法,说 session cleanup mechanism did not trigger as intended 。
他们当时给我的临时建议之一,是定期通过 automation 或 scheduled alarm 执行 kick-all 。这个建议我没有实际采用,因为生产已经完全迁走了,而且他们同时又要求我保留 App 给 Engineering 调查。
整个过程中还有一个让我比较困惑的地方,就是最开始那个最简单的 Beta billing 问题一直没有被单独回答。Support 不断在讲 Engineering review 、Session 、Participant 、Meeting ID ,我后来直接要求他们把两个问题分开:Session lifecycle 可以慢慢查,但请先回答 RealtimeKit Beta 到底应该收费还是不应该收费。
后来 Cloudflare 明确确认,Beta 期间这些 RealtimeKit usage 不应该收费。
两张账单最后分别退款 $143.53 和 $147.68 ,共 $291.21 ,已经全部到账。
这期间 Support 还发生过一次比较有意思的反复。客服先建议我考虑删除 RealtimeKit App 来停止可能继续产生的 usage ,没过多久 Engineering 又要求我千万不要删除,因为他们还需要这个 App 做调查。于是这个已经不用的 App 又保留了一个多月。后来 RealtimeKit 已经从 Beta 转成 GA ,开始正式收费,我又专门追问了一次为什么还要继续保留一个 billable GA App 。
直到最近,Cloudflare 才确认 Engineering review 已经完成,可以删除 App 。我已经把它删掉了。
最终技术结论也比较微妙。
Cloudflare 前面确认过 stale LIVE Session 属于异常状态,也说过 cleanup mechanism 没按预期触发。但最终 Engineering review 的结论是,没有识别到 underlying RealtimeKit platform defect ,因此没有 product fix 在跟踪。他们同时也没有认定 audio-only / Audio-Video participant classification 存在独立的 metering defect 。
所以比较准确的描述应该是:Cloudflare 确认当时观察到的 Session 状态不是预期行为,但一个多月的调查最后没有定位到可以归因的 RealtimeKit platform defect 或明确 root cause 。
我其实不太关心最后是哪一行代码出了问题。让我觉得这件事麻烦的主要是处理过程。
错误计费本身最后退款了,这部分没有经济损失。但为了一个并非由我造成的问题,我做了紧急生产迁移,自己检查了两千多个 Session ,自己清理 stale participant ,然后一个 support case 来回跟了一个多月。期间大部分时间没有明确 ETA ,也没有类似 incident owner 的角色来统一推进 Billing 、Product 和 Engineering 。
至少在我的经验里,production + billing 这种问题通常会比较快被当成 incident 处理:先隔离客户风险,再由相关团队并行调查。Cloudflare 这次给我的体验更像一个普通 support ticket 在几个团队之间来回转。
我以前对 Cloudflare 的印象一直不错,现在也还在继续用 Workers 、DO 、R2 、Serverless SFU 等服务。它对独立开发者的开发体验确实很好。
但这次以后,我会把“开发体验很好”和“生产运维成熟度很高”当成两件不同的事情。
Beta 产品有 bug 很正常。Billing 、metering 、incident escalation 这些东西最好不要也处于 Beta 。
现在这个项目已经完全迁到 Serverless SFU 。至少从我自己的使用场景来看,按实际 egress 计费,比 participant-minute 加 server-side session state 这种模型更容易理解风险。
