本期和大家聊的是剛剛在2月份拿到FAST 2018最佳論文獎的一篇文章。它討論了實現(xiàn)一種支持保序IO操作的設(shè)備會帶來哪些好處,目前的Linux內(nèi)核里處理FLUSH、FUA的方式可以參見https://lwn.net/Articles/400541/,本文大部分內(nèi)容來自于 blog.acolyer.org ,圖表來自于論文原文。
作者
朱延海,Linux系統(tǒng)工程師,來自阿里云系統(tǒng)組。
阿里云系統(tǒng)團(tuán)隊,是由原淘寶內(nèi)核組擴建而成,2013年淘寶內(nèi)核組響應(yīng)阿里巴巴集團(tuán)的號召,整建制轉(zhuǎn)入阿里云,開始為云計算底層系統(tǒng)構(gòu)建完善的系統(tǒng)支持。 阿里云系統(tǒng)團(tuán)隊是由一群具有高度使命感和自我追求的內(nèi)核開發(fā)人員組成,團(tuán)隊中的大多數(shù)人,都是活躍的社區(qū)內(nèi)核開發(fā)人員。目前的工作領(lǐng)域主要涉及(但不限于) Linux內(nèi)核的內(nèi)存管理、文件系統(tǒng)、網(wǎng)絡(luò)和內(nèi)核維護(hù)構(gòu)建,以及和內(nèi)核相關(guān)聯(lián)的用戶態(tài)庫和工具。如果你對我們的工作很感興趣,歡迎加入我們,請將簡歷發(fā)送至 tao.ma at linux.alibaba.com或者 boyu.mt at alibaba-inc.com。
概述
現(xiàn)代高速Flash設(shè)備的性能訣竅在于充分提高請求處理的并行度(scale-out),而并非無限地降低其延遲(scale-up)—例如,使用多通道控制器(multi-channel controllers)、更大的緩存以及更深的命令隊列,這些都是用來提高并行度的有效辦法。同時,寫一個flash cell所需要的時間一直沒有什么變化,近來甚至有變差的趨勢。在大部分情況下,用戶對此并不在意,也感覺不到—除非你的應(yīng)用希望它發(fā)出的一系列請求是保序的(guarantee ordering),這也就是本文所要重點討論的問題:
“在目前的設(shè)備上,為請求保序是通過一種代價很高的辦法來實現(xiàn)的:把排在請求X前邊的所有請求都發(fā)出去,然后等待它們?nèi)客瓿伞⒊志没⒎祷兀缓蟛虐l(fā)射請求X,這時我們就可以說X前邊的請求和X之間建立了明確的先后順序關(guān)系。我們把這種機制叫做Transfer-and-Flush。”
顯而易見,當(dāng)你使用Transfer-and-Flush機制時,設(shè)備的并行度會大大降低,因此帶來最終性能的降低,設(shè)備越是依賴高并行度來攫取性能,這種做法就越是令人無法接受。例如,在一個智能手機的單通道SSD上,保序?qū)懻埱蟮腎OPS是無序?qū)懻埱蟮?0%,對于32通道SSD,這一比例降低至1%。在目前的Linux內(nèi)核中,文件系統(tǒng)若真的想執(zhí)行一系列保序請求,使用的機制也是Transfer-and-Flush。然而,通過Transfer-and-Flush來保序顯然殺傷力過大了:首先,也許文件系統(tǒng)原本只想讓兩個單個請求之間是有序的,但卻不得不使得由flush分隔的兩組操作集合之間變得有序,而這每一個集合里都可能包含了大量不需要保序的請求;其次,這么做不僅實現(xiàn)了保序,同時還提供了同步的持久化保證,這并不是保序想要的—當(dāng)一個上層應(yīng)用發(fā)出兩個保序的請求A1和A2時,它對于A1和A2具體何時被持久化并沒有什么期待,可以是異步的,它唯一的要求是一但持久化動作開始,A1的持久化必須發(fā)生在A2之前。
本文的作者提出了一種被稱為Barrier-enabled IO stack的方案,這一方案不依賴Transfer-and-Flush,文件系統(tǒng)也就無需停下來等待前邊的請求成功返回。這一方案得到的性能提升相當(dāng)驚人:
“SQlite服務(wù)器場景性能提升270%,手機場景性能提升75%;實現(xiàn)了Barrier-enabled IO stack的BarrierFS在MySQL場景性能指標(biāo)是EXT4的43倍,在SQLite場景性能指標(biāo)是EXT4的73倍”
下邊我們來介紹下作者的方案
我們知道,現(xiàn)代IO stack天生就是亂序的。試想文件系統(tǒng)發(fā)射出來的一簇請求在下邊的路徑里會經(jīng)歷些什么:
IO調(diào)度器會對請求重排列,還有可能合并請求
設(shè)備上的控制器收到請求后放到自己內(nèi)部的命令隊列里,這時它也可以隨意改變請求順序。設(shè)備內(nèi)部的錯誤、超時、重傳等等也都有可能對請求實際執(zhí)行的順序產(chǎn)生影響
現(xiàn)代設(shè)備內(nèi)部通常也像文件系統(tǒng)一樣,有數(shù)據(jù)塊和元數(shù)據(jù)塊,有自己的journal。請求抵達(dá)存儲設(shè)備內(nèi)部之后,最終對用戶可見、對用戶有意義的持久化“順序”不光是由數(shù)據(jù)塊的持久化順序決定,同時也受那些元數(shù)據(jù)的持久化順序影響,而這兩者并不一定是相同的。
因此,多數(shù)操作系統(tǒng)的IO stack都包含了一個從硬盤時代流傳下來的設(shè)計假設(shè):上位機不能控制持久化順序
“現(xiàn)代IO stack設(shè)計中的一個基本假設(shè)就是上位機不能真正地控制到數(shù)據(jù)的持久化順序”
因此,一但上位機確實需要控制持久化順序時,就只能使用昂貴的Transfer-and-Flush機制了:如果請求a需要排在請求b之前完成,那么把請求a發(fā)到存儲設(shè)備之后,上位機就首先需要等設(shè)備報告a徹底完成,然后發(fā)一個flush命令并等待flush完成(以防設(shè)備上的cache造成亂序),然后才發(fā)請求b。
以EXT4的默認(rèn)工作模式Ordered模式為例,當(dāng)它提交一個journal transaction時,它需要執(zhí)行兩次寫:第一次寫journal descriptor和log blocks(JD),第二次寫commit block(JC)。JD必須先于JC完成持久化。在transaction的層面上看,各個transaction之間也必須是有序的,排在前邊的transaction一定要比排在后邊的transaction先完成持久化,否則文件系統(tǒng)執(zhí)行故障恢復(fù)時就有崩潰的可能。為了把保序語義引入IO stack,作者顯然需要自底向上把這個語義貫穿到整個IO stack中去。下邊具體介紹一下作者的工作。
帶barrier的保序塊設(shè)備
“給設(shè)備加入barrier指令支持后,上位機就不再需要通過顯式地刷cache來保證請求順序了。當(dāng)設(shè)備收到barrier指令時,它會確保排在barrier前的所有指令—可能是寫也可能是讀—都執(zhí)行完畢、完成數(shù)據(jù)傳輸后,才開始執(zhí)行排在barrier后邊的指令。”
論文的作者把他提出的這種barrier實現(xiàn)成了SCSI命令的一個附加屬性,而不是一條獨立的SCSI命令。設(shè)備具體實現(xiàn)barrier支持的方法有很多,對于本身已經(jīng)帶有一個大電容,寫操作返回時就可以保證持久化的那些設(shè)備,可以認(rèn)為它們天生對于收到的寫請求就是保序的,因此只要在設(shè)備上邊的各個層次能夠保證提交順序,整條鏈路就直接可以做出保序的承諾,因此對于這些設(shè)備沒什么需要修改的。對于其他設(shè)備,在設(shè)備內(nèi)部實現(xiàn)保序其實和之前在整個IO stack上實現(xiàn)保序的邏輯基本是一樣的,要么確保writeback cache按順序回寫、要么在回寫時引入事務(wù)機制、要么實現(xiàn)按順序recovery。論文對于具體如何實現(xiàn)這種帶barrier支持的存儲設(shè)備一筆帶過,并表示這不是重點,作者認(rèn)為論文的重點在于說明一但擁有此種設(shè)備會帶來多大好處,至于如何實現(xiàn)這種設(shè)備那是純粹的engineering efforts,不再過多考慮。
總之,一但擁有這種設(shè)備,就可以實現(xiàn)請求的保序發(fā)送:
“保序發(fā)送是本文的重要創(chuàng)新之處,上層的文件系統(tǒng)對于需要保序的請求可以帶上barrier標(biāo)志,只要注意在發(fā)送時不把它們重排序就行,不再需要等待flush。由下邊的存儲設(shè)備來保證帶barrier標(biāo)志請求的持久化順序與它們的發(fā)送順序相同。我們把這種機制叫做wait-on-dispatch”
顯然,wait-on-dispatch比wait-on-transfer的成本要小很多,如下圖所示:
scsi layer
我們沿著從下往上的方向繼續(xù)向上層走,當(dāng)設(shè)備實現(xiàn)了barrier支持之后,緊接著需要修改的是scsi層。在這里作者利用了scsi層已有的command priority level機制,按照scsi規(guī)范,命令可以分成三種:head of the queue(收到命令時要把它插入到隊列頭上)、ordered(收到命令時要把它插入到隊列尾部)、simple(命令可以插入到隊列中任意位置,但不能放在head of the queue命令或ordered命令的前邊)。因此,只需要把barrier命令打上ordered屬性發(fā)送,把其他寫請求打上simple屬性發(fā)送,就天然地可以在scsi層上保證barrier語義了。
“在目前的塊設(shè)備層實現(xiàn)中,ordered命令很少使用,這是因為當(dāng)整個IO stack尚且不能做到保序發(fā)送時,單獨在scsi層控制命令的發(fā)送順序沒有什么意義。然而,當(dāng)我們在全路徑上引入barrier語義后,scsi層的ordered命令就開始扮演重要的角色了”
epoch-based IO scheduler
在解決了scsi層的問題后,作者沿著IO路徑繼續(xù)往上走,對IO調(diào)度器加以修改,引入了所謂的epoch-based scheduling:
需要保序的寫操作,帶有REQ_ORDERED標(biāo)志
一對REQ_BARRIER之間的所有RED_ORDERED寫構(gòu)成一個epoch
兩個epoch之間整體上的提交是保序的,即第一個epoch的所有寫請求提交結(jié)束后,才提交第二個epoch里的寫請求
一個epoch內(nèi)部的REQ_ORDERED寫之間可以自由重排序
不帶REQ_ORDERED的寫請求可以任意自由跨epoch重排序
這樣作者就進(jìn)一步解決了barrier殺傷力過大的問題—只有明確表示需要保序的寫請求,其提交順序才受barrier約束。
Barrier-enabled filesystem
IO調(diào)度器理順之后,作者繼續(xù)向上走,開始修改文件系統(tǒng),提出了barrier-enabled filesystem(BFS)的概念,BFS引入了兩個新的原語:fbarrier()和fdatabarrier(),它們分別是fsync()和fdatasyn()在保序這個意義上的對應(yīng)產(chǎn)物,即是說,當(dāng)你調(diào)用它們時,它們會確保排在調(diào)用點之前的所有寫操作(或者所有數(shù)據(jù)寫操作)一定比排在它們之后的所有寫操作先完成持久化,然而對于具體何時會完成持久化不做保證。另外,作者也修改了ext4的journal以使它利用上新的barrier機制:
“利用底層設(shè)備提供的保序語義,我們就可以把一次journal提交過程中的控制平面活動(寫請求的提交)和數(shù)據(jù)平面活動(數(shù)據(jù)及journal的持久化)分開處理,我們建立兩個線程,一個負(fù)責(zé)保序提交請求,另一個負(fù)責(zé)等待它們完成。我們把這種機制叫做Dual Mode Journaling”
效果評估
原文中的第6小節(jié)也包括了塊設(shè)備層和文件系統(tǒng)層的性能測試,不過我們這里直接關(guān)注最終的應(yīng)用性能提升。
對于服務(wù)器負(fù)載,作者跑了varmail(varmail發(fā)的fsync非常多),還有MySQL上的OLTP-insert測試。作者把這里的對比測試細(xì)分成了兩種情況,第一種是所謂的durability guarantee測試,在這個測試?yán)飸?yīng)用代碼完全不改,用BarrierFS和標(biāo)準(zhǔn)的EXT4做對比,這是為了說明利用了barrier語義后fsync()本身的性能提升;第二種是所謂的ordering guarantee測試,在這個測試?yán)镒髡吲芰薆arrierFS、OptFS和EXT4三種文件系統(tǒng)(前兩種支持barrier語義),并在前兩種文件系統(tǒng)上把應(yīng)用的fsync()換成fdatabarrier()和osync()(osync是OptFS里的barrier操作),對于EXT4則加上nobarrier參數(shù)。這一測試是為了說明wait-on-dispatch比wait-on-transfer的優(yōu)越之處,注意這里作者實際上做了一個不切實際的假定,須知有時應(yīng)用調(diào)用fsync()時確實是想保證其持久性的,并非每一處fsync()都可以換成fdatabarrier(),具體要如何修改應(yīng)用必須結(jié)合應(yīng)用的具體上下文。第二個測試的結(jié)果只能說明結(jié)合應(yīng)用具體場景,去掉overkill的持久化約束后性能提升的上限會是多少。
在durability guarantee測試中,BarrierFS為varmail帶來了10%-60%的性能提升,為MySQL帶來了12%的性能提升;在ordering guarantee測試中,BarrierFS帶來了36倍性能提升,為MySQL帶來了43倍性能提升。
對于移動設(shè)備負(fù)載,作者測試了Sqlite,durability guarantee帶來了75%性能提升,ordering guarantee帶來了2.8倍性能提升。
結(jié)語
“為高并發(fā)Flash設(shè)備設(shè)計一個支持barrier語義的IO stack會帶來極大的性能優(yōu)勢 …… 這種barrier語義已經(jīng)日漸成為一種必須品,我們建議從移動端到服務(wù)端的各種Flash設(shè)備廠商考慮支持barrier語義”
-
控制器
+關(guān)注
關(guān)注
112文章
15885瀏覽量
175377 -
存儲設(shè)備
+關(guān)注
關(guān)注
0文章
148瀏覽量
18525 -
阿里云
+關(guān)注
關(guān)注
3文章
922瀏覽量
42780
原文標(biāo)題:Barrier-enabled IO stack for Flash storage
文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論