Files
zvfs/plan/codexplan.md
2026-03-03 14:24:17 +00:00

195 lines
7.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ZVFS 高性能框架设计(修订版)
## 0. 当前实现进展2026-03-03
- 已落地:
- stale blob 自愈open/create/unlink/rename 路径)
- hook 层小写合并per-fd writeback buffer默认 128KB+ 关键系统调用前 flush
- 仍待重点优化:
- 小块读路径仍是“同步提交 + 单请求往返 + 拷贝返回”,延迟和吞吐偏弱
## 1. 现状代码中的关键问题(先于方案)
基于 `zvfs.c``zvfs.h``zvfs_hook.c`,当前主要瓶颈和风险如下:
1. **单全局执行上下文串行化**
- 所有 IO 都通过 `global_thread` + `waiter()` 同步等待,天然把多线程请求串到一个 SPDK thread。
- `zvfs_t` 里只有一个 `channel`,读写都走这一个 channel无法利用多核并行。
2. **等待模型是忙轮询CPU 成本高**
- `waiter()` 用紧循环 `spdk_thread_poll()`,没有阻塞等待/退避策略。
- 在高并发小 IO 下,系统容易进入“高 CPU + 低有效 QD”。
3. **全局元数据无并发保护**
- `dirents/fd_table/g_dirs/g_dirfd_table/open_count/file_size` 读写没有统一锁。
- hook 层是多线程入口,当前实现有明显竞态和可见性问题。
4. **持久化与语义不完整**
- `fsync/fdatasync/sync_file_range` 对 zvfs fd 基本直接返回 0和数据库预期不一致。
- `meta_load()` 只读固定 4KB 文本,规模稍大就截断;`meta_save()` 也无崩溃一致性保证。
5. **数据路径的放大和额外开销**
- 小块随机写依赖 read-modify-write无写回缓存、无批量提交、无 IO 合并。
- per-file `dma_buf` 增长时可能反复 realloc缺少池化和复用策略。
6. **可扩展性不足**
- `dirent_find/fd_alloc` 等是线性扫描。
- 元数据、目录结构、fd 分配都偏“单点共享结构”,随着文件数/线程数增长会抖动。
---
## 2. 对 userplan.md 的补全与修正
`plan/userplan.md` 的方向TLS + per-thread channel + 缩小全局锁)是正确的,但有几个需要补全的点:
1. **“每个 pthread 一个 spdk_thread”要可配置**
- 对 MySQL 这类线程数可能很大的进程,严格 1:1 会导致线程对象和 channel 爆炸。
- 建议改为:默认“线程绑定 worker 池N:M支持配置成 1:1 调试模式。
2. **需要明确“文件句柄跨线程访问”的所有权规则**
- 同一 fd 可能被不同 pthread 使用,必须定义 offset、cache、flush 的同步策略。
3. **batch poll 需要配套“提交队列 + 背压 + 超时”**
- 仅有 `pending_queue` 不够,必须定义入队失败/队列满/超时处理。
4. **必须补上 fsync/fdatasync 的严格语义**
- 尤其面向数据库fsync 成功后应保证数据页 + 必要元数据已持久化。
5. **元数据持久化需要从“文本快照”升级为“日志+检查点”**
- 否则崩溃恢复和规模都不可靠。
---
## 3. 新框架设计(面向高性能与可重入改造)
### 3.1 分层与职责
- **Control Plane全局**
- 管理 mount/unmount、命名空间、inode 元数据、fd 表、恢复日志。
- 低频操作open/create/unlink/rename/mkdir/rmdir在此层处理。
- **Data Planeworker**
- 处理 read/pread/write/pwrite/fsync 的数据 IO。
- 每个 worker 持有:`spdk_thread + io_channel + submission_queue + completion_queue`
- **Persistence Plane元数据持久化**
- 元数据 WALappend-only+ 周期 checkpoint。
- 保障崩溃恢复和 fsync 语义。
### 3.2 全局运行时结构
```c
typedef struct {
// init/mount 生命周期
pthread_once_t init_once;
pthread_mutex_t mount_mu;
_Atomic int mount_state; // UNINIT/INITING/READY/FAILED/STOPPING
// core spdk objects
struct spdk_blob_store *bs;
struct spdk_bs_dev *bs_dev;
// metadata indexes
pthread_rwlock_t inode_rwlock;
inode_table_t *inode_by_path; // hash map: path -> inode
inode_table_t *inode_by_blobid; // hash map: blobid -> inode
pthread_rwlock_t fd_rwlock;
fd_table_t *fd_table; // pseudo fd -> file handle
// durability
meta_journal_t *journal; // WAL + checkpoint
// worker routing
worker_pool_t *workers; // configurable N workers
} zvfs_runtime_t;
```
### 3.3 worker 模型(建议默认 N:M可切 1:1
- 默认:`worker_count = min(online_cpu, ZVFS_IO_WORKERS)`
- 线程第一次进入时做 TLS 绑定:`pthread_id -> worker_id`(固定绑定,减少迁移)。
- 每个 worker 独占一个 io_channel避免全局 channel 争用。
- 等待机制:优先 `eventfd/futex + poll` 混合,避免纯忙轮询。
> 说明:若用户确认线程数有限,可配置 `ZVFS_WORKER_MODE=THREAD_LOCAL` 切 1:1以追求极致低延迟。
### 3.4 元数据模型
- `inode`(文件级共享对象)
- `blob_id, logical_size, allocated_clusters, link/open_ref, flags`
- 每 inode 一把细粒度锁mutex/spin + 原子字段)。
- `file handle`open 实例)
- `inode*`, `flags`, `current_offset`, `handle-local state`
- 路径索引与 blob 索引用哈希表替代线性数组。
- 目录树从 `g_dirs[]` 升级为前缀树或 hash+parent 索引,避免全表扫描。
### 3.5 IO 路径设计
#### Read/Pread
- 快路径命中页缓存clean/dirty直接拷贝。
- 慢路径:提交到绑定 worker。
- 对齐大读支持直接 DMA 到用户对齐缓冲(满足约束时)。
#### Write/Pwrite
- 小块随机写:写入 per-inode 页缓存4KB 粒度),标记 dirty。
- 大块或顺序写:绕过缓存直写(或写穿策略),减少二次拷贝。
- 扩容策略:按 chunk 预分配(例如 1~8MB减少 `resize + sync_md` 频率。
- flush 策略:
- 后台刷脏(阈值/时间)
- 前台 fsync 强制刷
- 合并连续页为 writev/batch IO
### 3.6 fsync/fdatasync 语义(数据库场景)
- `fdatasync(fd)`
1) 刷新该 fd 对应 inode 的脏数据页;
2) 若发生扩容,确保 blob 元数据同步完成;
3) 返回前确认提交完成。
- `fsync(fd)`
-`fdatasync` 基础上,额外保证需要的命名空间/元数据日志落盘(如 size、rename 可见性)。
### 3.7 崩溃一致性与恢复
- `meta_journal.log`append-only带 magic/version/CRC/seq
- 操作记录:`CREATE/UNLINK/RENAME/TRUNCATE/SIZE_UPDATE/ALLOC_UPDATE`
- 启动恢复:`checkpoint -> replay WAL`
- 周期 checkpoint按时间或日志大小触发避免恢复时间无限增长。
### 3.8 锁策略与死锁规约
- 固定锁顺序:`fd_table lock -> inode lock -> journal lock`
- IO 快路径不拿全局写锁。
- 元数据读多写少:读写锁 + inode 细粒度锁组合。
### 3.9 可观测与调优
- 统计项(至少):
- read/write IOPS、带宽、P50/P99 延迟
- cache hit ratio、dirty page 数
- flush 次数、merge 比例、resize 次数
- queue depth、排队延迟
- debug 开关:
- `ZVFS_TRACE_IO=1`
- `ZVFS_TRACE_META=1`
- `ZVFS_WORKER_MODE`, `ZVFS_IO_WORKERS`
---
## 4. 关键行为约束(必须保持)
1. POSIX 语义不回退:`openat/rename/unlink/ftruncate/fstat/fsync` 的错误码与行为保持一致或更严格。
2. 在无 root 环境下可跑功能测试(至少支持 Malloc bdev 或已有可用 SPDK 配置)。
3. 旧接口兼容:外部仍通过 `LD_PRELOAD=.../libzvfs.so` 使用。
4. 改造过程可分阶段落地,任何阶段都可独立编译、回归、继续下一阶段。
---
## 5. 性能目标(建议)
- 与当前实现相比:
- 多线程随机写 IOPS 提升 >= 2x4~16 线程场景)
- P99 延迟下降 >= 30%
- CPU busy-poll 占比显著下降(可通过 perf/top 观测)
- `test_single_file_perf``test_single_file_random_perf` 在同配置下持续稳定,无明显长尾抖动。