我们的智能体会话跑在 Cloudflare Durable Objects(下文简称 DO)上。前几天排查一个会话反复被平台重置的问题时(完整过程见《一次智能体会话内存超限的排查记录》),我们发现自己对 DO 的内存上限理解得并不对,于是部署了一个一次性的探针去实测。这篇只记录测到的结果和测的方法。

先说明范围:这是 2026 年 10 月 26 日在我们自己账号上的一次实测,不是官方说明。平台的实现随时可能变化,数字仅供参考,建议在自己的环境里复测。

为什么要测

文档写的上限是 128 MB。可我们在生产上看到的情况对不上:有会话的内存读数记录到 141 到 167 MB,却并不是每次越过 128 MB 都被重置。如果上限真是严格的 128 MB,这解释不通。我们需要知道到底什么情况会被杀,才能定优化目标。

怎么测

我们部署了一个临时的 Worker,里面只有一个 DO 类,接受几种请求:

  • 制造垃圾:在一次请求里反复分配、丢弃大块内存,总分配量很大,但同一时刻只保留很少的存活数据;
  • 持有数据:分配一块随机二进制或不重复的字符串,并挂在 DO 实例的字段上,让它一直存活;
  • 累积持有:对同一个对象多次发请求,每次多持有一块,存活数据逐步累积。

每次请求之后,我们用 Cloudflare 的 GraphQL 分析接口读这个对象的内存读数和超限次数:

durableObjectsPeriodicGroups(filter: { namespaceId: $ns, datetimeFiveMinutes_geq: $from }) {
  dimensions { datetimeFiveMinutes objectId }
  max { memoryUsageBytes }
  sum { exceededMemoryErrors }
}

同时看 Worker 的日志里有没有平台的重置记录。测完之后,这个 Worker 就删掉了。

测到的结果

场景 结果
一次请求里累计分配 2000 MiB 垃圾,同时存活只有约 4 MiB(中间有 await 和完全同步两种写法都测了) 存活
持有 110 MiB、140 MiB 随机二进制 存活
持有约 100 MiB、200 MiB 不重复的字符串 存活
同一个对象分几次请求累积持有 60 → 120 → 180 → 240 MiB 存活;GraphQL 读数 254 MiB,超限次数 0
一次请求里分配并持有 300 MiB 请求返回 1101;日志 Durable Object's isolate exceeded its memory limit and was reset.

我们从中得出的几点

一、实际的重置线不是 128 MB。 读数到 254 MiB 时进程仍然活着,持有 300 MiB 被重置。所以至少在我们测的这次,重置线落在 254 到 300 MiB 之间。我们没有继续往中间收窄,这个区间是目前知道的全部。

二、决定生死的是同一时刻存活的数据量,不是分配速度。 一次请求里分配 2 GB 垃圾都没事,只要回收得掉。这一点改变了我们找问题的方式:不再关注「谁分配得多」,而是找「哪几份数据在同一时刻活着」。我们的会话就是因为一条很大的工具输出在处理过程中同时存在四五份副本,才越过了线。

三、平台记录的峰值是下界。 造成重置的那次分配,GraphQL 永远采样不到,因为进程在下一次采样之前就已经被重置了。记录下来的是「死前最后一次采样」。拿生产上记录到的峰值去推算上限,会推得偏低。

四、读数可能不是这个对象自己的。 在测试环境里,我们看到同一个 5 分钟桶里有七个不同的 DO 报出完全相同的内存峰值。多个 DO 可能运行在同一个运行环境里,读到的是整个环境的内存。这意味着单个对象的读数要谨慎解读,一个对象用多了,也可能连累邻居。

五、平台日志里有明确的死因。 被重置时,平台会记一行 Durable Object's isolate exceeded its memory limit and was reset.。它不在你自己代码打的日志流里,但在 Workers 的日志里能查到。按这一行告警,比等 GraphQL 的 5 分钟桶更及时,也能直接定位到是哪个对象。

我们现在怎么用这些结果

  • 设计目标留余量。 我们按「同一时刻存活的数据」来估算每个会话的峰值,目标远低于测到的 254 MiB,也不依赖 128 MB 这个数字;同一运行环境里可能还有别的会话,余量要留给它们。
  • 外来的大块内容不进 DO。 工具输出、文件这类大小不可控的内容设字节上限,超出的部分留在外面,DO 里只放引用或头尾。
  • 两路监控。 GraphQL 的 exceededMemoryErrors 用来看趋势和统计;平台日志里的那一行用来即时告警。

如果你也在 DO 上跑内存占用比较大的工作负载,我们的建议是自己测一次。探针很简单,半小时就能写完,测完删掉,比靠文档里的数字估算可靠得多。

开始构建你的服务智能体
Sean

Praxis 知行云创始人。