NVMe概述


目前企業SSD市場按照接口協議主要分為SATA SSD,PCIe SSD和NVMe SSD,其中SATA SSD沿用了傳統的HDD使用的SATA協議,在企業應用和服務器兼容性上具有優勢;而PCIe SSD則一般使用私有協議,目前已經處於比較小眾的產品;NVMe SSD則在PCIe接口上使用新的標准協議NVMe,由於NVMe由大廠Intel推出並交由nvmexpress組織推廣,現在被全球大部分存儲企業采納,如memblaze,huawei,samsung都推出了相關的產品

NVMe 是什么?

NVM Express(NVMe),或稱非易失性內存主機控制器接口規范(Non-Volatile Memory express),,是一個邏輯設備接口規范。他是與AHCI類似的、基於設備邏輯接口的總線傳輸協議規范(相當於通訊協議中的應用層),用於訪問通過PCI-Express(PCIe)總線附加的非易失性內存介質,雖然理論上不一定要求 PCIe 總線協議。此規范目的在於充分利用PCI-E通道的低延時以及並行性,還有當代處理器、平台與應用的並行性,在可控制的存儲成本下,極大的提升固態硬盤的讀寫性能,降低由於AHCI接口帶來的高延時,徹底解放SATA時代固態硬盤的極致性能

NVMe具體優勢包括:

①NVMe是為SSD所生的。NVMe出現之前,SSD絕大多數走的是AHCI和SATA的協議,后者其實是為傳統HDD服務的。與HDD相比,SSD具有更低的延時和更高的性能,AHCI已經不能跟上SSD性能發展的步伐了,已經成為制約SSD性能的瓶頸. SATA現在最高帶寬就是600MB/s,nvme使得性能有數倍的提升;

②可降低延遲超過50%;

③NVMe可以把最大隊列深度從32提升到64000,SSD的IOPS能力也會得到大幅提升;

④自動功耗狀態切換和動態能耗管理功能大大降低功耗;

⑤NVMe標准的出現解決了不同PCIe SSD之間的驅動適用性問題。

NVMe Command

NVMe Host(Server)和NVMe Controller(SSD)都是通過NVMe Command進行信息交互。NVMe Spec中定義了NVMe Command的格式,可以看到,NVMe Command占用64字節。其中Command的前4個字節規定如下。Command Identifier作為識別這個Command的標志,Opcode通常包含Command類型(如讀寫,identify等)

 

NVMe有兩種命令,一種叫Admin Command,用以Host管理和控制SSD;另外一種就是I/O Command,用以Host和SSD之間數據的傳輸

Opcode在這兩類的基礎上進行划分。下圖是部分管理Command的Opcode定義:

 

下圖是 IO command的Opcode定義:

 剩余的60個字節則根據Command類型定義。

NVMe Queue

NVMe中有兩個隊列和一個寄存器:

①Submission Queue (SQ)

②Completion Queue(CQ)

③Doorbell Register (DB)

SQ和CQ位於Host的內存中,DB則位於SSD的控制器內部。

 

  • 有兩種SQ和CQ,一種是Admin,另外一種是I/O,前者放Admin命令,用以Host管理控制SSD,后者放置I/O命令,用以Host與SSD之間傳輸數據。
  • 系統中只有一對Admin SQ/CQ,它們是一一對應的關系;I/O SQ/CQ卻可以很多,多達65535(64K減去一個SQ/CQ)
  • Host端每個Core可以有一個或者多個SQ,但只有一個CQ。給每個Core分配一對SQ/CQ好理解,為什么一個Core中還要多個SQ呢?一是性能需求,一個Core中有多線程,可以做到一個線程獨享一個SQ;二是QoS需求,什么是QoS?Quality of Service,服務質量。實際系統中用多少個SQ,取決於系統配置和性能需求,可靈活設置I/O SQ個數
  • 作為隊列,每個SQ和CQ都有一定的深度:對Admin SQ/CQ來說,其深度可以是2-4096(4K);對I/O SQ/CQ,深度可以是2-65536(64K)。隊列深度也是可以配置的。AHCI只有一個命令隊列,且隊列深度是固定的32
  • Linux的NVMe驅動采用一個Core獨占一個Queue(由Completion Queue和Submission Queue組成)的方式。這種設計避免了一個隊列被多個Core競爭訪問,大家都各自使用自己的Queue,互不干擾。
  • 隊列用來存放NVMe Command,NVMe Command是Host與SSD Controller交流的基本單元,應用的I/O請求也要轉化成NVMe Command。
  • 每條命令大小是64字節,每條命令完成狀態是16字節
  • 每個SQ或者CQ有兩個DB: Head DB 和Tail DB

SSD作為一個PCIe Endpoint通過PCIe連着Root Complex (RC), 然后RC連接着CPU和內存。 RC就是CPU的代言人 SQ位於Host內存中,Host要發送命令時,先把准備好的命令放在SQ中,然后通知SSD來取;CQ也是位於Host內存中,一個命令執行完成,成功或失敗,SSD總會往CQ中寫入命令完成狀態。 Host發送命令時,不是直接往SSD中發送命令的,而是把命令准備好放在自己的內存中,那怎么通知SSD來獲取命令執行呢?Host就是通過寫SSD端的DB寄存器來告知SSD的:

 流程:

1.BIO封裝成的Command會順序存入Submission Queue中

2.對於Submission Queue來說,使用Tail表示最后操作的Command Index。每存入一個Command,Host就會更新Queue對應的Doorbell寄存器中的Tail值

3.NVMe沒有規定Command存入隊列的執行順序,Controller可以一次取出多個Command進行批量處理,所以一個隊列中的Command執行順序是不固定的(可能導致先提交的請求后處理)

4.SSD執行命令

5.SSD Controller根據Doorbell的值,獲取NVMe Command和對應數據(步驟3),待處理完成后(步驟4)將結果存入Completion Queue中

6.Controller通過中斷的方式通知Host

7.將Completion Command從Completion Queue中取出,然后把隊列的head值加1,並調用上層的Callback函數(完成BIO處理)

8.處理完Command后,往Completion Queue的Doorbell寫入Head值,通知NVMe Controller操作完成。中斷處理結束

 

 

DB的另外一個作用,就是通知作用:Host更新SQ Tail DB的同時,也是在告知SSD有新的命令需要處理;Host更新CQ Head DB的同時,也是在告知SSD,你返回的命令完成狀態信息我已經處理,同時表示謝意。這里有一個對Host不公平的地方,Host對DB只能寫,還僅限於寫SQ Tail DB和CQ Head DB,不能讀取DB

 

疑問:

1.SSD在取指的時候,是偷偷進行的,Host對此毫不知情。Host發了取指通知后,它並不清楚SSD什么時候去取命令,取了多少命令。怎么破?

答:

 

這是SSD往CQ中寫入的命令完成狀態信息(16字節)。是的,SSD往CQ中寫入命令狀態信息的同時,還把SQ Head DB的信息告知了Host!!這樣,Host對SQ中Head和Tail的信息都有了,輕松玩轉SQ

 

2.Controller寫入Command后,只有中斷觸發通知Host,沒有類似於Head/Tail機制告訴Host可以取哪些Completion Command?

答:一開始CQ中每條命令完成條目中的”P” bit初始化為0,SSD在往CQ中寫入命令完成條目時,會把”P”寫成1。記住一點,CQ是在Host端的內存中,Host可以檢查CQ中的所有內容,當然包括”P”了。Host記住上次的Tail,然后往下一個一個檢查”P”,就能得出新的Tail了。就是這樣。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM