NVMeSSD具有高性能、低時延等優(yōu)點,是目前存儲行業(yè)的研究熱點之一,但在光鮮的性能下也同樣存在一些沒有廣為人知的問題,而這些問題其實對于一個生產(chǎn)系統(tǒng)而言至關(guān)重要,例如:
QoS無法做到100%保證;
讀寫混合情況下,與單獨讀相比,性能下降嚴重,且讀長尾延遲比較嚴重;
所以如何利用好NVMe盤的性能,并更好的為業(yè)務(wù)服務(wù),我們需要從硬件,Linux內(nèi)核等多個角度去剖析和解決。
從內(nèi)核中NVMe IO框架來看其中存在的問題
當前Linux內(nèi)核中對NVMeSSD的訪問是通過MQ框架來實現(xiàn)的,接入NVMe驅(qū)動后直接略過IO調(diào)度器,具體實現(xiàn)上來說是從blocklayer中的通用塊層回調(diào)make_request從而打通上下層IO通路。示意圖如下,這里面有幾個關(guān)鍵的點:
IO發(fā)送過程
MQ的框架提升性能最主要的將鎖的粒度按照硬件隊列進行拆分,并與底層SSD的隊列進行綁定,理想的情況每一個CPU都有對應(yīng)的硬件發(fā)送SQ與響應(yīng)CQ,這樣可以并發(fā)同時彼此之前無影響。按照NVMeSPEC協(xié)議中的標準,硬件最多支持64K個隊列,所以理想情況下硬件隊列個數(shù)將不會是我們需要擔心的地方。但是實際情況又如何呢?由于硬件隊列的增加會給NVMeSSD帶來功耗的增加,所以不同的廠商在設(shè)計硬件隊列個數(shù)時的考量是不同的,比如intelP3600支持32個隊列,intel最新的P4500支持16384個,但是SUMSUNGPM963卻只支持到8個。那么當CPU的個數(shù)超過硬件的隊列個數(shù),就會出現(xiàn)多個CPU共用一個硬件隊列的情況,對性能就會產(chǎn)生影響。
下面使用SUMSUNGPM963做一個簡單的測試:
也就是整個IOPS可以達到50w
如果使用同一個硬件隊列
整個IOPS只有44w,性能下降12%,主要原因是多個CPU共用硬件隊列進行發(fā)送的時候會有自旋鎖爭搶的影響。所以對于共用硬件隊列的情況下,如何綁定CPU是需要根據(jù)業(yè)務(wù)的特點來確定的。
IO響應(yīng)過程
IO響應(yīng)過程中最主要問題是中斷的balance,由于默認linux中并沒有對NVMe的中斷進行有效的綁定,所以不同的綁定策略會帶來截然不同的性能數(shù)據(jù)。不過在我們的實際測試中,雖然我們沒有做中斷的綁定,但是貌似不管是性能還是穩(wěn)定性的下降并沒有那么嚴重,什么原因呢?根據(jù)我們的分析,這里面最主要的原因是(后面也會提到),我們并沒有大壓力的使用NVMe盤,所以實際的應(yīng)用場景壓力以及隊列深度并不大。
從應(yīng)用本身的IO Pattern來看使用NVMe問題
我們在評測一個NVMeSSD的性能的時候,往往都是通過benchmark工具,例如見1,見2。
然而這些測試的結(jié)果與業(yè)務(wù)實際使用NVMeSSD看到的性能相比差距很大。原因是因為這些性能測試存在兩個比較大的誤區(qū),因而并不能反映生產(chǎn)系統(tǒng)的真實情況。
1. 片面夸大了NVMe盤的性能
從上面兩篇文章中的測試中我們可以看到,大多數(shù)壓測中使用的隊列深度為128,并且是用libaio這樣的異步IO模式來下發(fā)IO。但是在實際應(yīng)用場景中很少有這么大的隊列深度。在這種場景下,根據(jù)“色子效應(yīng)”,并不會將NVMe盤的并發(fā)性能充分發(fā)揮出來。
2. 低估了NVMe的長尾延遲
然而在另外一些場景下,隊列深度又會非常高(比如到1024甚至更高),在這種情況下NVMeSSD帶來的QoS長尾延遲影響比上面的benchmark的測試又嚴重得多。
所以綜合起來看,這種評測選擇了一個看上去沒啥大用的場景做了測試,所以得出的結(jié)果也對我們實際的應(yīng)用基本沒有參考價值。那么問題出在什么地方么?
問題分析
首先讓我們再次強調(diào)一下一般評測文章中benchmark進行的測試場景的特點:
大多是fio工具,開啟libaio引擎增加IO壓力
隊列深度到128或者256
在這種場景下確實基本都可以將NVMe盤的壓力打滿。
在展開分析問題的原因之前,我們先看看Linux內(nèi)核的IO棧。
在實際應(yīng)用中,VFS提供給應(yīng)用的接口,從IO的特點來分類,大致上可以分為兩類:directIO與bufferIO。使用directIO的業(yè)務(wù)大多在應(yīng)用本身就已經(jīng)做了一層cache,不依賴OS提供的pagecache。其他的情況大多使用的都是bufferIO。linuxkernel中的blocklayer通過REQ_SYNC與~REQ_SYNC這兩種不同的標志來區(qū)分這兩類IO。大家常用的directIO這個類型,內(nèi)核要保證這次IO操作的數(shù)據(jù)落盤,并且當響應(yīng)返回以后,應(yīng)用程序才能夠認為這次IO操作是完成的。所以是使用了這里的REQ_SYNC標志,而對應(yīng)的bufferIO,則大量使用了~REQ_SYNC的標志。讓我們一個一個看過去。
direct IO
由于在實際使用方式中AIO還不夠成熟,所以大多使用directIO。但是directIO是一種SYNC模式,并且完全達不到測試用例中128路并發(fā)AIO的效果。這主要兩個方面原因:
direct io在下發(fā)過程中可能會使用文件粒度的鎖inode->i_mutex進行互斥。
前面說的IO SYNC模式
也就是說,我們很難通過directIO來達到壓滿NVMe盤的目的。如果一定要打滿NVMe盤,那么一方面要提高進程并發(fā),另外一方面還要提高多進程多文件的并發(fā)。而這是生產(chǎn)系統(tǒng)中很難滿足的。
buffer IO
我們再來看看bufferIO的特點。下面我使用了比較簡單的fio通過bufferIO的模式下發(fā),而且通過rate限速,我們發(fā)現(xiàn)平均下來每秒的數(shù)據(jù)量不到100MB,整個IO的特點如下:
抓取了下submit_bio在每秒的調(diào)用次數(shù)并分析可以得出,bufferIO在下刷的時候并不會考慮QD的多少,而是類似aio那樣,kworker將需要下發(fā)的臟頁都會bio形式下發(fā),而且不需要等待某些bio返回。注意這里面有一個細節(jié)從qusize觀察到IO最大值986,并沒有達到百K,或者幾十K,這個原因是由本身MQ的框架中tag機制nr_request決定,目前單Q設(shè)置默認值一般為1024??傊産ufferIO這樣特點的結(jié)果就是突發(fā)量的高iops的寫入,bufferIO對于應(yīng)用程序來說是不可見的,因為這是linuxkernel的本身的刷臟頁行為。但是它帶給應(yīng)用的影響確實可見的,筆者曾經(jīng)總結(jié)過異步IO的延時對長尾的影響,如下圖所示,分別是bufferIO與directIO在相同帶寬下延時表現(xiàn),可以看出這延遲長尾比我們簡單的通過fiobenchmark測試嚴重的多,特別是盤開始做GC的時候,抖動更加嚴重;而且隨著盤的容量用著越來越多,GC的影響越來越大,長尾的影響也是越來越嚴重。
在HDD的時代上面的問題同樣會存在,但是為什么沒有那么嚴重,原因主要是HDD大多使用CFQ調(diào)度器,其中一個特性是同步、異步IO隊列分離。并且在調(diào)度過程中同步優(yōu)先級比較高,在調(diào)度搶占、時間片等都是同步優(yōu)先。
解決問題
前面描述了使用NVMe硬盤的嚴重性,下面介紹一下如何解決這些問題。(1)MQ綁定的問題,需要根據(jù)當前業(yè)務(wù)的特點,如果硬件的隊列小于當前CPU的個數(shù),盡量讓核心業(yè)務(wù)上跑的進程分散在綁定不同硬件隊列的CPU上,防止IO壓力大的時候鎖資源的競爭。
(2)中斷綁定CPU,建議下發(fā)的SQ的CPU與響應(yīng)的CQ的CPU保持一致,這樣各自CPU來處理自己的事情,互相業(yè)務(wù)與中斷不干擾。
(3)解決directIO狀態(tài)下長尾延遲,因為長尾延遲是本身NVMeSSDController帶來,所以解決這個問題還是要從控制器入手,使用的方法有WRR(WeightRoundRobin),這個功能在當前主流廠商的最新的NVMeSSD中已經(jīng)支持。
(4)解決bufferIO狀態(tài)下長尾延遲,可以通過控制NVMeSSD處理的QD來解決,使用的NVME多隊列IO調(diào)度器,充分利用了MQ框架,根據(jù)同步寫、讀延遲動態(tài)調(diào)整異步IO的隊列,很好的解決bufferio帶來的長尾延遲。
-
cpu
+關(guān)注
關(guān)注
68文章
10776瀏覽量
210458 -
Linux
+關(guān)注
關(guān)注
87文章
11177瀏覽量
208487 -
nvme
+關(guān)注
關(guān)注
0文章
211瀏覽量
22538
原文標題:你所不知道到的NVMe
文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論