摘要:NVMe KV命令集(TP4091)将SSD I/O单元从512B/4KB块升级为变长键值对,通过Store/Retrieve/Delete/List/Exist五条命令直接对接RocksDB等KVS引擎,消除文件系统与FTL双重写放大。本文深入解析NVMe KV规范字段定义、PRP/SGL数据传输机制与4KB对齐瓶颈、BandSlim内联piggyback优化、nLSM固件级LSM-Tree K2P映射、KV-CSD计算型存储硬件加速架构,以及Samsung OpenMPDK/NVMeVirt开源实现。
📑 目录
- 一、为什么需要KV-SSD:块接口的"语义鸿沟"
- [1.1 KV工作负载的块层开销](#1.1 KV工作负载的块层开销)
- [1.2 双重写放大问题](#1.2 双重写放大问题)
- [1.3 软件栈简化动机](#1.3 软件栈简化动机)
- [二、NVMe Key-Value命令集规范深度解析](#二、NVMe Key-Value命令集规范深度解析)
- [2.1 TP4091技术提案与NVMe 2.0标准化](#2.1 TP4091技术提案与NVMe 2.0标准化)
- [2.2 五条核心命令Opcode定义](#2.2 五条核心命令Opcode定义)
- [2.3 Key/Value字段约束与编码](#2.3 Key/Value字段约束与编码)
- [2.4 SQE命令格式:CDW10-CDW15字段布局](#2.4 SQE命令格式:CDW10-CDW15字段布局)
- 三、数据传输机制:PRP/SGL与4KB对齐困境
- [3.1 PRP传输机制回顾](#3.1 PRP传输机制回顾)
- [3.2 小Value的PCIe流量膨胀问题](#3.2 小Value的PCIe流量膨胀问题)
- [3.3 NAND Write Amplification叠加效应](#3.3 NAND Write Amplification叠加效应)
- [3.4 BandSlim:命令内联Piggyback优化](#3.4 BandSlim:命令内联Piggyback优化)
- 四、KV-SSD固件架构:nLSM与K2P映射
- [4.1 从L2P到K2P:映射范式转换](#4.1 从L2P到K2P:映射范式转换)
- [4.2 nLSM Tree:闪存原生LSM-Tree](#4.2 nLSM Tree:闪存原生LSM-Tree)
- [4.3 Remapping Compaction:减少元数据重写](#4.3 Remapping Compaction:减少元数据重写)
- [4.4 冷热分离策略](#4.4 冷热分离策略)
- 五、KV-CSD:计算型存储的硬件加速KV引擎
- [5.1 架构设计:Device-side LSM-Tree](#5.1 架构设计:Device-side LSM-Tree)
- [5.2 Bulk PUT接口与批量传输](#5.2 Bulk PUT接口与批量传输)
- [5.3 性能基准:KV-CSD vs RocksDB](#5.3 性能基准:KV-CSD vs RocksDB)
- [六、开源实现:Samsung OpenMPDK与NVMeVirt](#六、开源实现:Samsung OpenMPDK与NVMeVirt)
- [6.1 Samsung KVSSD项目架构](#6.1 Samsung KVSSD项目架构)
- [6.2 NVMeVirt模拟器与KVVirt FTL](#6.2 NVMeVirt模拟器与KVVirt FTL)
- [6.3 Linux内核KVSSD驱动](#6.3 Linux内核KVSSD驱动)
- 七、SPDK对KV命令集的支持
- [7.1 SPDK NVMe KV接口API](#7.1 SPDK NVMe KV接口API)
- [7.2 用户态KV驱动实现](#7.2 用户态KV驱动实现)
- [八、KV-SSD vs Open-Channel SSD vs ZNS:三种接口范式对比](#八、KV-SSD vs Open-Channel SSD vs ZNS:三种接口范式对比)
- [8.1 抽象层次对比](#8.1 抽象层次对比)
- [8.2 适用场景分析](#8.2 适用场景分析)
- [九、前沿方向:AI推理KV Cache卸载](#九、前沿方向:AI推理KV Cache卸载)
- 十、当日知识点小结与思考题
一、为什么需要KV-SSD:块接口的"语义鸿沟"
1.1 KV工作负载的块层开销
现代数据中心的核心工作负载已从关系型数据库转向键值存储(Key-Value Store)。RocksDB、LevelDB、Redis等KVS引擎支撑着社交网络、搜索引擎、推荐系统、区块链等海量数据的存储与检索。据Meta公开的生產环境数据,RocksDB是其全球数据中心部署最广泛的存储引擎之一。
然而,这些KVS引擎运行在传统块存储之上时,面临一条冗长的软件路径:
应用程序(PUT/GET请求)
│
▼
KVS引擎(RocksDB/LevelDB)
│ ← Key→LBA映射(MemTable/SSTable/Compaction)
▼
文件系统(ext4/XFS/Btrfs)
│ ← 文件偏移→块映射(inode/block bitmap/journal)
▼
Block层(mq-deadline/none调度器)
│ ← I/O合并、排序、队列管理
▼
NVMe驱动
│ ← LBA→PPA映射(FTL)
▼
SSD硬件(NAND Flash)
关键问题 :在这条路径中,KVS引擎将Key→Value映射为文件内的偏移量,文件系统再将偏移量映射为逻辑块地址(LBA),SSD固件的FTL又将LBA映射为物理页地址(PPA)。三次映射中,前两次完全是软件开销------KVS不知道文件系统的存在,文件系统不知道KVS的语义,FTL不知道上层数据的含义。
这种"语义鸿沟"(Semantic Gap)导致的核心矛盾是:每一层都在做独立的数据管理,但彼此之间零信息共享。
1.2 双重写放大问题
当RocksDB执行一次简单的PUT操作时,写放大可能来自两个层面:
① KVS层面的写放大(LSM-Tree Compaction)
PUT("user:1001", {"name": "Alice", ...})
│
▼
MemTable(内存中SortedHashMap)
│ ← 满后Flush为SSTable L0
▼
L0 SSTable → L1 → L2 → ... (多级Compaction)
│ ← 每级合并重写,典型WAF = 5-30x
▼
最终写入文件系统
RocksDB的LSM-TreeCompaction机制会将旧的SSTable数据读取、排序、合并后重写为新SSTable。典型的写放大因子(WAF)在5-30x之间,取决于Compaction策略(Leveled/Universal/FIFO)和数据分布。
② 块设备层面的写放大(FTL GC)
文件系统写LBA[100-103]
│
▼
FTL: 找到PPA映射,写入新页
│ ← 旧页标记为invalid
▼
GC触发: 读取valid页→重写→擦除旧块
│ ← 额外写放大,典型WAF = 1.5-3x
▼
NAND Flash物理页
SSD固件的FTL在后台执行垃圾回收时,需要读取有效数据、重写、再擦除。这又引入了一层1.5-3x的写放大。
两层写放大的叠加效应:
总WAF = KVS_WAF × FTL_WAF = (5~30) × (1.5~3) = 7.5~90x
这意味着用户写入1GB数据,实际NAND消耗可能高达7.5GB到90GB!
1.3 软件栈简化动机
KV-SSD的核心思想是:让SSD直接理解键值对语义,消除文件系统层和KVS引擎中的LBA映射开销。
传统路径: KV-SSD路径:
应用程序 应用程序
│ │
▼ ▼
KVS引擎 NVMe KV驱动
│ │ ← 直接发送PUT/GET命令
▼ ▼
文件系统 ┌─────────┐
│ │ 已消除 │
▼ └─────────┘
Block层 ┌─────────┐
│ │ 已消除 │
▼ └─────────┘
NVMe驱动 NVMe KV驱动
│ │
▼ ▼
FTL(L2P) K2P映射 + vLog
│ │
▼ ▼
NAND Flash NAND Flash
消除文件系统和Block层带来的直接收益:
- 延迟降低:减少2-3层软件栈遍历,预期降低5-15μs
- 写放大消除:FTL级GC被KV-SSD的vLog append-only写入替代
- CPU占用降低:KVS的Compaction可以卸载到SSD设备端
- 容量利用率提升:无需为FTL预留over-provisioning空间给LBA映射
二、NVMe Key-Value命令集规范深度解析
2.1 TP4091技术提案与NVMe 2.0标准化
NVMe KV命令集起源于NVM Express组织的TP4091技术提案(Technical Proposal),于2021年随NVMe 2.0规范正式发布为独立的I/O命令集(I/O Command Set)。
规范文档 :NVM Express Key-Value Command Set Specification, Revision 1.0
NVMe 2.0引入了Namespace Types机制,允许同一控制器上的不同命名空间使用不同的I/O命令集:
NVMe Controller 0
├── Namespace 1: NVM Command Set (传统块接口, CC.CSS = 0x0)
├── Namespace 2: Key-Value Command Set (KV接口, CC.CSS = 0x1)
├── Namespace 3: Zoned Namespace (ZNS接口, CC.CSS = 0x2)
└── Namespace 4: NVM Command Set
主机在创建I/O队列时通过Controller Configuration寄存器中的**CSS(I/O Command Set Selected)**字段选择命令集:
c
/* CC寄存器 - I/O Command Set Selected (bits 6:4) */
#define NVME_CC_CSS_NVM 0x0 /* NVM命令集(默认) */
#define NVME_CC_CSS_KV 0x1 /* Key-Value命令集 */
#define NVME_CC_CSS_ZNS 0x2 /* Zoned Namespace命令集 */
#define NVME_CC_CSS_IOCS 0x6 /* 通过I/O Command Set Profile选择 */
#define NVME_CC_CSS_NOIO 0x7 /* 仅Admin命令集 */
2.2 五条核心命令Opcode定义
NVMe KV命令集定义了5条 mandatory I/O命令:
c
/* SPDK头文件中的KV命令集Opcode定义 */
enum spdk_nvme_kv_opcode {
SPDK_NVME_OPC_KV_STORE = 0x01, /* 存储键值对 */
SPDK_NVME_OPC_KV_RETRIEVE = 0x02, /* 检索键对应的值 */
SPDK_NVME_OPC_KV_LIST = 0x06, /* 列出命名空间中的键 */
SPDK_NVME_OPC_KV_DELETE = 0x10, /* 删除键值对 */
SPDK_NVME_OPC_KV_EXIST = 0x14, /* 检查键是否存在 */
};
各命令的语义和原子性保证如下:
| Opcode | 命令名 | 数据传输方向 | 原子性 | 描述 |
|---|---|---|---|---|
| 0x01 | KV Store | Host→Controller | ✅ 原子 | 存储Key-Value对,支持压缩/不可变/仅创建选项 |
| 0x02 | KV Retrieve | Controller→Host | ✅ 原子 | 按Key检索Value,支持解压/原始模式 |
| 0x06 | KV List | Controller→Host | ❌ | 列出NS内所有Key或按前缀过滤 |
| 0x10 | KV Delete | 无 | ✅ 原子 | 删除指定Key及其Value |
| 0x14 | KV Exist | 无 | ❌ | 检查Key是否存在,返回Success或Not Found |
规范原文引用 :"The Key-Value command set supports the following mandatory commands: Store, Retrieve, List, Delete, and Exist. Store and Delete operations shall be atomic --- either the entire operation completes successfully or the previous value of the key is preserved."(NVMe KV Command Set Spec 1.0, Section 3.1)
2.3 Key/Value字段约束与编码
NVMe KV规范对Key和Value有严格的约束:
Key约束:
- 最大长度:16字节(两个64位字)
- 最小长度:1字节
- 编码:不透明字节序列(opaque byte sequence),无编码要求
- 长度敏感:
0x55和0x0055视为不同Key - 存储位置:Key存储在NVMe SQE的CDW10-CDW13字段中
Value约束:
-
最大大小:4GB(2^32字节)
-
最小大小:0字节(允许只有Key无Value)
-
编码:不透明字节序列
-
传输方式:通过PRP或SGL指定的Host Memory缓冲区
┌─────────────────────────────────────────────────┐
│ NVMe KV Pair Constraints │
├─────────────────────────────────────────────────┤
│ Key: [1 byte .. 16 bytes] │
│ 变长,1字节粒度 │
│ 长度不同 = 不同Key │
├─────────────────────────────────────────────────┤
│ Value: [0 bytes .. 4 GB] │
│ 变长,字节粒度 │
│ 通过PRP/SGL传输 │
├─────────────────────────────────────────────────┤
│ 注意:Value大小0 = 合法(仅Key无Value) │
└─────────────────────────────────────────────────┘
16字节Key的实际限制 :16字节 = 128位,足够承载大多数哈希键(如SHA-1截断、MD5完整),但无法直接用于内容寻址存储(CAS)中的SHA-256(32字节)。实践中可通过
hash(key) → 16B映射解决,或使用Key的前16字节作为Key,后16字节作为Value头部。
2.4 SQE命令格式:CDW10-CDW15字段布局
KV Store命令的SQE(Submission Queue Entry)字段布局如下:
c
/* NVMe KV Store命令 - SQE字段定义 */
struct nvme_kv_store_command {
__u8 opcode; /* 0x01: KV Store */
__u8 flags; /* 命令标志位 */
__u16 command_id; /* 命令标识 */
__le32 nsid; /* 命名空间ID */
__le64 rsvd2[2]; /* 保留 */
__le64 metadata; /* 元数据指针(MPTR) */
__le64 prp1; /* PRP Entry 1: Value缓冲区地址 */
__le64 prp2; /* PRP Entry 2: 第二页或PRP List */
/* CDW10: Key低64位 (bytes 0-7) */
__le64 key_lo;
/* CDW12: Key高64位 (bytes 8-15) + Key Size */
struct {
__le32 key_hi; /* Key高32位 (CDW12低32位) */
};
/* CDW13: Value大小 + 选项 */
struct {
__le32 value_size; /* Value大小(字节) */
};
/* CDW14: 选项标志 */
struct {
__u8 key_size; /* Key大小 - 1(0-based) */
__u8 option; /* 压缩/原子性/IF_NOT_EXIST选项 */
__le16 rsvd; /* 保留 */
};
/* CDW15: 保留 */
__le32 cdw15;
};
/* Option字段位定义 (CDW14 bits 15:8) */
#define NVME_KV_OPT_COMPRESS (1 << 0) /* 请求压缩存储 */
#define NVME_KV_OPT_ATOMIC (1 << 1) /* 原子操作 */
#define NVME_KV_OPT_IF_NOT_EXIST (1 << 2) /* 仅创建(Key已存在则失败) */
#define NVME_KV_OPT_NO_OVERWRITE (1 << 3) /* 禁止覆盖 */
关键设计决策 :Key直接嵌入SQE命令中(而非通过PRP/SGL指向Host Memory),这是为了避免一次额外的DMA读取来fetch Key。16字节的Key恰好可以放入CDW10-CDW13中,零额外传输开销。
三、数据传输机制:PRP/SGL与4KB对齐困境
3.1 PRP传输机制回顾
NVMe协议使用**Physical Region Page(PRP)或Scatter-Gather List(SGL)**来描述Host Memory中的数据传输缓冲区。PRP的基本规则:
PRP Entry结构(64位):
┌───────────────────────────────────────────┐
│ Bits 63:12 │ Bits 11:0 │
│ 物理页基地址 │ 必须为0(4KB对齐) │
└───────────────────────────────────────────┘
PRP传输规则:
- PRP1: 始终指向数据缓冲区的第一个页
- PRP2: 如果数据跨页,指向第二个页或PRP List
- PRP List: 一个包含多个PRP Entry的连续内存页
4KB对齐约束:
- 每个PRP Entry的基地址必须4KB对齐
- DMA传输以4KB页为最小单位
- 即使实际数据只有32字节,DMA仍传输整个4KB页
3.2 小Value的PCIe流量膨胀问题
据Meta公开的生产环境数据,RocksDB中Value的平均大小不到100字节,远小于4KB内存页大小。这意味着NVMe KV-SSD在使用标准PRP传输时面临严重的PCIe流量膨胀:
场景分析(引自BandSlim论文, ICPP 2024):
Case 1: Value = 32字节
┌─────────────────────────────────┐
│ Host Memory │
│ ┌──┬─────────────────────────┐ │
│ │32│ 未使用(4064字节) │ │ ← 4KB页
│ └──┴─────────────────────────┘ │
└─────────────────────────────────┘
│
DMA传输4KB
│
▼
PCIe带宽浪费 = 4064/4096 = 99.2%
Case 2: Value = 4K+32 = 4128字节
┌─────────────────────────────────┐
│ Host Memory │
│ ┌──────────────┬──┬──────────┐ │
│ │ 4096字节 │32│ 未使用 │ │ ← 8KB (2页)
│ └──────────────┴──┴──────────┘ │
└─────────────────────────────────┘
│
DMA传输8KB
│
▼
实际数据4128B, DMA传输8192B
PCIe效率 = 4128/8192 = 50.4%
量化影响 :BandSlim论文的实验数据表明,对于平均32字节的Value,传统NVMe KV-SSD的PCIe流量膨胀高达128倍(4096/32)。
3.3 NAND Write I/O Amplification叠加效应
PCIe流量膨胀只是问题的一半。在SSD设备内部,NAND Page Buffer同样以4KB为单位进行打包:
NAND Page Buffer打包(假设NAND Page = 16KB):
传统方式(4KB为单位打包):
┌─────────────────────────────────────────────┐
│ NAND Page Buffer Entry (16KB) │
│ ┌────────┬────────┬────────┬────────┐ │
│ │ 4KB │ 4KB │ 4KB │ 4KB │ │ ← 需要4个32B Value
│ │(4096B) │(4096B) │(4096B) │(4096B) │ │ 才能填满一个NAND页缓冲
│ └────────┴────────┴────────┴────────┘ │
└─────────────────────────────────────────────┘
实际NAND页写入:
- 每个32B Value触发一个4KB缓冲区分配
- 16KB NAND页需要填满4个Value才能写入
- 如果只收到1个Value → 写16KB NAND页,实际数据32B
- NAND WAF = 16384/32 = 512x !!!
双重膨胀的总效应:
Value = 32字节时:
PCIe流量膨胀 = 4096/32 = 128x
NAND WAF = 16384/32 = 512x(最坏情况)
总存储代价 = 16384 bytes NAND per 32 bytes value
3.4 BandSlim:命令内联Piggyback优化
BandSlim(ICPP 2024)提出了一种巧妙的解决方案:将小Value直接嵌入NVMe命令的保留字段中,避免PRP DMA传输。
原始NVMe KV Store命令(64字节 SQE):
┌──────┬──────┬──────┬───────────────────────────┐
│opcode│flags │cmd_id│ nsid │ 8B
├──────┴──────┴──────┴───────────────────────────┤
│ rsvd2[2] / metadata │ 16B
├─────────────────────────────────────────────────┤
│ PRP1 (Value地址) │ 8B
│ PRP2 │ 8B
├─────────────────────────────────────────────────┤
│ CDW10: key[0:3] │ 4B
│ CDW11: key[4:7] │ 4B
│ CDW12: key[8:11] │ 4B
│ CDW13: key[12:15] │ 4B ← Key占16B
├─────────────────────────────────────────────────┤
│ CDW14: key_size + option │ rsvd[1] │ rsvd[0] │ 4B
│ CDW15: value_size │ 4B
└─────────────────────────────────────────────────┘
BandSlim内联Piggyback:
┌─────────────────────────────────────────────────┐
│ 利用CDW14-CDW15中的保留字段和字节: │
│ - rsvd[0], rsvd[1] in CDW14: 2 bytes │
│ - Vendor-specific in CDW11: 1 byte │
│ - 总计最多35字节(Write Command) │
│ │
│ 对于Transfer Command(后续命令): │
│ - 除opcode外的所有CDW均可用于piggyback │
│ - 可利用56字节 │
│ │
│ Write Command (35B) + Transfer Command (56B) │
│ = 最多91字节内联传输,无需PRP/DMA │
└─────────────────────────────────────────────────┘
BandSlim性能数据(引自原论文):
┌───────────────────────────────────────────────────────┐
│ BandSlim vs 标准NVMe KV-SSD (Value=32B) │
├──────────────────┬────────────┬───────────────────────┤
│ 指标 │ 标准NVMe KV│ BandSlim │
├──────────────────┼────────────┼───────────────────────┤
│ PCIe流量/op │ 4096 B │ 64 B (SQE本身) │
│ PCIe流量减少 │ - │ 97.9%↓ │
│ NAND WAF │ ~512x │ ~1x (紧密打包) │
│ 延迟 │ ~10μs │ ~5μs │
└──────────────────┴────────────┴───────────────────────┘
四、KV-SSD固件架构:nLSM与K2P映射
4.1 从L2P到K2P:映射范式转换
传统SSD的FTL维护L2P(Logical-to-Physical)映射表:
传统FTL - L2P映射:
┌────────────┬────────────┐
│ LBA (逻辑) │ PPA (物理) │
├────────────┼────────────┤
│ 0 │ Ch0 LUN0 P0│
│ 1 │ Ch1 LUN0 P0│
│ 2 │ Ch0 LUN1 P0│
│ ... │ ... │
└────────────┴────────────┘
典型表大小: 每LBA 4-8 bytes
1TB SSD (512B sector) = 2B entries × 8B = 16GB DRAM
KV-SSD需要维护K2P(Key-to-Physical)映射:
KV-SSD FTL - K2P映射:
┌──────────────────┬────────────────┐
│ Key (1-16 bytes) │ PPA (物理页) │
├──────────────────┼────────────────┤
│ [0x01 0x02 0x03] │ Ch0 LUN0 P12 │
│ [0xAB 0xCD] │ Ch1 LUN2 P5 │
│ [0x55] │ Ch0 LUN1 P88 │
└──────────────────┴────────────────┘
映射粒度: Key变长 → 不能用简单数组
需要索引结构: Hash Table / B-Tree / LSM-Tree
4.2 nLSM Tree:闪存原生LSM-Tree
KVSSD论文(DATE 2018, Sung-Ming Wu et al.)提出了nLSM(NAND-flash-LSM)------一种直接在闪存上实现的LSM-Tree,取代传统的L2P映射:
nLSM Tree架构:
┌─────────────────────────────────────────────────────────┐
│ NAND Flash 空间划分 │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────┐│
│ │ 元数据区(Metadata Region) ││
│ │ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ││
│ │ │Meta │ │Meta │ │Meta │ │Meta │ ← Key Range ││
│ │ │Page 0│ │Page 1│ │Page 2│ │Page 3│ + 指针 ││
│ │ └──┬───┘ └──┬───┘ └──┬───┘ └──┬───┘ ││
│ └─────┼────────┼────────┼────────┼─────────────────────┘│
│ │ │ │ │ │
│ ┌─────┼────────┼────────┼────────┼─────────────────────┐│
│ │ KV区(KV Region) │ │ ││
│ │ ┌───┴───┐ ┌──┴────┐ ┌┴──────┐ ┌┴──────┐ ││
│ │ │KV Page│ │KV Page│ │KV Page│ │KV Page│ ← 排序后的 ││
│ │ │[A..D] │ │[D..G] │ │[G..J] │ │[J..M] │ KV对 ││
│ │ └───────┘ └───────┘ └───────┘ └───────┘ ││
│ └──────────────────────────────────────────────────────┘│
│ │
└─────────────────────────────────────────────────────────┘
查找路径:
Key = "F"
→ Key Range Tree: "F" in [D..G] → Meta Page 1
→ Meta Page 1: KV Page指向 → KV Page [D..G]
→ KV Page内线性搜索 → 找到 "F" → 返回Value PPA
nLSM的核心设计:
c
/* nLSM Key Range Tree节点(伪代码) */
struct key_range_node {
u8 key_start[16]; /* 范围起始Key */
u8 key_end[16]; /* 范围结束Key */
u32 level; /* LSM层级 */
u32 sstable_id; /* 指向的SSTable(闪存块) */
struct key_range_node *left, *right;
};
/* 元数据页结构(每个闪存页一个) */
struct metadata_page {
u32 num_entries;
struct {
u8 key_range_start[16];
u8 key_range_end[16];
u32 kv_page_offset; /* KV区内的页偏移 */
} entries[];
};
/* SSTable = 一个闪存块(典型4MB) */
/* 每个SSTable内的KV对按Key排序,物理连续 */
4.3 Remapping Compaction:减少元数据重写
nLSM的Remapping Compaction是一个精巧的优化------Compaction时只重写指向KV页的元数据指针,而不复制KV数据本身:
传统Compaction(重写所有数据):
Level i: Ta [A,B,C,D,E,F] → 读取、排序、重写
Level i+1: Tb [D,E,F,G,H] → 读取
Tc [G,H,I,J,K] → 读取
↓
新Tb' [A,B,C,D,E,F,G,H] ← 重写12个KV页 + 3个Meta页 = 15页写入
Remapping Compaction(只重写元数据):
Level i: Ta [A,B,C,D,E,F] → 分析Key Range
Level i+1: Tb [D,E,F,G,H] → 已有KV页
Tc [G,H,I,J,K]
↓
新Meta Tx → 指向 [A,B] (来自Ta)
新Meta Ty → 指向 [C,D,E,F] (来自Ta,指针重映射)
新Meta Tz → 指向 [G,H,I,J,K] (来自Tb+Tc)
只需重写3个Meta页!0个KV页重写!
写放大从15页降到3页(减少80%)
实验数据(KVSSD论文):
| 方案 | 写放大因子 | 吞吐提升 | 读放大 |
|---|---|---|---|
| LSM (LevelDB) | 基线 1.0x | 基线 | 基线 |
| dLSM (delay compaction) | 0.65x | 1.5x | 基线 |
| lLSM (light compaction) | 0.52x | 1.8x | 1.05x |
| nLSM | 0.35x | 2.8x | 1.08x |
| rLSM (remapping + hot-cold) | 0.12x | 4.47x | 1.11x |
4.4 冷热分离策略
rLSM进一步引入冷热分离(Hot-Cold Separation):
写入热数据(频繁更新):
→ 写入Hot Block Pool
→ 保留在SLC模式(快速擦写)
→ Compaction频率高
写入冷数据(一次写入,多次读取):
→ 直接写入Cold Block Pool
→ TLC/QLC模式(高密度存储)
→ 几乎不参与Compaction
物理闪存划分:
┌───────────────────────────────────────┐
│ Hot Block Pool (SLC, 低延迟) │
│ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │Block│ │Block│ │Block│ ← 高频更新 │
│ │ A │ │ B │ │ C │ 数据 │
│ └─────┘ └─────┘ └─────┘ │
├───────────────────────────────────────┤
│ Cold Block Pool (TLC, 高容量) │
│ ┌───────┐ ┌───────┐ ┌───────┐ │
│ │ Block │ │ Block │ │ Block │ │
│ │ X │ │ Y │ │ Z │ │ ← 归档数据
│ └───────┘ └───────┘ └───────┘ │
└───────────────────────────────────────┘
五、KV-CSD:计算型存储的硬件加速KV引擎
5.1 架构设计:Device-side LSM-Tree
KV-CSD(Key-Value Computational Storage Device)由LANL/Sandia国家实验室联合开发(IEEE Cluster 2023),将完整的LSM-Tree数据库引擎嵌入SSD固件:
KV-CSD架构图:
┌──────────────────────────────────────────────────────────┐
│ Host │
│ ┌──────────┐ NVMe KV Commands ┌──────────────┐ │
│ │Application│◄─────────────────────►│ NVMe Driver │ │
│ │(RocksDB │ PUT/GET/DELETE │ (kv-ssd.ko) │ │
│ │ 替代) │ └──────┬───────┘ │
│ └──────────┘ │ PCIe │
├──────────────────────────────────────────────────────────┤
│ KV-CSD Device │
│ ┌──────────────────────────────────────────────────────┐│
│ │ NVMe Controller (FPGA/ASIC) ││
│ │ ┌─────────┐ ┌──────────┐ ┌────────────────┐ ││
│ │ │ KV Cmd │→ │ LSM-Tree │→ │ vLog (Append) │ ││
│ │ │ Parser │ │ Engine │ │ Sequential Write│ ││
│ │ └─────────┘ │ (device- │ └────────────────┘ ││
│ │ │ side) │ ││
│ │ │ │ ┌────────────────┐ ││
│ │ │-MemTable │ │ NAND Flash │ ││
│ │ │-SSTable │→ │ (KV pairs) │ ││
│ │ │-Compaction│ └────────────────┘ ││
│ │ └──────────┘ ││
│ └──────────────────────────────────────────────────────┘│
└──────────────────────────────────────────────────────────┘
核心设计理念:
- PUT路径:接收Key-Value → 写入MemTable(DRAM)→ 异步刷写到SSTable(NAND)
- GET路径:MemTable查找 → Bloom Filter检查 → SSTable查找
- Compaction:在设备端异步执行,不占用主机CPU
- Bulk PUT:支持128KB批量消息,内含多达2570个KV对
5.2 Bulk PUT接口与批量传输
KV-CSD的Bulk PUT是其性能关键------将多个KV对打包到一个128KB消息中:
Bulk PUT消息格式(128KB):
┌─────────────────────────────────────────────────────────┐
│ Header (16 bytes) │
│ ┌────────┬──────────┬──────────┬────────────────────┐ │
│ │num_kvs │key_size │val_size │ reserved │ │
│ │(4B) │(4B) │(4B) │ (4B) │ │
│ └────────┴──────────┴──────────┴────────────────────┘ │
├─────────────────────────────────────────────────────────┤
│ KV Pair 0: [key_0 (16B)] [value_0 (32B)] │
│ KV Pair 1: [key_1 (16B)] [value_1 (32B)] │
│ KV Pair 2: [key_2 (16B)] [value_2 (32B)] │
│ ... │
│ KV Pair N: [key_N (16B)] [value_N (32B)] │
│ │
│ 对于16B key + 32B value: │
│ 每个KV对 = 48B │
│ 128KB / 48B ≈ 2570 个KV对/消息 │
│ │
│ vs 单条PUT: 2570次NVMe命令 → 1次NVMe命令 │
│ 加速比 ≈ 7x │
└─────────────────────────────────────────────────────────┘
5.3 性能基准:KV-CSD vs RocksDB
KV-CSD论文提供了详实的对比数据(32M随机KV对,16B Key + 32B Value):
┌─────────────────────────────────────────────────────────────────────┐
│ PUT性能对比: KV-CSD vs RocksDB (32M keys, 16B key + 32B value) │
├───────────────────┬──────────────┬──────────────┬──────────────────┤
│ 主机CPU核心数 │ RocksDB(s) │ KV-CSD(s) │ 加速比 │
├───────────────────┼──────────────┼──────────────┼──────────────────┤
│ 2 cores │ ~2000 │ ~253 │ 7.9x │
│ 4 cores │ ~1500 │ ~240 │ 6.25x │
│ 8 cores │ ~1000 │ ~230 │ 4.35x │
│ 16 cores │ ~700 │ ~225 │ 3.11x │
│ 32 cores │ ~500 │ ~119 │ 4.2x │
├───────────────────┼──────────────┼──────────────┼──────────────────┤
│ 总数据写入量 │ 250 GB │ 12.5 GB │ 20x↓ │
│ (Compaction I/O) │ │ │ │
└───────────────────┴──────────────┴──────────────┴──────────────────┘
关键发现:
1. RocksDB需要32个CPU核心才能跑满性能
2. KV-CSD只需2个CPU核心即可达到峰值(因为LSM操作在设备端)
3. KV-CSD的总I/O量仅为RocksDB的1/20(消除了Compaction读放大)
4. Value=4KB时,KV-CSD比RocksDB快10x(32 cores vs 32 cores)
六、开源实现:Samsung OpenMPDK与NVMeVirt
6.1 Samsung KVSSD项目架构
Samsung在2017年SDC大会上首次公开KV-SSD概念后,开源了OpenMPDK/KVSSD项目,提供完整的内核驱动和用户态工具:
Samsung KVSSD软件栈:
┌────────────────────────────────────────────────────────┐
│ User Space │
│ ┌──────────────┐ ┌────────────┐ ┌──────────────┐ │
│ │ kvssd-cli │ │ YCSB │ │ RocksDB │ │
│ │ (管理工具) │ │ (基准测试) │ │ (适配层) │ │
│ └──────┬───────┘ └─────┬──────┘ └──────┬───────┘ │
│ │ │ │ │
│ ┌──────┴────────────────┴────────────────┴─────────┐ │
│ │ kvssd.ko (Kernel Module) │ │
│ │ ┌───────────┐ ┌──────────┐ ┌──────────────┐ │ │
│ │ │ KV Block │ │ KV Char │ │ KV Library │ │ │
│ │ │ Device │ │ Device │ │ & Tools │ │ │
│ │ │(/dev/kvssd)│ │(ioctl) │ │ │ │ │
│ │ └─────┬─────┘ └────┬─────┘ └──────────────┘ │ │
│ └────────┼──────────────┼───────────────────────────┘ │
│ │ │ │
│ ┌────────┴──────────────┴───────────────────────────┐ │
│ │ nvme.ko + nvme-core.ko (NVMe KV命令集驱动) │ │
│ └────────────────────────┬──────────────────────────┘ │
├───────────────────────────┼────────────────────────────┤
│ Hardware │ PCIe │
│ ┌────────────────────────┴──────────────────────────┐ │
│ │ Samsung KV-SSD (PM983/PM9A3 modified firmware) │ │
│ │ ┌─────────┐ ┌───────────┐ ┌──────────────┐ │ │
│ │ │ KV Cmd │ │ nLSM/Hash │ │ NAND Flash │ │ │
│ │ │ Parser │→ │ FTL │→ │ (KV store) │ │ │
│ │ └─────────┘ └───────────┘ └──────────────┘ │ │
│ └──────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────┘
6.2 NVMeVirt模拟器与KVVirt FTL
首尔大学CNEX实验室(snu-csl)开发了NVMeVirt ------一个内核级NVMe设备模拟器,并扩展了KVVirt用于KV-SSD FTL研究:
bash
# KVVirt部署流程(引自github.com/snu-csl/kvvirt)
# 1. 预留内存(启动参数)
# GRUB_CMDLINE_LINUX="memmap=1G$600G" # 从600GB处预留1GB
# 2. 加载KVSSD内核模块
rmmod nvme nvme_core
insmod driver/nvme-core.ko
insmod driver/nvme.ko
# 3. 加载NVMeVirt模块(配置KV-SSD模拟参数)
insmod nvmevirt/nvmev.ko \
memmap_start=32G \ # 预留内存起始地址
memmap_size=128G \ # 模拟磁盘容量
cpus=35,36 \ # dispatcher线程→CPU35, IO线程→CPU36
gccpu=37 \ # GC线程→CPU37
evictcpu=38 \ # 驱逐线程→CPU38
cache_dram_mb=128 # DRAM缓存大小
# 4. 验证设备
sudo nvme list
# Node SN Model NS Usage Format FW Rev
# /dev/nvme0n1 CSL_Virt_SN_01 CSL_Virt_MN_01 1 128GB/128GB 512B+0B CSL_002
# 5. 运行YCSB基准测试
./examples/ycsb/ycsb \
--dir=/dev/nvme0n1 \
--num_pairs=100000000 \ # 1亿KV对
--vlen=1000 \ # Value长度1000字节
--threads=20 \
--num_ops=500000 \
--benchmarks=a \ # YCSB Workload A (50%读/50%更新)
--store_name=KVSSD \
--uniform=true
KVVirt的FTL实现包含两种方案:
- Original FTL:基于Hash Table的K2P映射(引自PinK项目)
- Plus FTL:优化的Hash FTL,增强小Value支持
6.3 Linux内核KVSSD驱动
Samsung的KVSSD内核驱动基于Linux 5.10.37修改,核心数据结构:
c
/* 简化的KVSSD设备结构(内核态) */
struct kvssd_device {
struct nvme_ctrl *ctrl; /* NVMe控制器 */
struct nvme_ns *ns; /* 命名空间 */
/* KV接口 */
struct kv_index *index; /* Key索引(Hash/LSM) */
struct vlog *vlog; /* Value日志(append-only) */
/* 内存结构 */
struct memtable *active_mt; /* 活动MemTable */
struct memtable *immutable_mt; /* 不可变MemTable(等待Flush) */
/* 配置 */
u32 max_key_size; /* 最大Key大小(16B) */
u32 max_value_size; /* 最大Value大小(4GB) */
u32 nand_page_size; /* NAND页大小 */
u32 block_size; /* 闪存块大小 */
};
/* KV操作接口 */
int kvssd_put(struct kvssd_device *dev, const u8 *key, u32 key_len,
const u8 *value, u32 value_len, u32 options);
int kvssd_get(struct kvssd_device *dev, const u8 *key, u32 key_len,
u8 *value, u32 *value_len);
int kvssd_delete(struct kvssd_device *dev, const u8 *key, u32 key_len);
int kvssd_exist(struct kvssd_device *dev, const u8 *key, u32 key_len);
七、SPDK对KV命令集的支持
7.1 SPDK NVMe KV接口API
SPDK(Storage Performance Development Kit)在其NVMe驱动中实现了KV命令集的用户态支持:
c
/* SPDK NVMe KV数据结构 */
/* KV控制器数据(Identify Controller扩展) */
struct spdk_nvme_kv_ctrlr_data {
/* KV特定能力字段 */
struct spdk_nvme_kv_kvfc kvfc; /* KV Format Capabilities */
struct spdk_nvme_kv_afo afo; /* Additional Format Options */
/* ... */
};
/* KV Format数据结构(16字节) */
struct spdk_nvme_kv_format {
__le32 ksze; /* Key Size (in bytes) - 0 means 1 byte key */
__le32 vsze; /* Value Size (max, in bytes) */
__le16 flags; /* 格式标志 */
__u8 rsvd[6];
};
/* KV命名空间数据 */
struct spdk_nvme_kv_ns_data {
/* 命名空间级KV能力 */
__le64 nkvze; /* Namespace KV Capacity */
__le64 nkvmu; /* Namespace KV Maximum Utilization */
/* ... */
};
/* KV操作码(SPDK定义) */
enum spdk_nvme_kv_opcode {
SPDK_NVME_OPC_KV_STORE = 0x01,
SPDK_NVME_OPC_KV_RETRIEVE = 0x02,
SPDK_NVME_OPC_KV_LIST = 0x06,
SPDK_NVME_OPC_KV_DELETE = 0x10,
SPDK_NVME_OPC_KV_EXIST = 0x14,
};
/* SPDK KV规范版本 */
#define SPDK_NVME_KV_SPEC_VER SPDK_NVME_VERSION(1, 3, 0)
/* KV Command Set specification version 1.3 */
7.2 用户态KV驱动实现
SPDK的KV驱动通过用户态NVMe驱动直接发送KV命令,绕过内核Block层:
c
/* SPDK KV Store操作伪代码 */
int spdk_kv_store(struct spdk_nvme_qpair *qpair,
struct spdk_nvme_ns *ns,
const void *key, uint32_t key_size,
void *value, uint32_t value_size,
spdk_nvme_cmd_cb cb_fn, void *cb_arg)
{
struct spdk_nvme_cmd cmd = {};
/* 构建KV Store命令 */
cmd.opcode = SPDK_NVME_OPC_KV_STORE;
cmd.nsid = spdk_nvme_ns_get_id(ns);
/* Key嵌入命令CDW10-CDW13 */
memcpy(&cmd.cdw10, key, key_size); /* Key ≤ 16B */
/* Value通过PRP传输 */
cmd.prp1 = spdk_vtophys(value, NULL);
if (value_size > 4096) {
cmd.prp2 = spdk_vtophys(value + 4096, NULL);
/* 更大Value需要PRP List */
}
/* CDW14: Key大小和选项 */
cmd.cdw14 = (key_size - 1) & 0xFF; /* 0-based key size */
/* CDW15: Value大小 */
cmd.cdw15 = value_size;
/* 提交命令到SQ */
return spdk_nvme_qpair_submit_cmd(qpair, &cmd, NULL, NULL,
value, value_size, cb_fn, cb_arg);
}
/* SPDK KV Retrieve操作 */
int spdk_kv_retrieve(struct spdk_nvme_qpair *qpair,
struct spdk_nvme_ns *ns,
const void *key, uint32_t key_size,
void *value, uint32_t *value_size,
spdk_nvme_cmd_cb cb_fn, void *cb_arg)
{
struct spdk_nvme_cmd cmd = {};
cmd.opcode = SPDK_NVME_OPC_KV_RETRIEVE;
cmd.nsid = spdk_nvme_ns_get_id(ns);
/* Key嵌入命令 */
memcpy(&cmd.cdw10, key, key_size);
/* 接收缓冲区 */
cmd.prp1 = spdk_vtophys(value, NULL);
cmd.cdw14 = (key_size - 1) & 0xFF;
return spdk_nvme_qpair_submit_cmd(qpair, &cmd, NULL, NULL,
value, *value_size, cb_fn, cb_arg);
}
八、KV-SSD vs Open-Channel SSD vs ZNS:三种接口范式对比
8.1 抽象层次对比
NVMe 2.0定义了三种主要的I/O命令集,代表了不同的抽象层次和设计哲学:
抽象层次对比(从高到低):
┌─────────────────────────────────────────────────────────────┐
│ KV-SSD(最高抽象) │
│ I/O单元: 变长Key-Value对 │
│ 主机职责: 发送PUT/GET命令 │
│ 设备职责: Key索引管理 + 数据放置 + GC + Compaction │
│ 优势: 完全消除主机端数据管理开销 │
│ 劣势: 设备固件复杂度极高,灵活性最低 │
├─────────────────────────────────────────────────────────────┤
│ ZNS(中等抽象) │
│ I/O单元: 顺序追加写Zone │
│ 主机职责: Zone管理 + 数据放置 + 垃圾回收 │
│ 设备职责: 保证Zone内顺序写,提供Write Pointer │
│ 优势: 主机可控数据放置,消除设备端GC │
│ 劣势: 主机需要实现完整的Zone管理逻辑 │
├─────────────────────────────────────────────────────────────┤
│ Open-Channel SSD(低抽象) │
│ I/O单元: 物理页地址(PPA: Channel/LUN/Page) │
│ 主机职责: 完整FTL(L2P映射、GC、磨损均衡、坏块管理) │
│ 设备职责: 仅执行物理读写擦 │
│ 优势: 最大灵活性,完全可定制的FTL策略 │
│ 劣势: 主机CPU和内存开销巨大,FTL开发难度极高 │
├─────────────────────────────────────────────────────────────┤
│ NVM Command Set(最低抽象/传统) │
│ I/O单元: 逻辑块(LBA) │
│ 主机职责: 发送读写命令 │
│ 设备职责: 完整FTL + GC + 磨损均衡 + 坏块管理 │
│ 优势: 兼容性最好,开发最简单 │
│ 劣势: 语义鸿沟最大,性能受限 │
└─────────────────────────────────────────────────────────────┘
8.2 适用场景分析
| 特性 | KV-SSD | ZNS | Open-Channel | NVM (传统) |
|---|---|---|---|---|
| 适用KVS | ✅ 原生 | ⚠️ 需适配 | ⚠️ 需适配 | ❌ 双重WA |
| 适用文件系统 | ❌ | ✅ (f2fs) | ❌ | ✅ |
| 适用数据库 | ✅ | ⚠️ | ⚠️ | ✅ |
| 主机CPU开销 | 低 | 中 | 高 | 低 |
| 设备固件复杂度 | 极高 | 低 | 极低 | 中 |
| 写放大控制 | 设备端 | 主机端 | 主机端 | 设备端 |
| 延迟可预测性 | 中 | 高 | 高 | 低 |
| 生态成熟度 | 早期 | 增长中 | 已停止 | 成熟 |
| Linux内核支持 | 第三方 | ✅ 6.x+ | ❌ 已移除 | ✅ |
| 主要推动者 | Samsung/SK hynix | HGST/Ultrastar | CNEX Labs | 全行业 |
重要事实 :Linux内核对Open-Channel SSD的LightNVM子系统支持已在5.x版本周期中被移除,主要原因是维护者不足以及ZNS/ZNS的出现提供了更好的替代方案。SNIA(存储网络工业协会)在2022年公开讨论中明确指出**"KV-SSD will replace ZNS"**的观点,认为KV接口最终将取代ZNS成为下一代存储接口标准。
九、前沿方向:AI推理KV Cache卸载
2024-2025年的一个热门前沿方向是将KV-SSD应用于大语言模型(LLM)推理的KV Cache卸载。
LLM推理KV Cache层级存储架构:
┌──────────────────────────────────────────────────────┐
│ Tier 1: GPU HBM (最快,最小) │
│ ┌────────────────────────────────────────────────┐ │
│ │ 当前活跃token的K/V向量 │ │
│ │ 容量: 16-80GB, 带宽: 2-3.35 TB/s (HBM3e) │ │
│ │ 延迟: ~1ns │ │
│ └──────────────────────┬─────────────────────────┘ │
│ │ 溢出 │
│ Tier 2: Host DRAM (中等) │
│ ┌──────────────────────┴─────────────────────────┐ │
│ │ 近期token的K/V向量(CPU可达) │ │
│ │ 容量: 256GB-2TB, 带宽: 50-100 GB/s │ │
│ │ 延迟: ~100ns │ │
│ └──────────────────────┬─────────────────────────┘ │
│ │ 卸载 │
│ Tier 3: NVMe SSD (大容量) │
│ ┌──────────────────────┴─────────────────────────┐ │
│ │ 历史对话/前缀缓存的K/V向量 │ │
│ │ 容量: 3.84TB-61.44TB, 带宽: 7-14 GB/s │ │
│ │ 延迟: ~10-100μs │ │
│ │ │ │
│ │ KV-SSD优势: 直接以KV对存储K/V Cache │ │
│ │ Key = (session_id, layer_id, token_pos) │ │
│ │ Value = K/V向量数据 │ │
│ └────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────┘
Samsung在2025年发布的白皮书中展示了使用其Z-SSD(超低延迟SSD)配合LMCache软件实现LLM推理KV Cache的SSD卸载,在8GPU推理服务中实现了约36GB/s的平均KV Cache吞吐量。
KV-SSD在这一场景中的独特优势:
- 消除Block层开销:KV Cache本身就是键值结构,KV-SSD可以直接接收KV对而无需转换为块I/O
- 减少写放大:KV Cache写入是append-only模式,与KV-SSD的vLog设计完美匹配
- 快速前缀缓存恢复:通过Key直接检索之前的K/V Cache,避免重复计算
十、当日知识点小结与思考题
📊 知识点小结
| 知识点 | 核心内容 | 重要程度 |
|---|---|---|
| NVMe KV命令集 | TP4091提案→NVMe 2.0标准,5条命令(Store/Retrieve/List/Delete/Exist) | ⭐⭐⭐⭐⭐ |
| Key约束 | 最大16字节,变长,嵌入SQE的CDW10-CDW13 | ⭐⭐⭐⭐ |
| Value约束 | 最大4GB,通过PRP/SGL传输 | ⭐⭐⭐⭐ |
| 4KB对齐问题 | PRP强制4KB DMA传输,32B Value导致128x PCIe流量膨胀 | ⭐⭐⭐⭐⭐ |
| BandSlim优化 | 命令内联piggyback,减少97.9% PCIe流量 | ⭐⭐⭐⭐ |
| nLSM Tree | 闪存原生LSM-Tree,K2P映射替代L2P | ⭐⭐⭐⭐ |
| Remapping Compaction | 只重写元数据指针,写放大降至0.12x | ⭐⭐⭐⭐ |
| KV-CSD | 设备端LSM-Tree引擎,比RocksDB快7.9x(2核) | ⭐⭐⭐⭐⭐ |
| KV-SSD vs ZNS | KV最高抽象→设备管全部;ZNS中等→主机管放置 | ⭐⭐⭐⭐ |
| AI KV Cache | LLM推理的三级存储卸载,KV-SSD天然适配 | ⭐⭐⭐⭐ |
🤔 思考题
题目1:NVMe KV命令集将Key限制为16字节,但现代内容寻址存储(CAS)系统常用SHA-256(32字节)作为Key。请分析这种限制的设计动机,并提出两种在16字节约束下实现CAS功能的方案,分析各方案的优劣。
题目2:BandSlim利用NVMe命令的保留字段内联传输小Value(≤35字节/命令)。请思考:如果CXL互连普及(支持字节粒度远程内存访问),BandSlim的内联方案是否还有存在的必要?CXL的byte-granularity access如何从根本上解决4KB对齐问题?
题目3:KV-SSD将Compaction卸载到设备端执行,显著降低主机CPU占用。但在多租户云环境中,不同租户的KV工作负载竞争同一SSD的Compaction资源。请设计一个公平的Compaction资源调度策略,考虑QoS隔离(金/银/铜级别)和Compaction优先级与写放大的权衡。
📚 参考资料
- NVM Express Key-Value Command Set Specification Rev 1.0
- BandSlim: A Novel Bandwidth and Space-Efficient KV-SSD (ICPP 2024)
- KVSSD: Close integration of LSM trees and FTL for write-efficient KV store (DATE 2018)
- KV-CSD: A Hardware-Accelerated Key-Value Store (IEEE Cluster 2023)
- Samsung OpenMPDK/KVSSD GitHub Repository
- KVVirt: KVSSD FTLs on NVMeVirt (snu-csl)
- NVMe 2.0 Key-Value Command Set (Gluesys Tech Blog)
- SAKER: Software Accelerated Key-value Service via NVMe Interface
- Optimizing NVMe-Based KV Interfaces (Soongsil University Seminar 2025)
- SPDK NVMe Specification Header (nvme_spec.h)
- Why KV SSD will replace ZNS (SNIA, Tomlin 2022)
- LightNVM: The Linux Open-Channel SSD Subsystem
作者持续更新中,关注获取每日SSD硬核知识 👆