Meerkat:Cloudflare 在全球共识上的一次新实验

2026-07-08 33 预计阅读时间: 1 分钟
来源: blog.cloudflare.com AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:8 分钟

Cloudflare Research 正在构建一个名为 Meerkat 的全球共识服务,并为它设计了新的共识算法 QuePaxa。这个方向值得关注:一旦全球共识能以可用的延迟、故障模型和运维复杂度落地,它就不只是论文里的复制状态机,而会变成强一致键值存储、跨区域控制面、配置分发和协调服务的基础设施。

Meerkat 想解决的不是“存储”,而是“谁说了算”

来源摘要里提到,Meerkat 的目标之一是构建强一致、容错的 key-value store。这里的关键词不是 key-value,而是强一致和容错。

普通缓存或最终一致数据库可以接受短时间内不同节点读到不同值;但很多系统不能这么做。例如:

  • 全局唯一配置开关:同一时刻只能有一个真实值。
  • 租约和锁:两个区域不能同时认为自己持有同一把锁。
  • 账户、权限、路由规则:写入成功后,后续读不能绕回旧状态。

这类问题的底层抽象通常是共识:多个节点在网络延迟、节点故障、消息重试的情况下,对一串操作达成同一个顺序。KV 存储只是把这串操作表现成 PUT key valueGET keyDELETE key

Meerkat 的有趣之处在于它被描述为 global consensus service,而不是单机房或单区域协议实验。全球范围意味着延迟、分区、时钟偏差和区域级故障都会变得更尖锐。

QuePaxa 暂时应该被当作“新算法边界”,不是黑盒魔法

摘要只说明 QuePaxa 是 Meerkat 使用的新共识算法,没有给出它的协议细节。因此在工程判断上,不应该假设它一定替代 Raft、Paxos 或 Multi-Paxos 的所有场景。

更稳妥的理解是:Cloudflare Research 正在探索一个面向全球部署的共识层,QuePaxa 是这个探索里的核心算法。对使用者来说,真正需要观察的是这些问题:

  • 写入路径是否跨洲?多数派如何选择?
  • 读请求能否本地服务?在什么条件下仍然强一致?
  • 区域故障时,可用性如何变化?
  • API 是否暴露事务、条件写、版本号或 watch 语义?
  • 运维层面如何做成员变更、数据迁移和灾难恢复?

这些问题比“它是不是更快”更实际。全球共识的成本通常不会消失,只会被协议、拓扑和产品接口重新分配。

可以这样实践:用条件写模拟强一致 KV 的客户端姿势

下面的示例不是 Meerkat API,也不代表 QuePaxa 的真实接口。它是一个最小可运行的伪项目,用来演示强一致 KV 客户端通常需要的两个动作:读取版本、基于版本做条件写。以后如果 Meerkat 暴露类似能力,可以把 HTTP 地址和字段替换成真实 API。

保存为 kv_cas_demo.py 后运行:

from dataclasses import dataclass
from threading import Lock, Thread
from typing import Dict, Tuple


@dataclass
class Entry:
    value: str
    version: int


class StrongKV:
    def __init__(self):
        self._lock = Lock()
        self._data: Dict[str, Entry] = {}

    def get(self, key: str) -> Tuple[str | None, int]:
        with self._lock:
            entry = self._data.get(key)
            if entry is None:
                return None, 0
            return entry.value, entry.version

    def compare_and_set(self, key: str, expected_version: int, new_value: str) -> bool:
        with self._lock:
            current = self._data.get(key)
            current_version = current.version if current else 0
            if current_version != expected_version:
                return False
            self._data[key] = Entry(new_value, current_version + 1)
            return True


def enable_feature(kv: StrongKV, worker: str):
    value, version = kv.get("feature.checkout_v2")
    ok = kv.compare_and_set("feature.checkout_v2", version, "enabled")
    print(f"{worker}: read={value!r}@v{version}, write={'ok' if ok else 'conflict'}")


if __name__ == "__main__":
    kv = StrongKV()
    threads = [Thread(target=enable_feature, args=(kv, f"worker-{i}")) for i in range(4)]
    for thread in threads:
        thread.start()
    for thread in threads:
        thread.join()
    print("final:", kv.get("feature.checkout_v2"))

运行:

python3 kv_cas_demo.py

你会看到多个 worker 竞争写入同一个 key。由于示例运行在单进程里,锁模拟了“所有写入必须排队形成同一顺序”。真实的全球共识服务会把这个顺序扩展到多个节点、多个区域和不可靠网络中。

如果未来要把这类客户端姿势改造成 HTTP API,可以设计成这样:

curl -sS -X PUT "https://kv.example.internal/v1/keys/feature.checkout_v2" \
  -H "content-type: application/json" \
  -d '{"value":"enabled","expected_version":3}'

服务端应该只在当前版本仍为 3 时提交写入,否则返回冲突,例如 409 Conflict。这种接口能让调用方显式处理并发,而不是把冲突藏在“最后写入获胜”里。

适合关注的落地点

Meerkat 这类服务最适合出现在“写入不一定高频,但正确性很贵”的位置。比如全局配置、控制面元数据、分布式锁、集群成员信息、证书或路由状态。它不一定适合替代高吞吐日志、低延迟本地缓存或大规模分析存储。

采用前可以列一个短清单:

  • 是否真的需要强一致,而不是会话一致或最终一致?
  • 写入延迟是否能承受跨区域协调?
  • 故障时宁愿拒绝写入,还是接受分叉后修复?
  • 客户端是否准备好处理超时、重试、幂等和条件写冲突?
  • 数据模型是否足够小,能放在共识层的关键路径上?

Meerkat 还处于 Research 实验语境中,最合理的态度是跟踪它的协议、API 和故障语义,而不是立刻把所有状态都搬进去。全球共识是硬问题;如果它被做成可靠的服务,价值会很高,但每一次写入都应该知道自己为什么值得付出这笔协调成本。


相关推荐