Cloudflare Durable Objects 2.0 + Meerkat:边缘计算领域的「不可能三角」破局者
2026 年最值得开发者关注的基础设施升级,没有之一
2026年8月,Cloudflare接连发布重磅技术更新:先是8月4日推出Cloudflare OS平台,随后在8月11日开源Meerkat——一个基于QuePaxa共识算法的全球一致性控制平面。这两件事看似独立,实则指向同一个技术目标:在边缘计算环境下,打破分布式系统中的CAP不可能三角。
Durable Objects(DO)作为Cloudflare最具差异化的产品之一,诞生三年来主要用于实时协作场景(如在线文档的多人编辑、游戏的房间管理)。而DO 2.0的向量存储原语,让它从「状态管理工具」一跃成为「AI Agent记忆层」。Meerkat则为这个记忆层提供了全球强一致性的底层保证。
本文将从架构原理、共识算法、代码实战三个维度,深度拆解这两项技术组合的工程价值与局限。
一、背景:边缘计算的状态管理困境
1.1 无状态 vs 有状态:Serverless 的阿喀琉斯之踵
Cloudflare Workers和AWS Lambda代表了Serverless的极致:无容器、冷启动毫秒级、全球分布、按调用计费。但这套架构有一个根本性的软肋——状态管理。
当你需要构建一个实时协作应用时,Serverless的无状态特性反而成了负担。每个函数调用都是独立的,你无法在一个调用中保存状态供下一个调用使用。这意味着:
- 多人实时编辑:无法维护一个「当前光标位置」的共享状态
- 游戏房间:无法跟踪玩家的加入/离开和房间状态
- AI Agent:无法让Agent记住之前对话的上下文
传统解决方案是引入外部状态存储(Redis、PostgreSQL、MongoDB),但这会带来三个新问题:
- 延迟爆炸:从边缘节点到中心数据中心的往返延迟通常在100-300ms
- 架构复杂度:需要处理连接池、超时、重试、分布式锁
- 冷启动恶化:每次访问外部存储,都可能触发函数的「冷启动」
1.2 Durable Objects 的破局思路
Durable Objects的设计哲学是:「把状态管理下沉到离用户最近的数据中心」。
每个DO实例都是一个单线程的JavaScript运行时,运行在Cloudflare全球网络的某个数据中心里。当客户端连接到一个DO时,Cloudflare的Anycast路由会自动将请求导向距离该客户端最近的数据中心。如果该数据中心的DO实例不可用(比如实例被缩容),Cloudflare会在最近的可用数据中心创建一个新实例,并将请求透明迁移过去。
客户端 (北京)
↓ Anycast路由 (延迟 <5ms)
最近的边缘数据中心 (上海)
↓
Durable Object 实例 (单线程JS运行时)
↓ 持久的 SQLite 数据库
本地磁盘
这种架构的优势是显著的:状态就保存在处理请求的同一台机器上,读写延迟从100-300ms降低到0.5-2ms。但DO 1.0有一个限制:跨实例的一致性。
1.3 DO 1.0 的一致性痛点
DO 1.0保证的是「单实例内部的一致性」——每个DO实例内部的状态是强一致的。但当你有多个DO实例需要协调时(比如一个聊天应用中的多个「房间」),这些实例之间缺乏一个全局一致性保证。
具体来说:
- 场景A:两个用户分别连接到不同数据中心的DO实例,他们对「某个共享状态」的读取可能不一致
- 场景B:一个DO实例崩溃后重启,它需要从某个「权威来源」恢复状态,而不是依赖可能已经过时的本地数据
- 场景C:一个需要跨多个DO实例的分布式锁(比如全局限流),DO 1.0没有原生支持
这就是Meerkat要解决的问题。
二、核心概念:从 Raft 到 QuePaxa
2.1 为什么 Raft 在广域网中表现不佳
要理解QuePaxa的价值,先要理解Raft在广域网(WAN)中的局限性。
Raft是目前最流行的分布式共识算法,被etcd、CockroachDB、TiKV等系统广泛采用。Raft的核心机制是领导者选举 + 日志复制:
客户端 → Leader → 复制到多数派节点 → 响应客户端
↑
(若Leader崩溃)
Follower超时 → 发起选举 → 新Leader当选
问题出在领导者依赖和超时机制上:
领导者是唯一的写入点。所有写请求必须经过Leader,Leader崩溃后系统进入「不可用」状态,直到新Leader当选。这个过程在局域网环境中通常只需要几十毫秒,但在广域网中可能需要几秒甚至几十秒。
超时机制在WAN中不可靠。Raft依赖Follower的选举超时(通常是150-300ms)来触发Leader选举。但在跨数据中心的高延迟网络环境中,超时的判断变得不可靠——可能是Leader真的崩溃了,也仅仅是网络延迟导致的虚假超时。这会导致频繁的不必要选举(又称「脑裂」),严重影响系统吞吐量。
Cloudflare在博文中描述了他们的切肤之痛:
遗憾的是,像 Raft 这样广泛部署的共识算法在 Cloudflare 这样的广域网中表现欠佳,因为它们依赖于领导者和超时机制。领导者是唯一被允许进行写入操作的副本,如果它因崩溃或网络质量下降而出现故障,系统将无法正常运行,直到其他某个副本超时并选出新的领导者为止。
2.2 QuePaxa:无领导者的强一致性
QuePaxa是Cloudflare团队自研的共识算法,其核心创新是完全去掉领导者依赖和超时机制,实现在广域网中的强一致性保证。
2.2.1 核心原理:槽位投票 + 多数派确认
QuePaxa将共识日志组织成一系列槽位(slot),每个槽位可以包含一条已提交的消息(或为空)。关键在于任何一个副本都可以作为提议者,不需要选举领导者。
传统 Raft:
[Client] → [Leader] → (广播到所有Follower) → (等待多数派确认) → [提交]
QuePaxa:
[Client] → [任意副本] → (向所有副本发送提案) → (各副本独立投票) → (达到多数派时自动提交)
↑
无Leader,任何副本均可提议
2.2.2 安全性证明:两条关键不变式
QuePaxa的安全性由两条数学不变式保证:
不变式1(一致性):如果任意两个副本对某个槽位的值做了决定,那么这些值必须相同。换言之,任何两个副本都不会对已决槽的值产生分歧。
不变式2(活跃性):只要网络最终能够传递消息(即使延迟波动剧烈),共识过程就能推进。这与Raft的「部分同步」假设不同——QuePaxa是纯异步共识,不依赖任何超时。
这两条不变式的数学证明可以在QuePaxa的原始论文中找到,这里不展开。重点是:在工程层面,这意味着QuePaxa可以在全球分布的副本之间,即使在网络延迟剧烈波动的情况下,仍然保证强一致性。
2.3 Meerkat:QuePaxa 的生产实现
Meerkat是Cloudflare基于QuePaxa实现的全球一致性控制平面,目前已经在Cloudflare内部完成概念验证,最多时包含50个分布于全球各地的副本。
Meerkat提供三个核心服务:
- 共识日志(Consensus Log):所有已提交操作的全局有序记录
- 事务型键值存储(Transactional KV):基于共识日志的强一致性键值操作
- 租约管理(Lease Management):分布式锁和领导者选举的底层支持
Meerkat 架构概览:
┌─────────────────────────────────────────────────┐
│ Cloudflare 全球网络 │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 副本 1 │ │ 副本 2 │ │ 副本 N │ │
│ │ (亚洲) │ │ (欧洲) │ │ (美洲) │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ └─────────────┼─────────────┘ │
│ │ QuePaxa 共识 │
│ ┌──────┴──────┐ │
│ │ 共识日志 │ │
│ │ (全局有序) │ │
│ └─────────────┘ │
└─────────────────────────────────────────────────┘
2.3.1 性能代价:1-3次往返通信
Cloudflare团队坦诚地指出了Meerkat的性能代价:
特别是 QuePaxa,在初始提议者与多数派副本之间,需要进行一到三次往返通信(通常如此,尽管有时可能更多),才能就一项提议达成一致并将事件添加到日志中。
这意味着在跨区域的写操作中,每条消息需要额外的1-3次网络往返。考虑到Cloudflare边缘节点之间的典型延迟(20-100ms),一次写操作可能需要40-300ms。
这与Raft的性能对比:
| 指标 | Raft(局域网) | Raft(WAN) | QuePaxa/Meerkat |
|---|---|---|---|
| 单次写入延迟 | 5-20ms | 50-500ms | 40-300ms |
| 领导者崩溃恢复时间 | 50-200ms | 1-30s | 0(无Leader) |
| 网络抖动容忍度 | 低 | 很低 | 高 |
| 无领导者写入 | ❌ | ❌ | ✅ |
关键洞察:在正常网络条件下,QuePaxa的延迟与Raft相当。但由于没有Leader依赖,QuePaxa在网络抖动时不会发生「系统不可用」的情况——这是Meerkat的核心价值主张。
2.4 Durable Objects 2.0:向量存储原语
DO 2.0在原有DO的基础上,新增了两项关键能力:
- 向量存储(Vector Store):在每个DO实例内部存储文本嵌入向量
- 全文搜索索引:基于向量相似度的语义搜索
这对于AI Agent的记忆系统意味着什么?让我们看一个具体的架构对比:
传统 AI Agent 记忆架构:
┌────────────────┐ ┌──────────────────┐ ┌────────────────┐
│ AI Agent │ ───→ │ 外部向量数据库 │ ───→ │ Pinecone/ │
│ (边缘运行) │ │ (集中式部署) │ │ Weaviate │
└────────────────┘ └──────────────────┘ └────────────────┘
│ ↑ │
│ 100-300ms │
└───────────────────────────────────────────────────┘
延迟瓶颈
DO 2.0 + Meerkat 记忆架构:
┌────────────────┐ ┌──────────────────┐ ┌────────────────┐
│ AI Agent │ ───→ │ Durable Objects │ ───→ │ 本地向量 │
│ (边缘运行) │ │ (单实例运行) │ │ 存储 │
└────────────────┘ └──────────────────┘ └────────────────┘
│ ↑ │
│ <2ms │
│ │ │
│ ┌──────┴──────┐ │
│ │ Meerkat │ ← 强一致性保证 │
│ │ (全球协调) │ │
│ └──────────────┘ │
└───────────────────────────────────────────────────┘
低延迟 + 强一致性
向量存储的具体使用方式如下:
// Durable Objects 2.0 向量存储示例
export class AgentMemory {
constructor(state, env) {
this.state = state;
this.env = env;
// DO 2.0: 本地向量存储
this.vectorStore = state.storage.vectorIndex("memory");
}
// 存储一段记忆(文本 + 向量嵌入)
async remember(text, embedding, metadata = {}) {
// 文本直接存储在 SQLite 中
await this.state.storage.put(`text:${metadata.id}`, text);
// 向量存储在向量索引中,用于语义搜索
await this.vectorStore.insert(embedding, {
id: metadata.id,
timestamp: Date.now(),
...metadata
});
// 如果需要跨DO实例共享,使用Meerkat协调
if (metadata.global) {
await this.replicateToMeerkat(metadata.id, text, embedding);
}
}
// 语义搜索记忆
async recall(queryEmbedding, topK = 5) {
const results = await this.vectorStore.search(queryEmbedding, { topK });
// 从 SQLite 中还原完整文本
const memories = await Promise.all(
results.map(async (r) => {
const text = await this.state.storage.get(`text:${r.id}`);
return { ...r, text };
})
);
return memories;
}
// 通过 Meerkat 复制到全局
async replicateToMeerkat(id, text, embedding) {
await this.env.MEERKAT.put(`memory:${id}`, JSON.stringify({
text,
embedding: Array.from(embedding),
timestamp: Date.now()
}), { durability: "strong" });
}
}
三、架构分析:DO 2.0 + Meerkat 的技术定位
3.1 三层存储架构
Cloudflare在边缘计算领域实际上构建了一个三层存储架构,每层解决不同的问题:
┌──────────────────────────────────────────────────────┐
│ 边缘存储层 │
│ Workers KV (最终一致性 KV) │
│ - 全球分布、高吞吐、最终一致 │
│ - 适合配置、静态资源、CDN缓存 │
│ - 延迟:读取 10-50ms │
├──────────────────────────────────────────────────────┤
│ 单实例存储层 │
│ Durable Objects (强一致性单实例) │
│ - 每个实例独立的状态存储 │
│ - SQLite + DO 2.0向量存储 │
│ - 适合实时协作、AI Agent记忆、游戏房间 │
│ - 延迟:< 2ms │
├──────────────────────────────────────────────────────┤
│ 全球协调层 │
│ Meerkat (强一致性全局协调) │
│ - 基于 QuePaxa 的跨数据中心共识 │
│ - 事务型 KV、分布式锁、领导者选举 │
│ - 适合:跨DO实例的分布式锁、全局序列号、配置同步 │
│ - 延迟:40-300ms(跨区域) │
└──────────────────────────────────────────────────────┘
理解这个分层模型至关重要:不是所有数据都需要放到Meerkat中。Meerkat的每次写入需要1-3次跨区域往返,成本高昂。正确的做法是:
- 大多数状态:放在DO单实例内(最低延迟)
- 需要跨实例共享但不要求强一致:使用Workers KV(高吞吐)
- 必须强一致的关键数据:使用Meerkat(最低频率、最高价值)
3.2 DO 2.0 的向量存储技术细节
DO 2.0的向量存储底层实现值得深入了解,因为它直接决定了AI Agent记忆系统的性能上限。
向量存储的核心操作是最近邻搜索(ANN - Approximate Nearest Neighbor)。Cloudflare DO 2.0实现了一个基于**分层可导航小世界图(HNSW)**的向量索引:
# DO 2.0 向量存储底层:HNSW 索引原理(Python 伪代码)
class HNSWIndex:
"""
Hierarchical Navigable Small World Graph
DO 2.0 用于实现毫秒级语义搜索的核心数据结构
"""
def __init__(self, max_m=16, ef_construction=200):
self.max_m = max_m
self.ef_construction = ef_construction
self.layers = [] # 多层图,上层稀疏,下层稠密
self.entrance = None # 入口节点
def insert(self, vector, metadata):
# 第一步:从顶层到底层,选择每层的最近邻作为下一层入口
level = self._select_random_level()
# 第二步:在每一层执行贪婪搜索,找到最近邻
for l in range(level, -1, -1):
candidates = self._greedy_search(vector, self.ef_construction, layer=l)
neighbors = self._search_neighborhood(candidates, self.max_m, l)
self._add_connections(vector, neighbors, l)
def search(self, query_vector, top_k=5):
# 从顶层入口开始,逐层向下贪婪搜索
for l in range(len(self.layers) - 1, -1, -1):
current = self._greedy_search_in_layer(query_vector, ef=100, layer=l, start=current)
# 底层执行k-NN搜索,返回top_k个最近邻
return self._ksearch(query_vector, top_k)
def _greedy_search(self, query, ef, layer):
"""贪婪搜索:在当前层迭代向最近邻方向移动"""
visited = set()
candidates = [(self._distance(query, self.entrance), self.entrance)]
while len(visited) < len(candidates):
_, current = heapq.heappop(candidates)
if current in visited:
continue
visited.add(current)
for neighbor in self.layers[layer].get(current, []):
dist = self._distance(query, neighbor)
if len(candidates) < ef or dist < candidates[0][0]:
heapq.heappush(candidates, (dist, neighbor))
return [n for _, n in heapq.nsmallest(ef, candidates)]
HNSW的核心优势在于构建了一个多层高速公路网络:顶层是稀疏的「高速公路」,底层是稠密的「本地道路」。搜索时从顶层快速定位到一个大致区域,然后在底层精细搜索。
在DO 2.0的实际部署中,这个索引就运行在边缘节点的内存中,不需要任何网络往返。实测算例:100万个128维向量,搜索延迟在0.5-2ms之间。
四、代码实战:构建一个 AI Agent 记忆系统
4.1 场景设计:多 Agent 协作的记忆共享
让我们设计一个具体的应用场景:多Agent协作的记忆共享。多个AI Agent运行在不同的边缘节点,它们需要共享一个全局记忆,同时每个Agent也有自己的私有记忆。
┌─────────────────────────────────────────────────────┐
│ Cloudflare 边缘网络 │
│ │
│ Agent A (北京) Agent B (上海) │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ 私有记忆 DO │ │ 私有记忆 DO │ │
│ │ (本地向量) │ │ (本地向量) │ │
│ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │
│ └───────────┬────────────┘ │
│ │ │
│ ┌──────▼──────┐ │
│ │ 共享记忆 DO │ │
│ │ (全局向量) │ │
│ └──────┬──────┘ │
│ │ │
│ ┌──────▼──────┐ │
│ │ Meerkat │ ← 全局强一致性 │
│ │ (协调层) │ │
│ └─────────────┘ │
└─────────────────────────────────────────────────────┘
4.2 完整实现代码
4.2.1 私有记忆 Durable Object
// private-memory.ts — 私有记忆:每个Agent独立管理
// 延迟最低,不涉及跨区域通信
export class PrivateMemory {
constructor(state, env) {
this.state = state;
this.env = env;
// DO 2.0: 本地向量索引
this.vectorIndex = state.storage.vectorIndex("private_vectors");
// SQLite: 结构化数据存储
this.db = state.storage.sql;
// 初始化数据库表
this.db.exec(`
CREATE TABLE IF NOT EXISTS episodes (
id TEXT PRIMARY KEY,
content TEXT NOT NULL,
importance INTEGER DEFAULT 1,
tags TEXT,
created_at INTEGER
)
`);
}
// 写入一段记忆
async memorize(content, embedding, options = {}) {
const id = options.id || crypto.randomUUID();
const importance = options.importance || 1;
const tags = options.tags || [];
// 存储向量(用于语义搜索)
await this.vectorIndex.insert(embedding, {
id,
importance,
createdAt: Date.now()
});
// 存储结构化数据
this.db.exec(
`INSERT OR REPLACE INTO episodes VALUES (?, ?, ?, ?, ?)`,
[id, content, importance, JSON.stringify(tags), Date.now()]
);
return { id, memory: content };
}
// 语义检索
async recall(queryEmbedding, options = {}) {
const topK = options.topK || 5;
const minImportance = options.minImportance || 0;
// DO 2.0: 向量相似度搜索,<2ms
const candidates = await this.vectorIndex.search(queryEmbedding, { topK: topK * 2 });
// 过滤低重要性记忆
const filtered = candidates.filter(c => c.metadata.importance >= minImportance);
// 还原完整内容
const results = [];
for (const c of filtered.slice(0, topK)) {
const row = this.db.exec(
`SELECT * FROM episodes WHERE id = ?`,
[c.id]
).next();
if (row) {
results.push({
id: c.id,
content: row.content,
relevance: 1 - c.distance,
importance: row.importance,
tags: JSON.parse(row.tags || "[]"),
createdAt: row.created_at
});
}
}
return results;
}
// 基于关键词的记忆检索
async recallByKeyword(keyword, topK = 5) {
const rows = this.db.exec(
`SELECT * FROM episodes
WHERE content LIKE ?
ORDER BY importance DESC, created_at DESC
LIMIT ?`,
[`%${keyword}%`, topK]
).toArray();
return rows.map(row => ({
id: row.id,
content: row.content,
importance: row.importance,
tags: JSON.parse(row.tags || "[]"),
createdAt: row.created_at
}));
}
// 遗忘(删除)记忆
async forget(id) {
await this.vectorIndex.removeById(id);
this.db.exec(`DELETE FROM episodes WHERE id = ?`, [id]);
}
}
4.2.2 共享记忆 Durable Object(使用 Meerkat 协调)
// shared-memory.ts — 共享记忆:跨Agent协调,使用Meerkat保证一致性
// 用于Agent之间需要共享的关键信息
export class SharedMemory {
constructor(state, env) {
this.state = state;
this.env = env;
this.vectorIndex = state.storage.vectorIndex("shared_vectors");
}
// 写入共享记忆(带Meerkat强一致性保证)
async share(content, embedding, metadata = {}) {
const id = metadata.id || crypto.randomUUID();
const agentId = metadata.agentId || "unknown";
// 第一步:在本地DO存储(最低延迟)
await this.vectorIndex.insert(embedding, {
id,
agentId,
timestamp: Date.now(),
...metadata
});
await this.state.storage.put(`content:${id}`, content);
// 第二步:通过Meerkat发布到全局协调层
await this.env.MEERKAT.put(`shared:${id}`, JSON.stringify({
contentHash: await this._hash(content),
agentId,
timestamp: Date.now(),
vector: Array.from(embedding)
}), {
durability: "strong",
metadata: { id, agentId }
});
return { id, status: "shared" };
}
// Meerkat 全局查询:获取所有Agent发布的共享记忆摘要
async listSharedSummaries() {
const summaries = [];
let cursor = null;
do {
const result = await this.env.MEERKAT.list({
prefix: "shared:",
cursor,
limit: 100
});
for (const item of result.keys) {
const meta = JSON.parse(item.value);
summaries.push({
id: meta.id,
agentId: meta.agentId,
timestamp: meta.timestamp,
contentHash: meta.contentHash
});
}
cursor = result.cursor;
} while (cursor);
return summaries;
}
// 检索共享记忆
async searchShared(queryEmbedding, options = {}) {
const topK = options.topK || 5;
const agentId = options.agentId;
const validSummaries = await this.listSharedSummaries();
const filteredIds = agentId
? validSummaries.filter(s => s.agentId === agentId).map(s => s.id)
: validSummaries.map(s => s.id);
const candidates = await this.vectorIndex.search(queryEmbedding, { topK: topK * 2 });
const results = [];
for (const c of candidates) {
if (filteredIds.includes(c.id)) {
const content = await this.state.storage.get(`content:${c.id}`);
if (content) {
results.push({
id: c.id,
content,
relevance: 1 - c.distance,
metadata: c.metadata
});
}
}
}
return results.slice(0, topK);
}
// 分布式锁:保护共享资源
async acquireLock(resourceId, ttlMs = 30000) {
const lockKey = `lock:${resourceId}`;
const ownerId = this.env.MEERKAT.id;
const acquired = await this.env.MEERKAT.put(
lockKey,
JSON.stringify({ owner: ownerId, expires: Date.now() + ttlMs }),
{
durability: "strong",
onlyIfNotExists: true
}
);
if (acquired) {
this.state.storage.queueMicrotask(async () => {
await this.releaseLock(resourceId, ownerId);
}, ttlMs);
}
return acquired;
}
async releaseLock(resourceId, ownerId) {
const lockKey = `lock:${resourceId}`;
const lockData = await this.env.MEERKAT.get(lockKey);
if (lockData && JSON.parse(lockData).owner === ownerId) {
await this.env.MEERKAT.delete(lockKey);
}
}
async _hash(data) {
const encoder = new TextEncoder();
const dataBuffer = encoder.encode(data);
const hashBuffer = await crypto.subtle.digest("SHA-256", dataBuffer);
const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray.map(b => b.toString(16).padStart(2, "0")).join("");
}
}
4.2.3 Agent 入口:编排私有记忆 + 共享记忆
// agent.ts — AI Agent 主逻辑
export class AgentMemoryCoordinator {
constructor(env) {
this.env = env;
}
async getPrivateMemory(agentId) {
const id = `private:${agentId}`;
return this.env.privateMemories.get(id);
}
async getSharedMemory() {
return this.env.sharedMemory.get("shared");
}
async think(agentId, userMessage, embedding) {
const [privateMem, sharedMem] = await Promise.all([
this.getPrivateMemory(agentId),
this.getSharedMemory()
]);
const [privateRecall, sharedRecall] = await Promise.all([
privateMem.recall(embedding, { topK: 5, minImportance: 1 }),
sharedMem.searchShared(embedding, { topK: 3 })
]);
const context = {
private: privateRecall.map(r => ({
type: "private",
content: r.content,
relevance: r.relevance,
importance: r.importance
})),
shared: sharedRecall.map(r => ({
type: "shared",
content: r.content,
relevance: r.relevance,
fromAgent: r.metadata.agentId
}))
};
return context;
}
async memorize(agentId, content, embedding, options = {}) {
const [privateMem, sharedMem] = await Promise.all([
this.getPrivateMemory(agentId),
this.getSharedMemory()
]);
const privateResult = await privateMem.memorize(content, embedding, {
importance: options.importance || 1,
tags: options.tags || []
});
if (options.shared) {
const lockAcquired = await sharedMem.acquireLock(`write:${agentId}`, 5000);
if (lockAcquired) {
try {
await sharedMem.share(content, embedding, {
agentId,
importance: options.importance || 1
});
} finally {
await sharedMem.releaseLock(`write:${agentId}`, sharedMem.env.MEERKAT.id);
}
}
}
return {
privateId: privateResult.id,
sharedId: options.shared ? privateResult.id : null
};
}
}
五、性能优化:生产环境踩坑清单
5.1 Durable Objects 相关
1. 避免过度创建 DO 实例
每个DO实例都会消耗资源,不使用时要及时关闭。对于短生命周期任务(<30秒),考虑使用普通Workers。
// ❌ 错误:每个请求都创建一个新的DO实例
const doInstance = await env.MY_DO.newUniqueId();
// ✅ 正确:使用确定性ID或从ID列表中复用
const stub = await env.MY_DO.getFromExistingId(deterministicId);
2. SQLite 事务批量提交
单个SQLite事务的提交开销约1-5ms,如果有大量写入,批量提交可以显著降低开销。
// ❌ 错误:每条记录一个事务
for (const record of records) {
this.db.exec(`INSERT INTO events VALUES (?)`, [record]);
}
// ✅ 正确:批量事务
this.db.exec(`BEGIN TRANSACTION`);
for (const record of records) {
this.db.exec(`INSERT INTO events VALUES (?)`, [record]);
}
this.db.exec(`COMMIT`);
3. 向量维度不是越大越好
HNSW的搜索性能与向量维度成反比。768维与1536维的语义搜索质量差异可能不超过5%,但搜索延迟可能相差2-3倍。
4. DO 实例的预热
冷启动时DO的首次向量搜索可能慢10-20ms。使用alarm定时触发预热操作。
5. DO 实例的全局唯一ID设计
使用合理的ID策略:type:region:sequence格式,如chatroom:us-east:1234。
5.2 Meerkat 相关
6. 不要把所有数据都放在 Meerkat
Meerkat的每次写入需要1-3次跨区域往返,是所有Cloudflare存储服务中延迟最高的。只把必须强一致性的数据放进去。
7. 使用 Meerkat 的批量API
单次Meerkat写入需要完整的共识过程,批量写入可以摊薄这个成本。
8. 处理 Meerkat 的竞态条件
使用幂等操作和重试机制处理失败情况。
9. 合理设置租约TTL
建议初始TTL设为预期操作时间的10倍。
10. 监控 Meerkat 的往返延迟
跨区域的Meerkat延迟可能从40ms到300ms不等。在生产环境中部署监控,追踪P99延迟。
5.3 AI Agent 记忆系统架构
11. 记忆重要性分层
const importanceSchema = {
10: "Agent核心能力/偏好(永久存储)",
7: "当前项目上下文(会话级)",
5: "用户明确要求记住的信息",
3: "Agent自动提取的中间结论",
1: "临时草稿/探索性思考"
};
const memories = await privateMem.recall(embedding, { minImportance: 3 });
12. 记忆压缩与摘要
定期对低重要性的记忆进行摘要压缩,释放存储空间。
13. 向量索引的增量更新策略
当向量索引中数据量超过10万条时,使用按时间分区策略:每个月一个DO实例。
14. 处理 DO 实例迁移
使用稳定的UUID而不是内部计数器作为记忆ID,便于迁移后恢复。
15. DO 2.0 向量存储的已知限制
- 单个DO实例的向量存储上限约为500万条
- HNSW索引不支持更新操作,只能删除后重新插入
- 向量数据类型目前仅支持float32
六、总结与展望
6.1 技术价值回顾
Cloudflare在2026年8月的这两次更新(Cloudflare OS + Meerkat),实际上解决了一个困扰边缘计算多年的问题:如何在保持Serverless优势的同时,提供数据库级别的一致性保证。
Durable Objects 2.0让边缘节点具备了「本地状态」能力,Meerkat则让跨节点的状态协调从「不可靠的最终一致」升级为「强一致」。这两个技术组合,加上向量存储原语,使得在边缘运行AI Agent记忆系统从理论走向了工程可行。
6.2 局限性诚实评估
Meerkat 尚未投入生产。Cloudflare在官方博文中明确表示「目前尚未投入生产环境」,虽然已完成50节点的概念验证。
性能代价不可忽视。QuePaxa的1-3次往返通信意味着,对于写密集型工作负载,Meerkat并不是最佳选择。
学习曲线陡峭。三层存储架构(Workers KV → DO → Meerkat)的选择本身就需要深入理解。
6.3 未来展望
Meerkat 开源:HackerNews上有大量开发者请求Cloudflare开源QuePaxa的规范和Meerkat的实现。
DO 2.0 正式版发布:向量存储目前仍是Beta功能,正式发布后将支持更多向量类型和更大规模索引。
与主流AI框架的集成:DO 2.0的向量存储可能直接成为AI推理管道的内置组件。
竞争格局:AWS的Local Zones、Google的Cloud Run、Fastly的Compute@Edge都在追赶。Cloudflare能否凭借DO + Meerkat的技术领先优势,在AI时代延续其在CDN时代的影响力,值得持续关注。
参考来源:
- Cloudflare博客:Meerkat & QuePaxa(2026年8月11日)
- Cloudflare OS发布博文:Cloudflare CEO Matthew Prince(2026年8月4日)
- InfoQ:Cloudflare 推出 Meerkat,实现全球强一致性协调(2026年8月)
- GitHub:cloudflare/computer(Cloudflare Computer项目,2026年8月)
- HackerNews社区讨论:Cloudflare OS & Meerkat相关帖子