Fletch:在可编程交换机里缓存分布式文件系统元数据

Fletch:在可编程交换机里缓存分布式文件系统元数据

📄 论文解读

Fletch: File-System Metadata Caching in Programmable Switches Qingxiu Liu, Jiazhen Cai, Siyuan Sheng, Yuhui Chen, Lu Tang, Zhirong Shen, Patrick P. C. Lee arXiv:2510.08351v3 · 2026 年 5 月 · 17 页 GitHub: https://github.com/adslabcuhk/fletch

一句话核心

把 HDFS 的元数据缓存从客户端搬到可编程交换机数据平面里,用 P4 写到 Tofino, 直接在网络关键路径上吸收读请求,把一致性维护从 O(N) 降到 O(1),同时用 “in-switch 集中化"天然吸收热点请求、缓解后端负载倾斜。

为什么需要它

  • 百度 AI Cloud 文件系统请求 67–96% 是元数据;Yahoo HDFS 3% 文件承担 34–39% 请求——访问严重倾斜。
  • 客户端缓存三大痛点:
    1. 一致性维护 O(N),每次写要通知所有客户端;
    2. 客户端缓存各自为战,没法协同消除后端负载倾斜;
    3. 现有方案(IndexFS / InfiniFS)只能缓存目录权限,attribute 仍要回 server。
  • 可编程交换机正好相反:处在所有 client↔server 关键路径上,集中化天然解决这两 个问题——一致性 O(1),热点天然吸收。

三大关键技术

技术做什么
路径感知缓存管理 (§IV)缓存一条路径必同时缓存它所有祖先;用 CMS 估频 + frequency counter 精确统计;淘汰按"无后代且频率最低"递归淘汰祖先
多级读-写锁 (§V)8 个 lock counter array(按路径层级分配),每个 64K 槽 16-bit;validation flag 1-bit 标记有效;靠 recirculation 让 PHV 沿路径层层处理
本地哈希冲突解决 (§VI)64-bit MD5 + 8-bit token = (hash, token);controller 同步 token 给 switch / server / client;避免每次问 controller

多级锁 P4 拆解

下面是基于论文 §V 推演的 P4 风格伪代码——P4_16 没有循环/递归,多级路径解析靠 packet recirculation(一次处理一层,再把包送回 ingress)。

数据结构

// === Lock counter arrays: 8 组,每组 64K 槽 × 16-bit ===
register lock_array_1 { Width: 16; Size: 65536; }  // level 1: /a
register lock_array_2 { Width: 16; Size: 65536; }  // level 2: /a/b
register lock_array_3 { Width: 16; Size: 65536; }  // level 3: /a/b/c
// ... 共 7 个;level 8+ 共享 lock_array_8

// === Validation flags: 1 bit / cached path ===
register validation { Width: 1; Size: <hash_space>; }

// === Cache values ===
register cache_value_lo { Width: 32; Size: <num_slots>; }
register cache_value_hi { Width: 32; Size: <num_slots>; }

读路径(单路径读,如 open/stat)

每一层都要:① 加锁 → ② 校验 → ③ 权限检查 → ④ 通过则去下一层 → ⑤ 上一层解锁。 整个流程靠 recirculation 实现:

action process_level() {
    lvl = cur_level;
    idx = hash_low16_at_level(lvl);  // 从 PHV 取预计算的 hash

    valid = validation.read(idx);
    if (valid == 1) {
        lock_val = lock_array_X.read(idx);
        lock_array_X.write(idx, lock_val + 1);   // 读锁:counter += 1

        meta = read_cache(idx);
        if (!permission_check(meta)) {
            failed = 1; fail_level = lvl;
        }
    } else {
        failed = 1; fail_level = lvl;             // 失效或正在写
    }

    if (lvl > 1) release_lock(lvl - 1);            // 释放上一层锁

    if (cur_level < depth && !failed) {
        cur_level = lvl + 1;
        recirculate();                              // 处理下一层
    } else {
        release_lock(lvl);                          // 释放最后一层
        if (!failed) send_response_to_client();     // packet cloning 直返
        else        forward_to_server();
    }
}

写路径(单路径写,如 chmod/chown)

action process_write() {
    idx = hash_low16_at_level(depth_of_target);
    cur = lock_array_X.read(idx);
    if (cur > 0) { recirculate(); return; }         // spin-wait 直到归零
    validation.write(idx, 0);                       // 独占
    forward_to_server();                            // write-through
}

action on_write_response() {
    if (success) update_cache(idx, new_metadata);
    validation.write(idx, 1);                       // 不论成败都恢复可读
    // 用 sequence number 防 ACK 丢失造成的 lock 双重 decrement
    send_ack_to_server();
}

写饥饿隐患(论文自陈): reader-preferring,写等待时新读会持续 ++counter, 写永远等不到锁。这是 Fletch 当前明确遗留的限制。

多路径写(chmod -R)的 top-down 技巧

父路径的 validation 一直 = 0,直到所有 cached 后代都更新完才置 1, 任何中途到来的读都会被拦下、走 server,永远读不到"父已更新、子未更新"的混合状态。

P4 实际写不出来的部分——“循环"怎么落地

逻辑P4 实现
解析 level 1..depth每个 PHV 包最多 recirculate depth + 1
按层级选不同 lock_arrayingress pipeline 里根据 cur_level 做 if-else
每个 memory block 每次只能访问一次把 lock_array / validation / cache_value 放在不同 pipeline 阶段

关键实验数字(128 模拟 server)

负载Fletch 相对 NoCacheFletch+(加客户端缓存)相对 CCache
Alibaba+11.0%+14.7%
Training+134.6%+103.6%
Thumb+181.6%+139.6%
LinkedIn+71.2%+57.3%
  • 延迟:读密集场景 @ 0.26 MOPS,Fletch 把 NoCache 的 avg / p95 / p99 降 64.6% / 89.8% / 87.7%
  • 交换机资源:SRAM 58.4% / Stage 100% / ALU 98% / PHV 93%——比 NetCache / FarReach 略高,但还能用。
  • 恢复时间:server 0.5–2.1 s / controller < 40 ms / switch 14.6–75.5 s(最慢,要 replay admission)。

论文自陈的局限

  • 写饥饿未解决(reader-preferring lock,writer 可能永远拿不到锁)
  • 写密集负载掉链:chmod > 50% 时吞吐开始跌
  • PHV 已用到 93%,再加功能就撞资源墙
  • 强假设:root 永久缓存、permissions 不变
  • 多交换机拓扑未讨论,目前只跑了一台 Tofino

我的判断

思路对、实现完整、评估扎实。但有两个工程隐患值得注意:

  1. 写饥饿是真实部署的雷区,生产环境如果 chmod / rename 多就会卡;
  2. PHV 93% 离天花板很近,未来想加任何 feature 都会撞资源墙。
Figure 4: Example of processing a read request under multi-level read-write locking

参考资料