The kernel isn’t the solution. The kernel is the problem. ——Robert Graham CEO of Errata Security
Linux系統設計之初,採用了分級、分層設計方式,用戶調用底層設備,需要切換到內核態,由系統進行調用,這種方式適合硬盤速度遠低於CPU的場景。
然而隨着存儲速度越來越快,以及網絡存儲的興起,這種設計逐漸成爲了存儲的瓶頸。另外,本地硬盤協議,以及網絡協議,也都成爲了提高性能的絆腳石。
本文是突破硬件瓶頸系列文章的第二篇,上一篇主要Intel體系架構主講述本地和網絡存儲架構,以及網絡協議帶來的瓶頸。
硬盤的瓶頸
1 AHCI到NVMe
雖然這並不是重點,但是作爲基礎,我們必須要提一下。
傳統的HDD機械硬盤因爲結構原因,速度和延遲均難以令人滿意,且提升空間不大,而SATA接口的固態硬盤儘管提高了讀寫速度,也遠沒能釋放閃存的性能。
SATA/SAS接口多數由RAID卡或是PCH擴展而來,並非CPU直接控制,造成了很高的延遲,而且接口本身的速度上限是6/12Gbps,難以進一步提高。
這兩點均限制了硬盤本身性能的上限。早期存儲設備發展緩慢,CPU速度遠比硬盤快,因此有較多的不合理設計,在近些年存儲設備快速發展後顯得“格格不入”。
AHCI只設計了一個隊列,且隊列深度爲64,現有的高速硬盤已經幾乎將他佔滿,遙想當年,對於機械硬盤,32深度似乎已經“綽綽有餘”了。
NVMe擁有更低的延遲,支持更高級的MSI-X中斷,並且充分考慮到了未來存儲設備的發展,預留了64K個隊列,且隊列深度上限是64K,這種設計下,目前的硬盤連十萬分之一都無法發揮,爲Optane或更遠未來的新興存儲介質做好了伏筆。
在linux 3.13內核中,也加入了IO Multi-Queue機制,和NVMe的多隊列相輔相成。
SATA、SAS的速度受限於接口,速度只有6/12Gbps,而NVMe硬盤採用U.2\M.2\PCI-E Slot等介面,速度可以輕鬆達到32/64Gbps甚至更高。
因此,採用NVMe硬盤,是提高存儲性能的必要途徑。
FASS在支持傳統的SATA硬盤的同時,更建議用戶採用全NVMe硬盤,以獲得更高的性能。
然而,僅僅是本地提升並不能解決所有問題,就如SCSI有iSCSI用於網絡傳輸一樣,NVMe同樣也應該有它的網絡傳輸協議。
2 iSCSI到NVMe-oF
NVMe委員會並不會閒着,他們很快起草並通過審覈了NVMe 1.4規範,包含衆多新特性,其中對於NVMe over Fabrics(下簡稱爲NVMe-oF)的支持受到了廣泛關注。
大約90%的基於fabric的NVMe協議與本地NVMe協議相同。
對於用戶而言,他可以簡單理解爲NVMe的iSCSI,允許共享和掛載遠端的NVMe設備。
在標識上,NVMe-oF也參考了iSCSI的IQN,採用了NQN,命名規則與之相似。
毫無疑問,以高性能爲目標的FASS分佈式存儲,採用了NVMe-oF技術。
網絡傳輸協議瓶頸
目前分佈式存儲已經是主流,在容量需求已經得到相對滿足的今天,性能需求越來越迫切。
然而性能的提升異常艱難,我們被迫要推翻某些Linux早期的設計,這也代表存儲性能發展,終於超出了前輩們的設想,或許這也代表了我們存儲人的成就。
1 Linux原始設計
如何降低提交和進行網絡傳輸過程中所產生的延遲,是提升性能的關鍵,他們主要來自於內存拷貝、上下文切換、以及中斷。
發生上下文切換時,CPU需要將寄存器中的用戶態(user context)的指令位置保存起來,停止並轉而執行內核態(kernel context)的代碼,CPU寄存器需要更新爲內核態的新位置,最後跳轉到內核態執行內核調用。調用完成後,再恢復之前的用戶態。
我們以將一個文件,從用戶端通過網絡發送到存儲端爲例。這個過程,可以分解爲客戶端的發送和服務端的接收。
此處僅說明客戶端發送的過程,而服務端的接收同理。
1、用戶處於用戶態,進行上下文切換到內核態,這是第一次上下文切換,計爲S1。
2、將文件從硬盤讀取到內核態的內存緩衝區(kernel buffer),發生1次拷貝,記爲C1,這次拷貝因爲是慢介質(硬盤)向快介質(內存)拷貝,速度受限於慢介質。
3、將文件從內核態的內存區域拷貝到用戶態的內存區域,發生C2,這次拷貝是快介質(內存)向快介質(內存)拷貝,由CPU內IMC直接調用,速度較快。
4、拷貝完成,從內核態切換回用戶態,發生S2。
至此,用戶僅僅拿到了屬於自己的文件而已,接下來,他需要將數據送到網卡發送。
5、進行上下文切換,由用戶態轉換爲內核態,發生S3
6、調用內核函數,將文件從用戶態內存拷貝到內核態的Socket緩存,發生C3。
7、將文件拷貝到網卡緩存,這裏是異步發送,不一定成功,發生C4。
8、最後切換回用戶態,發生S4。
至此,發生四次上下文切換,四次內存拷貝,僅僅將數據發送出去而已。而服務器端的情況與客戶端類似,同樣有四次上下文切換和內存拷貝。
一次文件傳輸需要8次的上下文切換和內存拷貝,嚴重浪費了CPU和內存,造成了大量延遲。
經過測試,上下文切換時間是3us左右,我們可以通過一個典型場景計算上下文切換的造成的巨大性能損失。
如某節點目標提供100萬IOPS,爲了簡便計算,我們假設每次IOPS需要8次上下文切換,每次3us,那麼每秒造成的上下文切換爲800萬次,單核需要執行24秒。
換句話說,我們需要24顆CPU核心專門滿足上下文切換的開銷,才能跟得上IOPS。
類似的,內存拷貝也會造成延遲和速度降低,我們大可以從宏觀量化內存拷貝造成的速度降低,八倍的內存拷貝相比於一次,樂觀估計也要降低八倍的速度。
內存的延遲爲60-80ns左右,8次拷貝就會造成640ns的延遲,這些延遲相比於上下文切換並不大,但是內存拷貝卻造成了明顯的速度瓶頸。
內存的讀寫速度爲數十GB/S(圖中測試條件爲雙通道,內存頻率3733),如果進行任何的讀寫都需要在本地內存進行八次拷貝,那代表即便網絡和硬盤寫入瞬間完成,帶寬極限也只有內存的八分之一,如果再考慮從硬盤讀取和寫入降低的速度,以及網絡的傳輸,速度會進一步降低。
對於單塊硬盤,這個速度是可以接受的,但是對於多塊NVMe硬盤的存儲服務器來說,這個速度就遠低於理想值了,即便服務器端的libaio可以緩解這個問題,但是客戶端的延遲仍然無法解決。
2 RDMA技術的引入
繞過無意義的內存拷貝和上下文切換成了提高存儲性能的當務之急。RDMA就是爲了解決這個問題而生,其中InfiniBand網絡下的RDMA的性能最爲優秀。
RDMA直接建立兩端用戶態內存數據的傳輸,在服務端和客戶端各省去了一半的內存拷貝和上下文切換。
此外,RDMA將負載轉移到NIC上,不需要CPU參與和計算,避免了CPU開銷,還躲過了CPU中斷造成的延遲增加。
但是RDMA技術僅相當於完成了網絡傳輸的任務,他並沒有解決本地延遲的問題。
以客戶端爲例,本地硬盤的文件,要拷貝到RDMA IB網卡對應的內存區,仍然需要2次內存拷貝和2次上下文切換,之後才能“享受”RDMA技術直接傳輸到服務端內存區域的待遇。
爲了解決這個問題,我們還需要另一項技術的幫助。
3 SPDK
SPDK(Storage Performance Development Kit),由Intel開發並開源,包含一套驅動程序,以及一整套端到端的存儲參考架構。
SPDK的目標是能夠把硬件平臺的計算、網絡、存儲的最新性能進展充分發揮出來。自芯片而上進行設計優化,SPDK已展示出超高的性能指標。
它的高性能實際上來自於兩項核心技術:第一個是用戶態運行,第二個是輪詢(polling)模式驅動。前者是顯著降低延遲的原因,而後者則和FASS的高性能理念不謀而合。按照SPDK官方文檔描述,他能將一次任務提交的延遲從5800ns降低到600ns左右。
5800ns的延遲主要來自於2次上下文切換和2次內存拷貝,SPDK可以將硬盤驅動在用戶態運行,省去了所有的上下文切換,僅進行一次由硬盤到內存的拷貝,達到了600ns的驚人成績。
SPDK在網絡上完美對接RDMA,降低了延遲,並且提供了豐富的本地接口,完善了從硬盤設備驅動,到NVMe-oF Target等操作在用戶態下完成的方法。
上圖爲SPDK的架構圖,FASS採用了SPDK的少數組件,自己實現了其餘部分。
我們分層講述FASS所採用的SPDK部分。
硬件驅動層:
NVMe Driver:SPDK的基礎組件,這個高優化無鎖的NVMe硬盤驅動提供了高擴展性,高效性和高性能,採用UIO技術,在用戶空間運行。
後端塊設備層:
NVMe over Fabrics initiator:NVMe-oF本地客戶端啓動器,從程序員的角度來看,本地SPDK NVMe驅動和NVMe-oF啓動器共享一套API命令。這意味着本地到遠程的拷貝就像本地拷貝一樣,非常容易實現。
繞過了最後的上下文切換,FASS真正實現了將能節省的延遲,全部節省掉。
總結
由以上分析,得出存儲架構和協議瓶頸以及解決方式如下:
當然,即便是運用如此多的技術,想要獲得理想的性能,仍然還有許多工作要做,這部分內容將在系列文章的後續中爲您講述。
參考資料
NVMe_Over_Fabrics(NVMe委員會官方文檔).PDF
Storage Performance Development Kit(SPDK官方文檔)
Linux Block IO: Introducing Multi-queue SSD Access on Multi-core Systems
(TaoCloud團隊原創)