Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

swiftfuse benchmark — chunk mode, 4-node etcd cluster

Environment: Contabo lab, 4 nodes (swift1-4, 8GB RAM), OpenStack Swift (cluster-wide throughput shared), etcd 3-node cluster (swift1-3), blocks 4 MiB, leases on, FUSE write-back on, prefetch 8 MiB, read/write workers 8/8, kernel_ttl = 0(正确性优先:内核每次 LOOKUP 重验;进程内 path/attr/dir 缓存仍在内存服务)。

数值口径(G11):kernel_ttl=0 下 stat 不再是“3ms 路径缓存“ 意义上的纯缓存命中—— 每次 stat 先走内核 LOOKUP(带 TTL=0 的 entry 回复),再由进程内 path_inodes 缓存命中后 0 次 etcd 往返。2026-08-09 G8 重跑后本节数值以 raw JSON 为准 (/opt/detect/results/20260809-full/g8/perf.json)。

Benchmark 2.0 framework(R7,2026-08-11)

scripts/benchmark.sh 已从 v1(纯 dd 序列)重写为 Benchmark 2.0 框架(R7 交付物)。 框架只负责运行与记录;R7 先交付框架本身,不跑 live benchmark。

工作负载分类(workload taxonomy,显式 phases)

workload内容默认
seq-write顺序写 BENCH_SIZE_MIB MiB(bs=BENCH_FIO_BS)256 MiB / 1M
seq-read顺序读同一文件256 MiB / 1M
rand-writeBENCH_RAND_WRITES × 4KiB 随机写(M1 object 放大探针)100
small-filecreate + stat + readdir,BENCH_SMALL_FILES 个 4K 文件1000
renameBENCH_RENAME_FILES 次 rename500
multi-node跨 BENCH_NODES 并发读/写(共享 FS,每节点 BENCH_MULTI_MIB)128 MiB

冷 / 温 / 混合分离(per-workload 分别记录)

  • cold = 新文件 + drop_caches(本地 + 各节点 ssh)+ dataset > cache。 local_seq_read 若必须 seed seq.bin,seed 之后立刻 sync + drop_caches。 GeeseFS / JuiceFS 的用户态缓存不受 drop_caches 影响:公平列用 FAIR_REMOUNT=1(写完 persist、umount、清 JuiceFS --cache-dir、再 drop_caches、再 remount)。GeeseFS 在本 lab 的 s3api 上要用 --single-part 80,默认 multipart 不会落地。
  • warm = 数据已入 cache、100% 缓存命中路径(不 drop_caches,重复 pass);
  • mixed = 交错负载:IO 用 fio rwmixwrite/rwmixread(70/30), metadata 用 create+stat+readdir 融合单 pass;multi-node = 一半读一半写。

确定性输出

每次运行写入 $RESULTS_ROOT/bench2.0-<UTC ts>-<commit8>/(结果在本地盘; 被测数据在挂载点 $BENCH_ROOT/$RUN_ID 下,避免结果写入污染被测路径): meta.json(运行元数据+config env)、summary.json(统一结果表,jq 友好)、 results.tsv(平表)、run.log、workloads/<backend>/<workload>/<phase>.json。

当日可测 instrumentation(框架内实现)

  • fio(优先)/ dd(回退)吞吐 + 延迟(clat p50/p99;dd 总时长);
  • Swift proxy 请求延迟+count:以 run 窗口为界,tail -n 窗口行数 $SWIFT_PROXY_LOG(默认 /var/log/swift/proxy-server.log)统计 request count / method / status / elapsed_time(默认 access log 的 float 字段);
  • etcd txn 延迟:窗口前后 diff $ETCD_ENDPOINT/metrics 的 grpc_server_handling_seconds{grpc_method="Txn"} sum/count → 窗口均值。

对比矩阵(env-gated backend sections)

gate默认后端
COMPARE_SWIFTFUSE=11本地 mount $BENCH_MOUNT
COMPARE_RAW_SWIFT=10swift CLI(RAW_SWIFT_*)
COMPARE_RCLONE=10rclone(RCLONE_REMOTE)
COMPARE_GEESEFS=10GeeseFS(S3API) mount $GEESEFS_MNT
COMPARE_JUICEFS=10JuiceFS mount $JUICEFS_MNT

所有启用 backend 写入同一 results.tsv / summary.json,结尾打印统一对齐表格。

Metrics Contract(R7)

daemon 暴露 GET http://127.0.0.1:<stats_listen>/metrics 以及 /run/swiftfuse/<fs_name>.stats.json(每 2s)。benchmark.sh 在每个 phase 窗口前后各拍一张,写入 phase JSON。字段:

字段含义单位
fuse_op_latency_usFUSE op 延迟 p50/p99µs
etcd_txn_latency_usdaemon 侧 etcd txn 延迟 p50/p99µs
swift_req_latency_usdaemon 侧 Swift 请求延迟µs
swift_req_countSwift 请求数(PUT/GET/DELETE/COPY 分桶)count
payload_bytes每 workload 读写字节bytes
cache_hit_ratio内存 block cache 命中率ratio
network_bytesclient↔proxy / proxy↔object 线上字节bytes

Results(2026-08-07 历史值;2026-08-09 重跑值见 G8 报告;2026-08-11 R3 修正见下)

单节点网络拓扑(M3,2026-08-11):10.0.0.1 = loopback(27.9 GB/s)。 单节点 seq read/write 不跨网卡;“千兆内网” 不适用,352-406 MiB/s 物理自洽。

WorkloadResultLimiting factor
seq-write 4MiB(2026-08-09 集群安静期)202.5 MiB/s(历史 12.4-13.2 MiB/s)Swift cluster PUT 延迟(并行 block PUT;忙时单块 0.3-3s)
seq-read 4MiB / 1MiB QD32352.3 / 406.3 MiB/sSwift proxy 并发 GET 上限
rand-read 64K QD8129.9 MiB/s(2079 iops)block 级随机读
4K 随机写(32MiB 全随机,close-flush)超时(8192 块串行 PUT)结构性写放大:每 4K 写 1 新块;非相邻写不合并 → close 时数千块 PUT;开 compaction 后可后台合并
4K 随机写(单次独立 flush)~0.9 s/次1 block PUT (~0.4s) + etcd commit
256 MiB warm read (block cache)915 MB/smemory
small-file create~0.4–1.3 s/fileSwift PUT latency (1 block per file)
stat(hot path,路径缓存命中)进程内命中 → 0 次 etcd 往返;含内核 LOOKUP 全程为一次 fuse round-trip见上文口径
readdir(726 文件,BUG-1 修复后)冷 0.75 s / 热 0.079 s;根目录(4 项)0.19 setcd 前缀扫描(并行化后)
mdtest file create / stat9.5 / 103.5 ops/sSwift PUT vs etcd metadata(两条路径清晰分离)
rename / truncate~0.2 s / 0.22 setcd quorum commit(strong consistency cost)
2-node concurrent read—(节点间 ssh 不可达;多节点由 Mac 驱动 multi_node.sh)

注意:上表 small-file create 为带 4K 内容的文件(1 对象 PUT);空文件 create 是纯 metadata(0 个 Swift 对象,114ms/create,见下文 M2 口径)——两条路径不要混读。

pjdfstest(G1,2026-08-09 全量)

分类文件数
PASS(适用用例)见 REPORT-2026-08-08.md §1
UNSUPPORTED(symlink/link/mkfifo/mknod → ENOSYS 声明)同上
KNOWN DEVIATION(unlink/14 open-deleted 链式 fd)1
FAIL0

Analysis

  • Data plane: parallel block PUT/GET confirmed correct (16 blocks in one round-trip); throughput is bounded by the Swift cluster itself (single-block PUT 0.3–3 s during benchmark runs — object servers were busy with auditor passes and replication). Raw Swift API has the same ceiling; swiftfuse adds no serialization.
  • Metadata plane: etcd quorum commits are the cost of strong consistency; path-resolution caching keeps hot stat at one fuse round-trip with zero etcd lookups (BUG-1 parallel list + BUG-3 umask 修复后).
  • The 宗旨 properties measured:
    • 4K random write into a 256 MiB file = 1 new block + CAS commit; no old-data read/rewrite (verified via container block audit).
    • rename/truncate/chmod = metadata transactions only.
    • Crash of a lease holder: other writers blocked (EBUSY) until etcd TTL expiry (30 s), then recovery (verified).
    • Concurrent writers on different nodes: CAS conflict → reload → retry (verified with 2 mounts writing the same file).

Amplification metrics(宗旨专项,2026-08-11 容器审计定死)

更正(2026-08-11 M1 审计):此前 REPORT/BENCHMARK 的 “4K 写 → 1 × 4MiB 对象 ≈ 1024× byte amplification” 是错误声明。 实测:4K 写 + fsync → 1 × 4096B Swift 对象(字节放大 = 1×)。 真实问题是 object/request amplification(每次 4K 写 = 1 个对象 + 1 次 PUT)。

指标值说明
4K 写 + fsync → Swift1 × 4096B 对象,1 PUT字节放大 1×;491ms/写(PUT + etcd commit)
100×4K 随机写 + 单 fsync96 个对象(94×4K + 2×8K 合并)非相邻 4K 写不合并 → N 对象;flush 曾串行 33s → 批量并行后 9.4s(4f063f7)
empty-file create → Swift0 个对象(纯 metadata)114ms/create = 串行 etcd 往返(非 Swift);stat 9ms
stat → etcd0(路径缓存命中)/ 1(miss)BUG-1 前缀修复 + 并行化后
readdir(726) → etcd1 次前缀扫描 + 并行 inode 拉取修复前 1008 key 泄漏 + 串行 = 25s

网络拓扑(M3 定死,与 ROADMAP 附录 M1-M3 对齐):10.0.0.1 是 loopback (dev lo,27.9 GB/s)—— 单节点 benchmark 的 client→Swift 路径不跨网卡, 352-406 MiB/s 物理自洽;“千兆内网” 表述不适用单节点。eth1(10.0.0.x 内部网)为 Contabo virtio 网卡(ethtool 无法读速,物理 ≥10Gb 量级)。真实跨节点上限需 跨节点路径测量(G10 的 5-12 MiB/s 为部分证据)。

G8 判定(R7,2026-08-11)

G8 性能 gate 判定从 PASS/FAIL 改为 MEASURED / REGRESSION / TIMEOUT / SLO-VIOLATION (scripts/detect/run_gates.sh)。results.tsv 保留历史 PASS/FAIL 列(向后兼容), 新增 class= 列承载 R7 判定:

  • MEASURED:干净跑完,高于 SLO(且已知 baseline 时高于 baseline);
  • REGRESSION:高于 SLO,但低于已记录 baseline(默认 seq-write 202.5 MiB/s, G8_BASELINE_MIB,容差 G8_REGRESSION_PCT=0.8);
  • SLO-VIOLATION:低于 SLO(G8_SLO_SEQ_WRITE_MIB=10、G8_SLO_SEQ_READ_MIB=50、 G8_SLO_RANDREAD_IOPS=500,env 可覆盖);
  • TIMEOUT:任一 fio/mdtest job 触到 time bound(exit 124)。

mdtest 同理(create ops/s SLO G8_SLO_MDTEST_CREATE_OPS=1,baseline 9.5 ops/s)。

Tuning knobs (config)

  • block_size (4 MiB default): trade HTTP requests vs write amplification
  • prefetch (8 MiB default): read window per request
  • read_workers / write_workers: parallel GET/PUT concurrency
  • cache_blocks: in-memory read cache capacity
  • write_back: kernel write-back cache (on by default)
  • lease: ProxyFS-style write leases (etcd only)
  • kernel_ttl: 0 = 正确性优先(内核每次重验);bridge patch 稳定后可回正