一、AHCI和NVMe
AHCI和NVMe都是接口协议,AHCI属于以前SATA使用接口协议,因为存储介质的性能突破,整个盘的性能瓶颈由介质转移到上面的接口和协议,所以英特尔牵头制定了新的一套接口协议叫NVMe。而且NVMe和PCIe是“原配”,NVMe是跑在PCIe接口上的协议标准。
NVMe相比ACHI,延时更低、性能更高、功耗更低。
1、低延时:
闪存比传统机械硬盘速度快;
控制器角度,PCIe主控和CPU直连的方式相较于传统SATA通过南桥中转再连接CPU的方式;
软件接口角度,NVMe缩短了CPU到SSD的指令路径,比如NVMe减少了对寄存器的访问次数,使用了MSI-X中断管理,并行与多线程优化——NVMe减少了每个CPU核之间的锁同步操作等。
| 产品 | 写延时 | 读延时 |
|---|---|---|
| 消费级 入门级产品 | 20~50微秒 | 60~100微秒 |
| 消费级 中高端产品 | 10~20微秒 | 50~60微秒 |
| 企业级 强调性能产品 | 10微秒以下 | 10~30微秒 |
| 企业级 强调成本效益产品 | 10~20微秒 | 30~50微秒 |
2、高性能:IOPS = 队列深度/输入输出延时
公式理解:队列深度相同的情况下,输入输出延时越低,IOPS性能越好;但是队列深度越高,IO延时也会提高,它们不是正比关系。
| 接口协议 | 最大队列深度 | 队列数量 |
|---|---|---|
| AHCI | 32 | 1 |
| NVMe | 64K | 64K |
拥有更多的队列数量和更大的队列深度,所以NVMe的性能甩AHCI几条街是很自然的事情。
关于队列深度:
队列深度是指存储设备在一个队列(一般指单个程序)中可以同时处理的未完成的I/O请求的数量,表示了设备能够缓冲的I/O请求的程度。
a、如果以顺序读写为主的场景,视频编辑软件读取或写入大型视频文件,可以使用较低的队列深度,因为顺序读写的I/O请求相对比较规律,设备可以高效地处理一个接一个的请求。
b、如果是随机读写为主的场景,比如数据库应用中,可以适当增加队列深度来提高性能,因为数据库的查询操作是随机分布的,增加队列深度可以让存储设备更好的应对不规则的I/O请求流。
关于队列数量:
队列数量是指存储设备能够同时支持的独立I/O请求队列个数,每个队列可以有自己的队列深度,并且可以独立地接收和处理I/O请求。
多个队列可以让不同的应用程序或者线程将I/O请求发送到不同的队列中,从而避免了单个队列的竞争和拥堵;例如多用户并发的数据库服务。
合理利用多个队列可以根据不同的I/O优先级或者应用需求进行调度,例如一个监控系统的数据请求和后台数据备份的请求共享一个存储设备,可以为实时的监控系统分配更高的I/O处理优先级的队列,为后台数据备份分配较低的I/O处理优先级的队列。
a、虚拟化环境中,每个虚拟机可以分配一个独立的I/O请求队列,这样可以提高虚拟机之间的I/O隔离性和性能。
b、多核心处理器系统中,多个队列可以和多个处理器核心配合使用,每个核心可以向不同的队列发送I/O请求,从而充分利用多核处理器的并行处理能力,提高系统的整体I/O性能。
3、低功耗:自动功耗状态切换、动态能耗管理功能
二、NVMe综述
NVMe是一种主机和SSD之间通信的协议,在协议栈中隶属高层。
NVMe作为命令层和应用层协议,理论上可以适配任何接口上。而NVMe的手下大将就是PCIe,NVMe制定的任何命令都交由PCIe去完成。NVMe协议的原配是PCIe,所以它们合作形成的战斗力是最强的。
NVMe出现之前用的是AHCI+SATA的组合,但是SATA接口的速度上限太慢了(SATA3.0最高带宽是600MB/s),限制了整体的速度表现;所以要发展,就得用新的接口PCIe。
1、NVMe命令
a、Admin命令,用于帮主机管理和控制SSD;
创建/销毁队列(包括submisson queue-主机向设备发送的通道和completion queue-设备向主机返回数据的通道)
b、I/O命令,用于在主机和SSD之间传输数据。
写读、flush、数据校验基本属于此类命令
主机又是怎么把这些命令发送给SSD执行的?
通过SQ(Submission Queue)、CQ(Completion Queue)、DB(DoorBell register)组成的沟通机制进行命令发送和执行。
SQ位于主机内存中,DB位于SSD的控制器内部。
主机和SSD分别往SQ、CQ写指令命令,中间通过DB机制进行通讯告知对方取指进行命令的处理。
三、SQ、CQ、DB
1、SQ、CQ、DB的详细工作过程
①主机往SQ写命令;
②主机写SQ的DB,通知SSD取指;
③SSD收到通知后,到SQ中取指;
④SSD执行指令;
⑤指令执行完成,SSD往CQ中写指令执行结果;
⑥SSD发中断通知主机指令完成;
⑦收到中断,主机处理CQ,查看指令完成状态;
⑧主机处理完CQ的指令,通过DB回复SSD。
2、SQ\CQ详细介绍
SQ与CQ的关系可以是一对一,也可以是多对一,有SQ就必然会有CQ。
Admin命令和I/O命令的SQ互不相通,不能把I/O命令放到Admin SQ里。I/O SQ也是由Admin命令创建的。
系统中只有1对Admin SQ/CQ,但是I/O SQ/CQ可以多达65535对。
I/O SQ:单个CPU内核有多线程,可以让每个程序有单独的SQ可以使用,面对多任务同时处理的场景,对紧急重要的任务赋予高优先级的SQ,不紧急的任务赋予低优先级的SQ,保证用户体验满足场景需求。但是主机端每个CPU核可以有一个或者多个SQ,但只有一个CQ。
| 接口类型 | 队列深度 | 队列数量 |
|---|---|---|
| AHCI | 固定的32 | 只有一个 |
| NVMe(Admin SQ/CQ) | 2~4096(4K) | 可配置(一般使用2~128) |
| NVMe(IO SQ/CQ) | 2~65536(64K) | 可配置(一般使用2~128) |
SQ命令的条目大小为64B,CQ的条目大小为16B。
3、DB作用详细介绍
来重温一下主机和SSD的通讯过程吧。
a、首先主机给SSD控制器发送SQ命令,放在主机的内存中,往SQ的Tail端寄存器写入命令条目数值,控制器收到通知后开始处理命令,并在SQ的Head端更新相同的命令条目数值;
b、然后等SSD控制器处理完命令之后,给CQ的Tail端寄存器写入完成命令条目数值,以及更新SQ的Head端指针、本次CQ的每条完成条目的P标识位翻转为1,此时CQ同样存在主机的内存中;主机收到通知后,就会开始更新本地的CQ的Head端寄存器条目数值,同时因为SSD控制器在CQ队列中记录了SQ的Head端信息和CQ的Tail端信息,主机就能够获取完整的SQ、CQ队列信息。