Cloudflare 于 2026 年 10 月 9 日推出 Workers 和 Durable Objects 的按需 CPU、内存分析。开发者可以在控制台请求一次采集,查看交互式火焰图,也能下载 profile 文件进一步分析。
这给生产排障补上了更具体的证据:CPU 都花在什么调用链里,哪些代码正在大量分配内存。不过,Heap profile 并不是存活对象快照,按需采集也不会还原过去的请求。正确选择版本、实例和采集窗口,比拿到一张火焰图后立刻优化最宽的函数更重要。
日志说明发生了什么,采样帮助定位资源花在哪里
一次请求超过预期耗时,可能是计算昂贵,也可能是在等待网络或存储。看到内存错误,同样不代表已经知道是哪个模块造成的。日志和聚合指标可以指出现象,但通常不能直接给出函数级资源分布。
这次发布提供两种 profile。CPU profile 用于识别消耗 CPU 时间的函数;控制台中的 Heap profile 则记录采集期间的内存分配。官方文档说明,后者每分配 512 kB 内存采样一次调用栈。
| 诊断输入 | 适合回答的问题 | 不能据此直接得出的结论 |
|---|---|---|
| 请求日志和聚合指标 | 哪些请求失败、何时异常、资源走势怎样 | 哪个函数承担了全部资源开销 |
| CPU profile | 采集期间哪些调用链占用较多 CPU | 整个请求的等待时间都由这些函数造成 |
| Heap profile | 采集期间哪些调用链分配了较多内存 | 这些内存仍然存活,或已经证明存在泄漏 |
排障时,这些证据应当互相补充。比如某个接口延迟高,但 CPU profile 没有明显热点,就应继续检查等待和依赖服务,而不能只在 JavaScript 函数里寻找答案。
采集已有实例,不会替你启动一次请求
Workers 在不同数据中心和物理服务器上运行。即使同一个版本,也可能存在多个运行实例;Durable Objects 还涉及有状态对象的定位和迁移。
官方公告描述的采集流程,需要先找到最近运行过目标版本的位置,并确认 isolate 仍然加载。普通 Worker 会选择一个正在运行的 isolate,而不是把所有地区、所有副本汇成一张全局 profile。Durable Object 则可以指定目标实例,将请求路由到对应的运行位置。
这决定了结果的代表性。一次采集里的热点,可能反映该实例在当时处理的流量,不应直接推成整个应用在所有地区的固定比例。多次采集、记录版本和业务场景,通常比只看一张图更有帮助。
平台目前不会为了生成 profile 启动一个新 isolate,也不会因为点击采集按钮就主动调用业务代码。目标 Worker 或 Durable Object 需要在采集前和采集期间有流量。测试环境若没有请求,应先准备能够覆盖相关代码的受控请求;生产环境则要确认选中的版本确实正在服务业务。
CPU 采样期间正常请求仍能运行
Cloudflare 公告解释了 CPU 采集的实现过程:运行时取得 isolate 及其锁,创建 V8 CPU profiler,并以一毫秒间隔开始采样;随后释放锁,让正常请求继续执行。到达指定时长后,再取得锁停止采样,并在临界区之外序列化结果。
这个设计避免在整个采集窗口内占着 isolate 锁。否则,JavaScript 无法继续运行,拿到的结果也就失去了观察真实执行的价值。
但“采集期间继续服务请求”不等于“分析工具零开销”。本文引用的资料没有给出适用于所有业务的统一开销比例,采用前仍应观察代表性负载下的表现,并控制采集频率。
火焰图的宽度不是时间轴
控制台中的矩形表示采样调用栈里的函数,宽度按 profile 类型表示 CPU 时间或分配内存的比例。横向位置不表示函数在什么时候执行,不能把它当成请求时间线来读。
表格视图还区分 Self 和 Total。前者不包含后代函数,后者包含后代调用。一个调用入口看起来很宽,可能只是它调用的子函数成本高;判断修改位置时,应继续沿调用链向下看。
对于内存分析,更要避免把“分配多”和“保留多”混为一谈。Heap profile 记录的是窗口内的分配,无法说明这些对象随后是否被释放,也不是对象引用关系快照。一个函数不断创建短命对象,可以造成很高的分配量,却不必然持续积累存活内存。
公告还指出,采集窗口之外的分配看不到。如果大量分配发生在启动阶段,而采集时实例已运行一段时间,按需 profile 可能错过它。历史日志的时间范围和过滤条件也不会改变这个事实:采集观察的是当前窗口,不会回放日志里的旧请求。
latest 不一定是正在运行的版本
平台提供控制台、cf CLI 和 API 三种入口。官方文档允许采集时长为 1000 至 50000 毫秒,控制台默认 10000 毫秒,并支持选择 CPU 或 Heap profile。
在已安装并登录 cf、确认账号和权限后,可以参考下面的 CPU 采集示例。两个大写占位符需要替换为实际运行版本的 UUID 和 Worker 名称,本文没有执行这条命令。
1 | cf workers versions profile YOUR_RUNNING_VERSION_UUID \ |
这里特意使用运行版本标识。文档说明,CLI 和 API 中的 latest 选择最新创建的版本,不保证它已经部署。如果刚上传一个版本却没有发布,照抄 latest 可能找不到可采集的运行实例。
CLI 将二进制 pprof 数据写入标准输出,可以保存后用兼容工具分析;API 返回 gzip 压缩的 pprof。采集请求也受速率限制,收到 429 后应等待,并遵循存在的 Retry-After 响应头,不要不断重试。
Durable Object 的 CLI 采集还需要指定 namespace 和实例 ID,并选择拥有该 namespace 的 Worker,不能只选一个通过 binding 调用它的 Worker。控制台中则应进入相应 namespace 和目标实例,确认它有流量并正在运行所选版本。
TypeScript 或压缩后的 JavaScript 项目,还应按官方文档准备 source map。否则 profile 中的函数名和代码位置可能难以对应原始实现。使用 Wrangler 的项目可以核对 upload_source_maps 配置;这一步需要纳入自己的构建与部署流程,本文不会修改任何实际 Cloudflare 项目。
优化之后,仍要用同类流量复核
Cloudflare 公告给出一个 R2 binding Worker 的 CPU 案例:某个 JSON replacer 已经被 JSON.stringify 逐节点调用,却又自行遍历树,形成重复工作。采样把这条路径暴露出来,代码检查才进一步确认原因。
这里值得借鉴的是证据链。先从资源分布找到候选,再看实现是否存在重复计算或不必要分配,修改后用相近的流量和采集条件复核。不能只因为某个框很宽,就推断删掉它会让整体性能按同样比例提升。
对于内存错误,还应同时看异常次数、内存指标和分配变化。减少分配可以改善压力,却不能单独证明泄漏已经解决。业务输出、错误率和延迟也需要一并验证,避免以资源下降换来功能退化。
按需采集仍可能错过偶发问题。公告说 Cloudflare 正在开发持续性能分析,但这是后续方向,不能把它当作本次已经交付的能力。
结语
Workers 的生产 profile 让函数级资源分析更容易进入日常排障。它最有价值的用法,是把版本、运行实例、真实流量和采集结果关联起来,缩小需要检查的代码范围。
记住几个边界就能避免常见误判:CPU 时间不是整个请求耗时,分配内存不是存活内存,一次实例采样不是全局汇总,当前窗口也不是历史回放。带着这些限制看火焰图,再做有针对性的验证,优化才更有依据。
参考来源
- Cloudflare 10 月 9 日公告:Workers 与 Durable Objects 按需性能分析,用于核对发布时间、isolate 定位、CPU 采样机制及按需分析限制。
- Cloudflare Docs:Profiling in production,用于核对 Heap 分配采样、版本选择、采集时长、CLI/API 格式和火焰图指标。
- Cloudflare Docs:Source maps and stack traces,用于核对源映射用途与 Wrangler 配置。