ConfZNS分析
最近的学校项目涉及ZNS(Zone NameSpace)SSD,需要我们了解ZNS的实现机制以及confZNS的原理,其中涉及的知识之庞杂,代码量之多,非我等小可所能完全吸收。在这里浅浅分析一下。
SSD设备和ZNS协议 background
当谈论SSD设备时,它是一种固态存储设备,全称为“Solid State Drive”,它不像传统的机械硬盘使用旋转的磁盘和机械臂来读写数据,而是使用闪存芯片来存储数据。SSD具有许多优点,例如更快的读写速度、更低的能耗、更小的体积和更高的抗震性能。它们在现代计算机和数据中心中广泛应用,能够显著提升系统性能和响应速度。
至于ZNS协议,它是“Zoned Namespace”(分区命名空间)的缩写。ZNS是一种NVMe(Non-Volatile Memory Express)协议的扩展,它允许SSD将存储空间划分为多个固定大小的分区或“Zone”。每个Zone内部的数据可以进行连续的顺序写入,但不能进行随机写入。ZNS协议的主要目的是优化SSD设备的写入性能,特别是在大规模数据写入场景下。
那么问题来了,NVMe协议是什么?他们和传统的SATA和SAS协议的异同点是什么?来一起看下
传统协议和ZNS协议
SATA协议(Serial ATA):
SATA协议是一种用于连接计算机主板和存储设备(如硬盘和固态硬盘)之间的接口协议。它是一种串行传输的接口,用于替代传统的并行ATA(IDE)接口。SATA接口通常用于连接传统硬盘和低端固态硬盘,提供中等的数据传输速率和较低的延迟。
SAS协议(Serial Attached SCSI):
SAS协议是一种用于连接存储设备和服务器之间的接口协议。它是一种串行传输的接口,基于SCSI标准,并支持高可靠性和高性能的数据传输。SAS接口通常用于连接高性能的企业级硬盘和磁带库等设备,提供更高的数据传输速率和更低的延迟。
NVMe协议(Non-Volatile Memory Express):
NVMe协议是一种用于连接固态存储设备(如SSD)和计算机系统之间的接口协议。它是一种高性能、低延迟的接口,专门为固态存储设备而设计。NVMe接口采用PCI Express总线,并通过多队列和多核心技术来支持并发操作,提供更快的数据传输速率和更低的延迟。
ZNS协议(Zoned Namespace):
ZNS协议是在NVMe协议基础上扩展而来的,用于管理分区的固态存储设备。ZNS将物理存储空间划分为多个逻辑分区(命名空间),每个分区内的写入必须按照顺序进行,类似于磁带的顺序写。ZNS可以提高设备的写入效率,同时减少写入时的随机寻址,适用于写入密集型的工作负载。
有些晕了…来一个表格似乎更加直观
SATA | NVMe | ZNS | |
---|---|---|---|
传输接口 | 串行传输的接口协议 | 基于PCI Express的高速串行接口 | 在NVMe协议基础上进行扩展的,用于管理分区的固态存储设备 |
性能特点 | 适用于一般桌面应用和企业级应用,提供中等性能和可靠性 | 性能方面有显著优势,提供更高的数据传输速率和更低的延迟,适用于高性能计算和数据中心应用 | 同NVMe |
适用场景 | 连接传统硬盘和低端固态硬盘,适用于一般桌面和中小型企业服务器 | 用于高性能计算和数据中心应用,连接高性能固态硬盘(SSD) | 适用于写入密集型的工作负载,可以提高设备的写入效率。 |
命名空间 | 无 | 支持命名空间的概念,允许将物理存储空间划分为多个逻辑单元,每个命名空间都可以被视为一个独立的存储设备,提供更灵活的数据管理方式。 | 同NVMe |
设备类型 | 用于连接传统硬盘和企业级硬盘 | 连接固态硬盘(SSD) | 连接固态硬盘(SSD) |
性价比 | 相对较便宜,适用于预算有限的用户 | 性能更高,但价格也相对较高 | 同NVMe |
ZNS协议解决的问题
ZNS-SSD的出现主要是为了解决传统的Block Interface SSD(例如使用NVMe协议的Flash SSD)在某些场景下面临的一些问题。以下是一些传统Block Interface SSD存在的问题:
- 写入效率不高:传统SSD使用固定大小的块(通常为4KB或8KB),在写入时必须按照块为单位进行写入。对于小于一个块大小的数据写入,需要进行块对齐和补齐操作,导致写入效率不高。
- 垃圾回收和写放大:由于传统SSD的块大小固定,写入和擦除操作都是以块为单位进行的。当进行部分块的更新或删除时,需要先将整个块读取到内存中,进行修改后再整块写回,导致写放大问题和垃圾回收的开销。
- 寿命问题:由于传统SSD的擦除操作是以块为单位进行的,频繁的小块写入和擦除会导致SSD的寿命缩短。
- 数据分布不均衡:传统SSD中的块分配和擦除管理策略可能导致数据在不同块之间的分布不均衡,称为写入热点问题。
- 随机写性能:传统SSD在随机写入操作时可能面临性能下降,尤其是在块擦除和写入操作频繁时。
ZNS-SSD通过引入Zoned Namespace(分区命名空间)来解决这些问题。在ZNS-SSD中,存储空间被划分为多个Zone(区域),每个Zone内的写入操作必须按照顺序进行,从而避免了块对齐和补齐的问题。ZNS-SSD支持顺序写入,可以提高写入效率和减少写放大问题。此外,ZNS-SSD还通过合理规划Zone来均衡数据分布,提高随机写性能,并通过管理Zone的方式延长SSD的寿命。因此,ZNS-SSD可以更好地适应写入密集型的工作负载和大规模数据写入场景。
在随机写性能方面,我多查了一些资料。先说结论:在某些特定工作负载下,ZNS-SSD在随机写入性能方面可能会相对优于传统的Block Interface SSD,特别是当数据写入是以较大的连续块为单位进行时。然而,这并不意味着ZNS-SSD在所有随机写入场景下都优于传统SSD。对于小块随机写入,传统SSD可能仍然具有优势。
- 随机写支持方式:
- Block Interface SSD:传统的Block Interface SSD使用逻辑块(Logical Block)作为最小的可寻址单元。随机写操作可以直接在逻辑块级别进行,即可以在任意逻辑块上写入数据,无需关心实际的物理布局。
- ZNS SSD:ZNS SSD采用了Zoned Namespace技术,将存储空间划分为一系列称为Zone的连续区域。每个Zone都有固定的容量,且必须按照顺序写入,不支持随机写入。在随机写入数据时,需要将数据写入到当前活动的Zone中,并且在Zone被填满之后,才能切换到下一个Zone进行写入。
- 随机写性能差异:
- Block Interface SSD:由于Block Interface SSD支持随机写入,因此在随机写入小块数据时表现较好。随机写性能通常以IOPS(每秒I/O操作数)和延迟(响应时间)为主要指标。
- ZNS SSD:ZNS SSD在设计上更侧重于优化顺序写性能,因为随机写入会导致Zone切换和写入位置的变化,从而影响性能。在随机写入数据时,ZNS SSD的性能相对较差,尤其是在涉及多个Zone的情况下。因此,对于随机写入工作负载,传统的Block Interface SSD可能表现更好。
因此,ZNS SSD的设计是针对特定的工作负载场景,例如冷存储、日志记录等,对于需要大量随机写入的工作负载,传统的Block Interface SSD可能更适合。
ZNS architect
1. 核心架构
Zoned Namespace (ZNS) 是一种新型的SSD架构,它将存储空间划分为一系列称为Zone的连续区域,每个Zone都有固定的容量。ZNS架构主要由以下几个组件构成:
Zone:Zone是ZNS架构的基本单元,它是一段连续的存储空间,具有固定的容量。在ZNS中,数据必须按照顺序写入Zone,而不能随机写入。Zone通常比传统SSD中的块(Block)更大,这有助于减少读-修改-写(Read-Modify-Write)的操作,提高写入性能。
Zone Management:Zone Management负责管理Zone的状态和使用情况。每个Zone都有一个状态,包括空闲、打开(Open)、关闭(Closed)、读写保护(Read-Only)等状态。Zone Management可以实现自动打开和关闭Zone,以便在写入过程中实现数据的顺序写入。此外,Zone Management还负责处理Zone的空间回收和回收策略,以最大程度地减少擦除操作。
Zone Report:Zone Report是用于获取Zone信息的接口,它可以告知主机有关Zone的状态、容量和健康状况等信息。主机可以通过Zone Report来了解SSD的Zone布局,从而更好地进行数据管理和写入优化。
Zoned Block Device:Zoned Block Device是一个抽象层,用于将ZNS架构与主机系统的块设备接口对接。它负责将传统的块设备操作转换为Zone的顺序写入操作。Zoned Block Device可以通过读取Zone Report来确定Zone的写入状态,并将数据按照Zone的规则进行写入,以保证数据的顺序写入特性。
ZNS架构的工作原理是,主机系统通过Zoned Block Device进行数据的写入和读取操作,而Zoned Block Device则利用Zone Management来管理Zone的状态,并保证数据的顺序写入。在写入过程中,主机将数据写入当前打开的Zone,当Zone写满后,Zone Management会自动关闭当前Zone并打开下一个空闲的Zone,从而实现数据的连续写入。当Zone已经关闭且不再接受数据时,主机需要通过Zone Report获取新的可写Zone,并继续写入数据。
2. 软件层面的修改
为了评估ZNS带来的好处,对四个重要的软件项目进行的修改和开发工作。具体来说,首先对Linux内核进行了修改,以支持ZNS SSD。其次,修改了f2fs文件系统,以评估在更高级别的存储堆栈层面上进行区域集成的好处。第三,修改了fio基准测试工具,以支持新添加的ZNS特定属性。第四,开发了ZenFS,这是一个新颖的RocksDB存储后端,通过区域控制数据的放置,以评估区域存储的端到端集成的好处。
We have added support to four major software projects to evaluate the benefits of ZNS. First, we made modifications to the Linux kernel to support ZNS SSDs. Second, we modified the f2fs file system to evaluate the benefits of zone integration at a higher-level storage stack layer. Third, we modified the fio [6] benchmark to support the newly added ZNS-specific attributes. Fourth, we developed ZenFS [25], a novel storage backend for RocksDB that allows control of data placement through zones, to evaluate the benefits of end-to-end integration for zoned storage. We describe the relatively few changes necessary to support ZNS when building upon the existing ZAC/ZBC support for the first three projects [5, 42, 52] (§4.1) and finally detail the architecture of ZenFS (§4.2).
对以上四个层面的原理在参考论文中已经详细介绍,且跟后续的confZNS原理理解相互独立,在此不再赘述。(我承认zenfs的组件好多,我有些看不下去了)
ConfZNS
background
ConfZNS模拟器用于探索和理解ZNS固态硬盘(SSD)的设计空间。ConfZNS支持多种ZNS SSD的区域映射方式,并允许从内部设备结构到应用软件的完整堆栈探索。该模拟器具有时间精确性,对于存储研究社区来说是一个多功能工具。文章ConfZNS通过与两个不同厂商的真实ZNS SSD进行实验,并与之前一项研究的测量结果进行验证,证明了ConfZNS的有效性。文章还探讨了ConfZNS在使用硬件和软件参数对各种软件(如F2FS、RocksDB和Docker)在不同ConfZNS配置下的性能进行评估和比较的潜力。ConfZNS预计将促进ZNS SSD硬件及其相关软件的优化。
First, ConfZNS supports diverse zone mappings of ZNS SSD.
Second, ConfZNS is time-accurate.
Third, ConfZNS allows a full stack exploration from the internal device structure to the application software.
那么confZNS和ZNS的区别是什么?
ConfZNS和ZNS之间的区别在于它们的功能和用途。ZNS 是一种新一代的固态硬盘,通过改变SSD和主机之间的存储管理责任分配,以及利用硬件和软件层面的内部并行性,来解决传统块状存储器的性能和资源相关问题。而ConfZNS是一个用于探索和理解ZNS SSD设计空间的仿真器,它支持各种ZNS SSD的区域映射配置,从SSD内部结构到应用软件的全栈探索,并且具有时间精确度,因此它是存储研究领域的一个多功能工具。
ConfZNS architect
ZNS的组成包括以下几个关键组件:
1. ZNS配置器
用户通过提供配置文件来灵活配置ZNS固态硬盘的硬件参数,例如zone的大小、区域重置时间以及通道/路向区域的映射等。此外,还可以设置基本的SSD配置参数,如通道/路的数量、芯片的块/页大小、编程/读取/擦除时间、主机接口带宽限制等。
翻一下源码:
- 初始化ZnSSD控制器
- 配置ZnSSD控制器参数和特性
- 初始化Zone的几何属性和标识信息
1 |
|
在代码中,zns_exit
函数的函数体是空的,即没有实际的释放资源操作。这可能是因为在当前的代码实现中,并没有为 ZNS 模式分配额外的资源(例如 Zones),或者在控制器退出时不需要特定的资源清理操作。根据参考代码中的数据结构,合理补充 zns_exit
函数如下:
1 |
|
2. ZNS结构
逻辑页和物理页的映射
ZNS的映射是指在ZNS SSD中逻辑页与物理页之间的关联。ZNS SSD将存储空间划分为多个zone,每个区域包含一组逻辑页。映射关系决定了逻辑页如何映射到物理页,从而影响了ZNS设备的性能。
ZNS SSD的映射可以分为三种类型:单一并行单元映射(SU-zone)、多个并行单元映射(MU-zone)和全部并行单元映射(FU-zone)。在SU-zone映射中,一个区域仅映射到一个并行单元,而在FU-zone映射中,一个区域可以利用所有的并行单元。MU-zone映射介于两者之间,一个区域映射到多个并行单元。
ZNS SSD的映射由ZNS架构进行管理。首先,ZNS架构构建一个用户配置的通道-路组织结构。然后,它建立一个映射函数或表来关联区域和并行单元。大多数情况下,使用映射函数,但在映射比较复杂时,ConfZNS使用映射表。例如,当配置硬件以支持单个设备内的混合映射时,ConfZNS使用映射表。
在ZNS SSD中,逻辑页和物理页之间的映射是通过通道(channels)和路(ways)进行的。通道表示SSD中的通道数量,路表示每个通道中的路数量。
假设有一个ZNS SSD设备由4个通道和2个路组成,则逻辑页的映射关系如下:
- 第一个逻辑页(LPN)被映射到通道0和路0上的物理页(PPN)。
- 第二个LPN被映射到通道1和路0上的PPN。
- 第三个LPN被映射到通道2和路0上的PPN。
- 第四个LPN被映射到通道3和路0上的PPN。
- 第五个LPN被映射到通道0和路1上的PPN。
- 以此类推,映射规则循环重复。
在这种映射方式下,逻辑页和物理页的映射关系能够最大化SSD的吞吐量,并且通过通道和路的方式实现。具体的映射方式和规则可以根据ZNS SSD设备的配置和设计来进行调整和修改。
confZNS对地址映射的实现我在代码库中进行了仿真和调整,具体结果可以参考confzns_analyze
femu分析
翻一下femu源码:
1 |
|
关于 lpn_to_ppa
函数,首先,它通过调用zns_zone_idx函数计算LPN对应的区域索引(zone_idx)。然后,通过zns->wp结构体指针(写指针)获取当前通道和LUN,并将这些信息与区域索引合并成一个PPA。最后,将构建的PPA返回。
这种映射方式的问题在于,它没有考虑到不同Zone内部的地址映射。在ZNS-SSD中,Zone是一个连续的区域,而每个Zone内部的物理地址映射是独立的。然而,lpn_to_ppa函数中只使用了一个全局的通道号和LUN号,导致所有Zone内部的映射都是一样的。
在实际的ZNS-SSD中,不同Zone内部的映射是可以不同的,因为不同Zone可能使用不同的写入策略、擦除策略等。如果所有Zone都使用同样的通道号和LUN号,就会导致不同Zone之间的映射混乱,影响到数据的读写和擦除效率。
为了更准确地模拟ZNS-SSD的映射方式,lpn_to_ppa函数应该考虑到不同Zone内部的映射差异,确保每个Zone内部的地址映射都是独立的,而不是简单地使用全局的通道号和LUN号。这样才能更好地模拟ZNS-SSD的性能和行为。
在看 zns_zone_idx
函数的时候其实是有些懵的:为什么要 zone_size_log2
来做判断条件?为什么分支计算分别是右移和做除法?zone_size_log2
和 zone_size
的区别是什么?为什么为什么为什么?后来我想通了:
如果 zone_size_log2
大于 0,则说明 Zone 大小是固定的,是以 2 为底的对数值,表示每个 Zone 的大小是 2 的多少次幂。例如,如果 zone_size_log2
等于 12,表示每个 Zone 的大小是 2^12 = 4096 个逻辑块(Logical Block)。在这种情况下,通过右移 zone_size_log2
位,可以快速计算逻辑块地址 slba
属于哪个 Zone。与此相对应的是,如果 zone_size_log2
小于等于 0,则说明 Zone 大小是固定的块数(block count),而不是以 2 为底的对数值。例如,如果 zone_size
等于 128,表示每个 Zone 的大小是 128 个逻辑块(Logical Block)。在这种情况下,直接通过除法运算来计算逻辑块地址 slba
属于哪个 Zone。
两种方式都可以用来确定逻辑块地址所属的 Zone,但方式不同。固定的 zone_size_log2
方式可以通过移位运算更高效地计算,而固定的块数方式则需要进行除法运算。妙啊!
1 |
|
confZNS分析
1 |
|
在上述代码中,提到的不同通道配置是指存储设备中的通道数可能不同,也就是 struct zns_ssdparams
结构体中的 spp->nchnls
字段。不同的存储设备可能会有不同的通道数,这取决于硬件的设计和配置。
在代码中,通道数的配置主要涉及到以下几个地方:
zns_get_ns0_zone_ppn_idx()
函数中:1
2
3
4
5uint64_t now_avail_chnls = spp->chnls_per_another_zone;
if (spp->chnls_per_another_zone > spp->nchnls) {
femu_err("Wrong setting : spp->chnls_per_another_zone > spp->nchnls \n");
return 0;
}这里通过
spp->chnls_per_another_zone
来设置通道数,然后根据该通道数进行计算。这样可以根据不同的通道配置,计算第一个命名空间的区域物理页号(PPN)索引。zns_another_ns1_zone_ppn_idx()
函数中:1
2
3
4
5uint64_t now_avail_chnls = spp->nchnls - spp->chnls_per_another_zone;
for (uint64_t i = 0; i > 10; i++) {
femu_err("zns_another_ns_elastic:zns.c:172 [ spp->nchnls < spp->chnls_per_another_zone ] \n");
}这里通过
spp->nchnls - spp->chnls_per_another_zone
来设置通道数,然后根据该通道数进行计算。这样可以根据不同的通道配置,计算另一个命名空间的区域物理页号(PPN)索引。zns_advanced_chnl_idx()
函数中:1
return zns_get_multiway_chip_idx(ns, slba) % spp->nchnls;
这里使用
spp->nchnls
来获取通道数,然后根据该通道数计算给定逻辑块地址所属的通道索引。
通道数的配置影响了物理地址计算中的一些参数和计算方式,通过调整通道数,可以在不同的硬件配置下实现不同的映射策略,从而优化存储设备的性能和效率。
综合上述函数,可以看出ConfZNS中采用了多层的映射方式,首先将逻辑地址映射到不同的通道、路、平面,然后再根据通道和路的映射关系计算物理地址。这样的多层映射方式使得物理地址的计算更加灵活,并且可以根据硬件配置和应用需求进行调整。
这种映射方式的优势包括:
- 灵活性和可扩展性 :ConfZNS允许在不同的配置下进行映射,包括多通道、多路和高级平面映射等。这种灵活性使得ConfZNS能够适应不同的硬件架构和应用场景,具有较强的可扩展性。
- 性能优化 :通过多层映射,ConfZNS可以根据硬件配置和数据访问模式进行优化。例如,多通道和多路映射可以提高并行度,高级平面映射可以减少平面之间的干扰,从而提高存储设备的性能。
- 支持不同命名空间配置 :ConfZNS支持多个命名空间,并且可以根据不同的命名空间配置进行物理地址映射,从而为不同应用场景提供更好的性能和定制化的映射策略。
实现Zone的管理和状态转换
通过检查读写操作是否在有效的 Zone 范围内、自动打开新的 Zone 以继续写入数据,并根据写入操作的块数更新 Zone 的写指针等操作,有效地管理和维护 Zoned Namespace 的状态。
1 |
|
实现Zone内数据的写入、读取和追加写入
可以根据读写操作的起始地址和块数,在 Zoned Namespace 中执行相应的读取和写入操作,并根据 Zone 的状态和数据分布进行相应的处理和管理。
1 |
|
实现Zone管理指令(Zone Management Command)的处理
这些函数用于处理 Zone 管理指令,根据传入的请求参数 req,执行相应的 Zone 管理操作。Zone 管理指令是 NVMe 协议中针对 Zoned Namespace 的特有指令,用于管理和控制 Zone 的状态和属性。在这些函数中,会根据不同的 Zone 管理指令的具体要求,对 Zoned Namespace 中的 Zone 进行相应的操作,例如打开 Zone、关闭 Zone、重置 Zone 等。这些操作是 Zoned Namespace 特有的管理功能,用于优化 Zoned SSD 设备的性能和寿命。
1 |
|
实现Zone报告指令(Zone Report Command)的处理
用于处理 Zone 报告指令,根据传入的请求参数 req,生成 Zone 报告数据并返回给主机。Zone 报告指令是 NVMe 协议中针对 Zoned Namespace 的特有指令,用于向主机报告当前 Zone 的状态和属性信息。在这个函数中,会根据 Zoned Namespace 的状态和当前 Zone 的信息,生成相应的 Zone 报告数据,并通过 NVMe 设备的数据传输功能将数据返回给主机。这样,主机就可以获取到 Zoned Namespace 中各个 Zone 的状态,从而进行合理的数据管理和优化策略。
1 |
|
3. 时间估算器
ConfZNS中的时间估算器负责管理整个仿真过程中的时间准确性。它通过考虑服务时间和排队延迟来评估I/O请求的延迟。服务时间由用户给出,而延迟时间取决于所请求的资源是否正在使用或可用,以及队列中有多少先前的请求。排队延迟是通过使用全局和局部时钟分析资源争用来估算的。
时间估算器通过层级时钟算法来识别资源争用和等待请求的数量。它使用两个时钟,一个是全局时钟(𝑔𝑐),一个是局部时钟(𝑙𝑐)。全局时钟以每个时钟周期递增,而局部时钟是为每个资源分配的。局部时钟被设置为相关资源的下一个可用时间。当请求到达资源时,将相关资源的局部时钟设置为𝑙𝑐 = 𝑚𝑎𝑥 (𝑔𝑐,𝑙𝑐) + service_time,即下一个可用时间。
全局时钟和局部时钟满足以下性质:如果局部时钟小于等于全局时钟,则与局部时钟相关的资源处于空闲状态。否则,该资源正在忙碌状态。我们还可以通过两个时钟的差异来确定等待请求的数量。例如,假设某个资源的服务时间为2,并且全局时钟和局部时钟都为0。经过1个时钟周期后,如果没有请求到达该资源,全局时钟变为1,而局部时钟仍为0,这意味着该资源处于空闲状态。如果有请求到达该资源,局部时钟变为3,这意味着该资源在全局时钟为3之前都处于忙碌状态。
以读取请求和写入请求的延迟估计为例,ConfZNS利用逻辑页号(LPN)和物理页号(PPN)来估算延迟时间。在不同的区域映射下,LPN和PPN的对应关系不同,从而影响延迟时间的估计。
femu分析
翻一下源码,femu实现:
1 |
|
NAND闪存是SSD中常见的存储介质,其读写和擦除操作需要通过特定的NAND命令来执行。常见的NAND命令包括读取(NAND_READ)、写入(NAND_WRITE)和擦除(NAND_ERASE)。
计算NAND命令的执行时间是为了模拟SSD的读写延迟和擦除延迟,从而更真实地模拟SSD的性能表现。在实际的SSD中,NAND闪存芯片执行不同操作的时间存在差异,例如,读取速度通常较快,写入速度较慢,而擦除速度较为缓慢。这些延迟会影响到SSD的整体性能和数据访问效率。
通过计算NAND命令的执行时间,代码可以在模拟的SSD中引入实际的读写延迟和擦除延迟,以便更准确地模拟SSD的行为。
confZNS分析
confZNS的实现code:
1 |
|
这段代码是针对 NVMe命名空间进行管理的函数,主要处理读写请求,并对 NVMe 命令进行处理以实现模拟的时延。具体功能如下:
首先,从 NVMe 命令结构中解析出相关信息,如读/写命令、操作码等。
根据操作码执行相应操作:
- 如果是
NVME_ZONE_ACTION_RESET
,则调用znssd_reset_zones
函数来重置 zone,将 zone 的写指针(wp)和状态(status)重置,并将其状态设置为空(Empty)。 - 对于读(
NVME_CMD_READ
)和写(NVME_CMD_WRITE
)命令,根据req->is_write
来判断是执行读还是写操作,并调用相应的函数znsssd_write
或znsssd_read
来处理读写请求。
经过学长的指点,还是有些方面考虑不周,例如应该分析ssd请求执行各个阶段的时延模拟。
SSD请求执行包括以下几个主要阶段:
- 发送命令(Submission Queue):SSD接收来自主机的请求,包括读取(Read)、写入(Write)、擦除(Erase)等命令。
- 控制器处理(Controller Processing):SSD控制器接收并解析来自主机的请求,然后根据请求类型执行相应的操作,例如查找映射表、处理垃圾回收、执行写入、擦除等操作。
- NAND Flash操作:控制器根据请求中的地址信息,将数据从NAND Flash中读取出来(读操作),或者将数据写入NAND Flash(写操作)。
- 数据传输(Transfer Data):在执行写入请求时,数据还需要从主机传输到SSD的内部缓存,然后再写入到NAND Flash中。
- 完成请求(Completion Queue):SSD操作完成后,控制器将结果通知给主机,表明请求已完成,并将结果返回给主机。
在 confzns
中,针对ZNS SSD的请求执行时延进行了模拟。主要是通过在执行不同阶段的代码中插入时延相关的逻辑,来模拟SSD实际执行请求时的时延情况。以下是具体的模拟方式:
- 在
znsssd_read
和znsssd_write
函数中,通过更新req->expire_time
的方式模拟执行时延。在这两个函数中,会调用zns_advance_status
函数来模拟控制器处理阶段的时延。在这个函数中,会根据请求的类型和地址信息,计算出执行该请求所需要的时延,并加到req->expire_time
上,模拟控制器的处理时间。 - 在
backend_rw
函数中,模拟数据传输的时延。在模拟时,可以根据数据传输的大小和传输速度,计算出传输所需要的时间,并将其加到req->expire_time
上,模拟数据传输的时延。 - 在
zns_advance_zone_wp
函数中,模拟NAND Flash的操作时延。在这个函数中,会模拟执行写入操作后,更新写指针的操作,并计算出NAND Flash的写入时间,并加到req->expire_time
上,模拟NAND Flash的操作时延。 - 在
zns_reset_zones
函数中,模拟执行Zone Reset操作的时延。在这个函数中,会模拟执行Zone Reset操作后,更新相应的时间,并计算出Zone Reset的执行时间,并加到req->expire_time
上,模拟Zone Reset操作的时延。
通过以上的模拟方式,confzns
可以在模拟环境中合理地模拟SSD请求执行过程中的时延,并根据实际参数设置来调整模拟的准确性。这样可以更好地了解和评估SSD在不同场景下的性能表现。但也存在一些不足之处:
- 缺乏实际硬件特性:实际的SSD硬件在执行请求时可能会有更复杂的时序和操作流程,例如垃圾回收、错误处理等。这些硬件特性在
confzns
中可能没有得到充分的模拟。 - 缺少多线程/并发模拟:在实际SSD中,多个请求可能会同时进行,涉及多线程/并发操作。
confzns
中的简单模拟可能无法模拟这种并发场景,因此在真实的SSD中,性能表现可能会与confzns
中的模拟不同。 - 依赖假设和固定参数:
confzns
中的模拟方式基于一些假设和固定的参数设置,这些参数可能无法完全覆盖不同SSD的实际情况。因此,confzns
的模拟结果可能无法适用于所有SSD型号和配置。
关于FEMU如何模拟这些阶段的时延,代码中似乎没有具体的实现细节。
为什么 ConfZNS 更加准确,而 FEMU 存在问题:
- ConfZNS 使用 NVMe 命名空间模拟,因此其时延模拟更加细粒度,同时根据请求的不同类型进行区分处理。这种精细的时延模拟可以更好地反映真实的 SSD 设备行为,因为现代 SSD 设备通常支持多种操作,如读、写、擦除、重置等,并且每种操作都有自己特定的时延特征。同时,confzns通过在不同的ssd请求执行阶段插入时延的逻辑来模拟ZNS SSD请求执行的时延情况,这将会得到一个更准确的时延模型。
- FEMU 虽然提供了时延模拟,但其延迟设置是硬编码的,没有考虑实际 SSD 设备的特性和不同操作之间的时序关系。这可能导致模拟的结果与真实设备的行为不一致,特别是当 SSD 设备具有复杂的内部状态转换和时序要求时,FEMU 的模拟可能会产生不准确的结果。
综上所述,尽管两者都提供了一种形式的时延模拟,但 ConfZNS 更加准确和灵活,因为它模拟了更细粒度的 NVMe 命令,并根据不同请求类型进行区分处理,在不同的命令阶段都有模拟时延的逻辑。而 FEMU 的模拟虽然可行,但在时延设置上相对简单且不够准确,可能无法完全符合真实 SSD 设备的行为。
- 资源监视器
资源监视器收集各种ZNS SSD内部的统计数据,如各通道和路的利用率,有助于分析SSD的I/O分布能力和功耗。此外,它还报告各个单位的块擦除计数和I/O请求的来源(NVMe提交队列标识符)等内部数据。
总之,ZNS的组成包括ZNS配置器、ZNS结构、时间估算器和资源监视器。这些组件共同构成了ConfZNS这个用于仿真和研究ZNS SSD的工具。
运行confZNS
主要操作就是拉取ConfZNS源码,按照readme来配置相关运行环境,成功运行该仿真器并能跑OS就可以了。(指能运行./run-zns.sh)。
然而呢,配置之路并不是一帆风顺的,在此简短记录一下我的采坑过程😭
OS限制
刚开始我用的平台是WSL编译femu,根据readme的123步都没有问题,成功编译femu并且有了.qcow2的映像。但是在最后一步运行run-zns.sh的时候,他会报错not support aio,说明wsl可能不支持异步输入输出。我还是不死心,故而专门去验证了一下:
创建一个简单的测试程序来使用
libaio
库。创建一个名为aio_test.c
的文件,并将以下代码粘贴到其中:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include <stdio.h>
#include <stdlib.h>
#include <libaio.h>
int main() {
io_context_t ctx;
int ret = io_setup(1, &ctx);
if (ret != 0) {
printf("AIO is not supported on this system.\n");
return 1;
}
io_destroy(ctx);
printf("AIO is supported on this system.\n");
return 0;
}在 WSL 终端中,使用以下命令编译测试程序:
gcc -o aio_test aio_test.c -laio
运行编译后的测试程序:
./aio_test
好嘛,输出的果真是
AIO is not supported on this system.
在这个时候其实我对FEMU还有些疑问,我既然已经成功编译了FEMU,导入.qcow2的镜像是为了什么呢?
本着面向问题学习的思路,我查了一些资料,终于豁然:
虽然我已经成功编译了FEMU,但编译后的FEMU本身并不包含任何操作系统或用户空间环境。它仅提供了一个执行虚拟化的平台。因此,为了能够在FEMU中运行操作系统和应用程序,还需要在虚拟机中安装操作系统,并通过.qcow2镜像将操作系统和相关环境导入到虚拟机中。
在虚拟机中安装操作系统后,我可以登录到FEMU虚拟机中,并在其中运行应用程序或进行测试。
所以,我需要在虚拟机上使用FEMU,因为FEMU本身是作为一个虚拟化平台来运行操作系统的。在虚拟机中配置的操作系统和环境将作为FEMU的客户机,运行在FEMU的虚拟化环境中。
另辟蹊径
这个时候我就想,既然我已经有了.qcow2的映像,我直接把这个映像导入虚拟机中不就行了。这个虚拟机就是使用镜像文件作为硬盘而工作的,bingo!
这个时候问题又来了,我用的是VMvare,他是不支持导入.qcow2后缀的disk的。这难不倒我,转换成他支持的格式就可以了。一行代码搞定:
qemu-img convert -f qcow2 file.qcow2 -O vmdk file.vmdk
然后就得到了如下结果:
看起来是成功了哈
原始的方法
做到这我还是有些心虚,毕竟没有按照官方的步骤做。还有就是在FEMU的环境下通过.qcow2镜像进入FEMU的虚拟机和我直接新建一个虚拟机导入.qcow2进入其中,这其中还是有所区别的。毕竟我在FEMU的环境下,需要使用它提供的一些自定义选项和功能(比如我可以选择运行zns模式或者nossd模式)。但是直接导入.qcow2就不知道我用的哪种模式仿真了。
那么我就选择在VMvare中用ubuntu 20.04的disk作为实验环境,再次按照readme的配置走一遍。这时候新问题出现了,在编译过程中报错 Could not access KVM kernel module: No such file or directory. qemu-system-x86_64: failed to initialize kvm: No such file or directory
.原因是系统没有启用虚拟化,比如Intel的VT-x。需要在VWvare中启用一下虚拟化,我是参照这篇blog把问题解决了。