Cloudflare 的温柔陷阱
Cloudflare 的温柔陷阱
Cloudflare 很好用。好用到它会让人产生一种错觉:既然 Workers 可以跑业务逻辑,KV 可以放状态,Durable Object 可以做协同,Analytics Engine 可以写指标,那是不是一个小型后端系统也可以顺手全塞进去?
我最近在开发 rsshub-balancer 时,就被这个问题坑了
背景:一个 RSSHub 负载均衡器
这个项目的目标并不复杂:给多个 RSSHub 实例做一层轻量转发。请求进来以后,先看哪个上游已经有目标路由的缓存,优先转发到那个上游;如果没有缓存,就按健康情况和失败记录选择一个上游
这类 L7 的轻量 LB,一想就会觉得很适合放在 Cloudflare 上。它处理的是 HTTP 请求,不需要碰 TCP / UDP 连接调度;逻辑主要是改写 URL、转发请求、读一点状态、做一点并发合并;入口又天然离用户越近越好
最初这个设计放在 Cloudflare Workers 上非常自然:
- Workers 负责边缘入口和转发
- KV 存上游实例列表和短 TTL 的失败标记
- Durable Object 合并跨 isolate 的并发请求,避免过多重复请求打到上游
- Analytics Engine 记录相关数据
突发的高账单
Cloudflare 的付费计划会给人一种很踏实的感觉:赛博菩萨的额度很大方,如果每个月多花 5 刀看起来有根本用不完的额度,对于一个小项目来说,这些东西甚至有点过于豪华
以这个项目为例,一个请求不只是转发一次。它会读上游列表,读失败标记;上游失败时,还要再写一个短 TTL 标记。业务请求看着不多,背后的状态读写却被放大了。
这些操作单独看都很轻。一次 KV 读、一次 KV 写、一次 DO 调用,在写代码的时候几乎没有重量感。直到它们被放进每个请求的路径里,账单才开始提醒我:轻量不等于免费。
rsshub-balancer 在 5 月初,日均请求只有 10-20k 次,但是 KV 的日均读 180k 次,日均写 50k 次
按 30 天粗略换算一下,就是每月 540 万次读、150 万次写。这个请求量本身根本不大,甚至只能算一个小项目刚开始有真实使用。但按照当时对 KV 的使用方式,写入量已经会超过 Workers Paid plan 里 KV 的月度包含额度,后面就会进入额外计费。
于是就产生账单了。上面只是为了直观粗算 KV,实际上 DO 和 KV 叠在一起,让我收到了相比平时四倍左右的账单

超出额度后会非常贵
Cloudflare 的免费额度和 Workers Paid plan 内的包含额度都很好,小项目起步时几乎不用考虑机器、数据库和运维。
真正的问题在超额之后。Cloudflare 的托管服务按调用、读写、存储、请求分别计费,超过包含额度后,每一次额外操作都会继续计数。
KV 是最直观的例子。额度内它很舒服,但读写超出 plan 后,成本曲线就和自托管 Redis / Valkey 或一台小 VPS 很不一样。
当然,按量付费本来就是 Serverless 托管服务的共性。问题不在于它按量计费,而在于这个“量”的单价实在太高。
KV 超出额度后,每 1 million 次写入要 5 美元。作为对比,AWS ElastiCache for Valkey node-based on-demand 的 cache.t4g.micro 在 us-east-1 约 0.0128 美元/小时,规格是 2 vCPU / 0.5 GiB,折算下来每月大约 9 美元
就算保守到假设这台机器每秒只能处理 1 次写入,一个月也有约 259 万次写入;同样的写入量放到 Cloudflare KV 上,超额费用就要 15 美元。Cloudflare KV 的性能和边缘集成当然更好,也有最终一致性的设计,但对一个普通应用来说,这个价格还是太贵了。
不过这个似乎是云服务商的通病,计算很便宜,其他托管的服务(数据库、消息队列、缓存)都不便宜,之前看不少文章说过,就是存储太贵了,不少厂家在下云
Workers 像小服务器,但不是小服务器
Cloudflare Workers 的心智模型很容易误导人。你写的是 TypeScript,模块级变量也能复用,nodejs_compat 甚至让你可以使用一部分 Node 能力,于是它看起来像一台很小、很快、离用户很近的服务器。而且不需要管怎么部署,太爽了
但它不是。Workers 最大的差异不是语法,而是没有一个真正属于你的常驻进程。
这件事比看起来影响更大。现在计算机世界里很多后端生态,默认前提都是“你有一个一直活着的进程”:它可以持有连接池,可以攒计数器,可以定期 flush 指标,可以暴露 /metrics,可以在内存里维护一点临时状态。到了 Workers 里,这些默认假设都要重新审视。
Worker isolate 的生命周期由平台管理。它可能冷启动,可能被冻结,可能恢复,也可能被调度到不同地方。模块级变量可以复用,但它更像“如果这个运行时还活着,优先复用一下”,不是传统意义上的进程内长期状态。
Redis 连接
外部 Redis / Valkey 这类服务通常依赖 TCP/TLS 长连接。传统后端可以用常驻进程维护连接池,慢慢摊平建连成本;Workers 里则更像是在一个平台调度的短生命周期运行时里,尽量复用一段不稳定的连接。
网络延迟、冷连接、服务端 idle timeout、跨地域访问,都可能进入用户请求路径。更麻烦的是,超时处理本身也可能放大抖动。为了避免复用卡住的连接,超时后销毁 client 是合理的;但如果外部服务短时间抖动,高并发请求可能同时触发超时、销毁、重连,再把问题扩大成连接风暴。
这时候问题已经不是“某一次 Redis 慢了”,而是 Serverless 运行时和外部有状态服务的模型不匹配。Cloudflare 把入口做得很轻,但这个轻入口一旦挂上外部连接型资源,就会把连接管理、超时和重试策略都暴露出来。
可观测性
可观测性也会被“没有常驻进程”影响。传统后端里,你可以在进程里维护计数器,定期上报指标,或者直接暴露 Prometheus endpoint。Workers 里没有这样一个稳定进程,内存计数只能算当前 isolate 的临时状态,随时可能消失,也不能代表全局。
所以很多计数只能在请求发生时手动写出去:写日志,写 Analytics Engine,或者写数据库。这样当然能解决问题,但它会把观测本身也变成一次显式的远程写入,带来成本、延迟和失败处理。你不能像在一台常驻服务器上一样,默认有个进程替你在后台慢慢攒、慢慢 flush。
Cloudflare 的观测工具不是没有用。Workers Logs、Analytics Engine 都能提供不少信息。但它们和传统后端里的 Prometheus、长期 tracing、进程级 profiling、连接池指标不是一回事。这也是 Serverless 的一个隐性成本:你省掉了服务器,也省掉了一部分你平时依赖服务器才能看到和维护的内部状态。
外部依赖会让平台边界显形
如果一个系统完全在 Cloudflare 生态内部闭环,体验通常是顺的。Workers 调 KV、DO、R2、D1、Analytics Engine,虽然每个产品都有自己的边界,但至少调用模型和平台预期是一致的。
这也是一种隐性的 vendor lock-in。刚开始你只是顺手用了几个平台组件,代码也写得很自然;等到想迁出去时,才发现运行模型、状态存储、后台任务、指标、日志、权限和计费方式都已经和 Cloudflare 绑在了一起。不是完全迁不走,而是每拆一块都会牵出一串平台假设。
一旦把关键路径接到外部托管资源上,事情就微妙起来。Workers 仍然是短生命周期、平台调度的边缘运行时;外部数据库、缓存、队列仍然假设客户端能稳定建连、复用连接、处理 socket 生命周期。两边都没错,但它们中间有一条缝。
这条缝在低流量时几乎看不见。等到请求路径分散、并发上来、外部服务偶发慢一下,它就会变成日志里的 timeout、fallback、重连和各种运行时告警。
这些问题会让 Cloudflare 的边界变得更清楚:它很适合做边缘入口、轻量编排、缓存附近的逻辑和一些低复杂度状态;但不要把它想象成一台可以无限堆后端能力的小服务器。
原生产品能力未必够用
Cloudflare 的原生产品集成体验很好,但不代表每个产品都足够好用,尤其是当你开始把它当成系统基础设施来依赖时。
Metrics 是一个很典型的例子。Workers Analytics Engine 可以直接在 Worker 里写指标,不用自己搭 Prometheus 和 Grafana,这一点很方便。但真正查数据时,它更像是在查一张事件表:指标名、label、状态码、耗时都要塞进 blob1、blob2、double1、double2 这类固定字段里,查询时再靠 SQL 手动解释回来。
而且它的统计还是近似的,查询时还要记得用 _sample_interval 修正采样。像 docs/metrics.md 里查最近 24 小时合并收益,只是算几个分类占比,就已经需要一大段 sumIf、嵌套查询和手动百分比计算。
这和 PromQL 的体验差很多。PromQL 天然围绕 time series、label、rate、increase、分位数、聚合窗口这些场景设计,表达“过去 5 分钟请求速率”“按 label 聚合错误率”“某个分位延迟”很顺。Analytics Engine 当然也能查出很多东西,但 SQL 方言和函数支持都有限,很多常见指标分析要自己绕。
所以 Cloudflare 原生产品的优势是接入快、少运维、和 Workers 贴得近;缺点是能力边界很快会出现。排障和简单报表够用,但如果想把它当成完整可观测性平台,就会发现它没有 Prometheus / Grafana 那套生态来得顺手。