小块写缓存优化
This commit is contained in:
194
plan/codexplan.md
Normal file
194
plan/codexplan.md
Normal file
@@ -0,0 +1,194 @@
|
||||
# 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 Plane(worker)**
|
||||
- 处理 read/pread/write/pwrite/fsync 的数据 IO。
|
||||
- 每个 worker 持有:`spdk_thread + io_channel + submission_queue + completion_queue`。
|
||||
|
||||
- **Persistence Plane(元数据持久化)**
|
||||
- 元数据 WAL(append-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 提升 >= 2x(4~16 线程场景)
|
||||
- P99 延迟下降 >= 30%
|
||||
- CPU busy-poll 占比显著下降(可通过 perf/top 观测)
|
||||
- `test_single_file_perf`、`test_single_file_random_perf` 在同配置下持续稳定,无明显长尾抖动。
|
||||
Reference in New Issue
Block a user