1、為什么需要IO加速
傳統的機械磁盤(pán)在尋址時(shí)需要移動(dòng)磁頭到目標位置,移動(dòng)磁頭的操作是機械磁盤(pán)性能低下的主要原因,雖然各種系統軟件或者IO調度器都致力于減少磁頭的移動(dòng)來(lái)提高性能,但大部分場(chǎng)景下只是改善效果。一般,一塊SATA機械磁盤(pán)只有300左右的4K隨機IOPS,對于大多數云主機來(lái)說(shuō),300的隨機IOPS哪怕獨享也是不夠的,更何況在云計算的場(chǎng)景中,一臺物理宿主機上會(huì )有多臺云主機。因此,必須要有其他的方法來(lái)大幅提升IO性能。
早期SSD價(jià)格昂貴,采用SSD必然會(huì )帶來(lái)用戶(hù)使用成本的提升。于是,我們開(kāi)始思考能否從技術(shù)角度來(lái)解決這個(gè)問(wèn)題,通過(guò)對磁盤(pán)性能特性的分析,我們開(kāi)始研發(fā)第一代IO加速方案。即使今天SSD越來(lái)越普及,機械盤(pán)憑借成本低廉以及存儲穩定的特點(diǎn),仍然廣泛應用,而IO加速技術(shù)能讓機械盤(pán)滿(mǎn)足絕大多數應用場(chǎng)景的高IO性能需求。
2IO加速原理及第一代IO加速
機械磁盤(pán)的特性是隨機IO性能較差,但順序IO性能較好,如前文中提到的4K隨機IO只能有300 IOPS的性能,但其順序IO性能可以達到45000 IOPS。
IO加速的基本原理就是利用了機械磁盤(pán)的這種性能特性,首先系統有兩塊盤(pán):一塊是cache盤(pán),它是容量稍小的機械盤(pán),用來(lái)暫時(shí)保存寫(xiě)入的數據;另一塊是目標盤(pán),它是容量較大的機械盤(pán),存放最終的數據。
1. IO的讀寫(xiě)
寫(xiě)入時(shí)將上層的IO順序的寫(xiě)入到cache盤(pán)上,因為是順序的方式寫(xiě)入所以性能非常好,然后在cache盤(pán)空閑時(shí)由專(zhuān)門(mén)的線(xiàn)程將該盤(pán)的數據按照寫(xiě)入的先后順序回刷到目標盤(pán),使得cache盤(pán)保持有一定的空閑空間來(lái)存儲新的寫(xiě)入數據。
為了做到上層業(yè)務(wù)無(wú)感知,我們選擇在宿主機內核態(tài)的device mapper層(簡(jiǎn)稱(chēng)dm層)來(lái)實(shí)現該功能,dm層結構清晰,模塊化較為方便,實(shí)現后對上層體現為一個(gè)dm塊設備,上層不用關(guān)心這個(gè)塊設備是如何實(shí)現的,只需要知道這是一個(gè)塊設備可以直接做文件系統使用。

按照上述方式,當新的IO寫(xiě)入時(shí),dm層模塊會(huì )將該IO先寫(xiě)入cache盤(pán),然后再回刷到目標盤(pán),這里需要有索引來(lái)記錄寫(xiě)入的IO在cache盤(pán)上的位置和在目標盤(pán)上的位置信息,后續的回刷線(xiàn)程就可以利用該索引來(lái)確定IO數據源位置和目標位置。我們將索引的大小設計為512字節,因為磁盤(pán)的扇區是512字節,所以每次的寫(xiě)入信息變成了4K數據+512字節索引的模式,為了性能考慮,索引的信息也會(huì )在內存中保留一份。
讀取過(guò)程比較簡(jiǎn)單,通過(guò)內存中的索引判斷需要讀取位置的數據是在cache盤(pán)中還是在目標盤(pán)中,然后到對應的位置讀取即可。
寫(xiě)入的數據一般為4K大小,這是由內核dm層的特性決定的,當寫(xiě)入IO大于4K時(shí),dm層默認會(huì )將數據切分,比如寫(xiě)入IO是16K,那么就會(huì )切分成4個(gè)4K的IO;如果寫(xiě)入數據不是按照4K對齊的,比如只有1024字節,那么就會(huì )先進(jìn)行特殊處理,首先檢查該IO所覆蓋的數據區,如果所覆蓋的內存區在cache盤(pán)中有數據,那么需要將該數據先寫(xiě)入目標盤(pán),再將該IO寫(xiě)入目標盤(pán),這個(gè)處理過(guò)程相對比較復雜,但在文件系統場(chǎng)景中大部分IO都是4K對齊的,只有極少數IO是非對齊的,所以并不會(huì )對業(yè)務(wù)的性能造成太大影響。
2. 索引的快速恢復與備份
系統在運行過(guò)程中無(wú)法避免意外掉電或者系統關(guān)閉等情況發(fā)生,一個(gè)健壯的系統必須能夠在遇到這些情況時(shí)依然能保證數據的可靠性。當系統啟動(dòng)恢復時(shí),需要重建內存中的索引數據,這個(gè)數據在cache盤(pán)中已經(jīng)和IO數據一起寫(xiě)入了,但因為索引是間隔存放的,如果每次都從cache盤(pán)中讀取索引,那么,數據的恢復速度會(huì )非常慢。
為此,我們設計了內存索引的定期dump機制,每隔大約1小時(shí)就將內存中的索引數據dump到系統盤(pán)上,啟動(dòng)時(shí)首先讀取該dump索引,然后再從cache盤(pán)中讀取dump索引之后的最新1小時(shí)內的索引,這樣,就大大提升了系統恢復的啟動(dòng)時(shí)間。
依據上述原理,UCloud自研了第一代IO加速方案。采用該方案后,系統在加速隨機寫(xiě)入方面取得了顯著(zhù)效果,且已在線(xiàn)上穩定運行。
3. 第一代IO加速方案存在的問(wèn)題
但隨著(zhù)系統的運行,我們也發(fā)現了一些問(wèn)題。

1)索引內存占用較大
磁盤(pán)索引因為扇區的原因最小為512字節,但內存中的索引其實(shí)沒(méi)有必要使用這么多,過(guò)大的索引會(huì )過(guò)度消耗內存。
2)負載高時(shí)cache盤(pán)中堆積的IO數據較多
IO加速的原理主要是加速隨機IO,對順序IO因為機械盤(pán)本身性能較好不需要加速,但該版本中沒(méi)有區分順序IO和隨機IO,所有IO都會(huì )統一寫(xiě)入cache盤(pán)中,使得cache堆積IO過(guò)多。
3)熱升級不友好
初始設計時(shí)對在線(xiàn)升級的場(chǎng)景考慮不足,所以第一代IO加速方案的熱升級并不友好。
4)無(wú)法兼容新的512e機械磁盤(pán)
傳統機械磁盤(pán)物理扇區和邏輯扇區都是512字節,而新的512e磁盤(pán)物理扇區是4K了,雖然邏輯扇區還可以使用512字節,但性能下降嚴重,所以第一代IO加速方案的4K數據+512字節索引的寫(xiě)入方式需要進(jìn)行調整。
5)性能無(wú)法擴展
系統性能取決于cache盤(pán)的負載,無(wú)法進(jìn)行擴展。
4..第二代IO加速技術(shù)
上述問(wèn)題都是在第一代IO加速技術(shù)線(xiàn)上運營(yíng)的過(guò)程中發(fā)現的。并且在對新的機械磁盤(pán)的兼容性方面,因為傳統的512字節物理扇區和邏輯扇區的512n類(lèi)型磁盤(pán)已經(jīng)逐漸不再生產(chǎn),如果不對系統做改進(jìn),系統可能會(huì )無(wú)法適應未來(lái)需求。因此,我們在第一代方案的基礎上,著(zhù)手進(jìn)行了第二代IO加速技術(shù)的研發(fā)和優(yōu)化迭代。
1. 新的索引和索引備份機制
第一代的IO加速技術(shù)因為盤(pán)的原因無(wú)法沿用4K+512Byte的格式,為了解決這個(gè)問(wèn)題,我們把數據和索引分開(kāi),在系統盤(pán)上專(zhuān)門(mén)創(chuàng )建了一個(gè)索引文件,因為系統盤(pán)基本處于空閑狀態(tài),所以不用擔心系統盤(pán)負載高影響索引寫(xiě)入,同時(shí)我們還優(yōu)化了索引的大小由512B減少到了64B,而數據部分還是寫(xiě)入cache盤(pán),如下圖所示:

其中索引文件頭部和數據盤(pán)頭部保留兩個(gè)4K用于存放頭數據,頭數據中包含了當前cache盤(pán)數據的開(kāi)始和結束的偏移,其后是具體的索引數據,索引與cache盤(pán)中的4K數據是一一對應的關(guān)系,也就是每個(gè)4K的數據就會(huì )有一個(gè)索引。
因為索引放在了系統盤(pán),所以也要考慮,如果系統盤(pán)發(fā)生了不可恢復的損壞時(shí),如何恢復索引的問(wèn)題。雖然系統盤(pán)發(fā)生損壞是非常小概率的事件,但一旦發(fā)生,索引文件將會(huì )完全丟失,這顯然是無(wú)法接受的。因此,我們設計了索引的備份機制,每當寫(xiě)入8個(gè)索引,系統就會(huì )將這些索引合并成一個(gè)4K的索引備份塊寫(xiě)入cache盤(pán)中(具體見(jiàn)上圖中的紫色塊),不滿(mǎn)4K的部分就用0來(lái)填充,這樣當系統盤(pán)真的發(fā)生意外也可以利用備份索引來(lái)恢復數據。
在寫(xiě)入時(shí)會(huì )同時(shí)寫(xiě)入索引和數據,為了提高寫(xiě)入效率,我們優(yōu)化了索引的寫(xiě)入機制,引入了合并寫(xiě)入的方式:

當寫(xiě)入時(shí)可以將需要寫(xiě)入的多個(gè)索引合并到一個(gè)4K的write buffer中,一次性寫(xiě)入該write buffer,這樣避免了每個(gè)索引都會(huì )產(chǎn)生一個(gè)寫(xiě)入的低效率行為,同時(shí)也保證了每次的寫(xiě)入是4K對齊的。
2. 順序IO識別能力
在運營(yíng)第一代IO加速技術(shù)的過(guò)程中,我們發(fā)現用戶(hù)在做數據備份、導入等操作時(shí),會(huì )產(chǎn)生大量的寫(xiě)入,這些寫(xiě)入基本都是順序的,其實(shí)不需要加速,但第一代的IO加速技術(shù)并沒(méi)有做區分,所以這些IO都會(huì )被寫(xiě)入在cache盤(pán)中,導致cache盤(pán)堆積的IO過(guò)多。為此,我們添加了順序IO識別算法,通過(guò)算法識別出順序的IO,這些IO不需要通過(guò)加速器,會(huì )直接寫(xiě)入目標盤(pán)。
一個(gè)IO剛開(kāi)始寫(xiě)入時(shí)是無(wú)法預測此IO是順序的還是隨機的,一般的處理方式是當一個(gè)IO流寫(xiě)入的位置是連續的,并且持續到了一定的數量時(shí),才能認為這個(gè)IO流是順序的,所以算法的關(guān)鍵在于如何判斷一個(gè)IO流是連續的,這里我們使用了觸發(fā)器的方式。
當一個(gè)IO流開(kāi)始寫(xiě)入時(shí),我們會(huì )在這個(gè)IO流寫(xiě)入位置的下一個(gè)block設置一個(gè)觸發(fā)器,觸發(fā)器被觸發(fā)就意味著(zhù)該block被寫(xiě)入了,那么就將觸發(fā)器往后移動(dòng)到再下一個(gè)block,當觸發(fā)器被觸發(fā)了一定的次數,我們就可以認為這個(gè)IO流是順序的,當然如果觸發(fā)器被觸發(fā)后一定時(shí)間沒(méi)有繼續被觸發(fā),那么我們就可以回收該觸發(fā)器。
3. 無(wú)感知熱升級

第一代的IO加速技術(shù)設計上對熱升級支持并不友好,更新存量版本時(shí)只能通過(guò)熱遷移然后重啟的方式,整個(gè)流程較為繁瑣,所以在開(kāi)發(fā)第二代IO加速技術(shù)時(shí),我們設計了無(wú)感知熱升級的方案。
由于我們的模塊是位于內核態(tài)的dm層,一旦初始化后就會(huì )生成一個(gè)虛擬的dm塊設備,該塊設備又被上層文件系統引用,所以這個(gè)模塊一旦初始化后就不能卸載了。為了解決這個(gè)問(wèn)題,我們設計了父子模塊的方式,父模塊在子模塊和dm層之間起到一個(gè)橋梁的作用,該父模塊只有非常簡(jiǎn)單的IO轉發(fā)功能,并不包含復雜的邏輯,因此可以確保父模塊不需要進(jìn)行升級,而子模塊包含了復雜的業(yè)務(wù)邏輯,子模塊可以從父模塊中卸載來(lái)實(shí)現無(wú)感知熱升級:
上圖中的binlogdev.ko就是父模塊,cachedev.ko為子模塊,當需要熱升級時(shí)可以將cache盤(pán)設置為只讀模式,這樣cache盤(pán)只回刷數據不再寫(xiě)入,等cache盤(pán)回刷完成后,可以認為后續的寫(xiě)入IO可直接寫(xiě)入目標盤(pán)而不用擔心覆蓋cache盤(pán)中的數據,這樣子模塊就可以順利拔出替換了。
這樣的熱升級機制不僅實(shí)現了熱升級的功能,還提供了故障時(shí)的規避機制,在IO加速技術(shù)的灰度過(guò)程中,我們就發(fā)現有個(gè)偶現的bug會(huì )導致宿主機重啟,我們第一時(shí)間將所有cache盤(pán)設置為只讀,以避免故障的再次發(fā)生,并爭取到了debug的時(shí)間。
4. 兼容512e機械磁盤(pán)
新一代的機械磁盤(pán)以512e為主,該類(lèi)型的磁盤(pán)需要寫(xiě)入IO按照4K對齊的方式才能發(fā)揮最大性能,所以原先的4K+512B的索引格式已經(jīng)無(wú)法使用,我們也考慮過(guò)把512B的索引擴大到4K,但這樣會(huì )導致索引占用空間過(guò)多,且寫(xiě)入時(shí)也會(huì )額外占用磁盤(pán)的帶寬效率太低,所以最終通過(guò)將索引放到系統盤(pán)并結合上文提到的合并寫(xiě)入技術(shù)來(lái)解決該問(wèn)題。
5. 性能擴展和提升
在第一代的IO加速技術(shù)中只能使用1塊cache盤(pán),當這塊cache盤(pán)負載較高時(shí)就會(huì )影響系統的性能,在第二代IO加速中,我們設計了支持多塊cache盤(pán),并按照系統負載按需插入的方式,使加速隨機IO的能力隨著(zhù)盤(pán)數量的提升而提升。在本地cache盤(pán)以及網(wǎng)絡(luò )cache盤(pán)都采用SATA機械磁盤(pán)的條件下,測試發(fā)現,隨著(zhù)使用的cache盤(pán)數量的增多,隨機寫(xiě)的性能也得到了大幅度的提升。
- 在只使用一塊本地cache盤(pán)時(shí),隨機寫(xiě)性能可達4.7W IOPS;

- 在使用一塊本地cache盤(pán)加一塊網(wǎng)絡(luò )cache盤(pán)時(shí),隨機寫(xiě)性能可達9W IOPS;

- 在使用一塊本地cache盤(pán)加兩塊網(wǎng)絡(luò )cache盤(pán)時(shí),隨機寫(xiě)性能可達13.6W IOPS;

目前,我們已經(jīng)大規模部署應用了第二代IO加速技術(shù)的云主機。得益于上述設計,之前備受困擾的cache盤(pán)IO堆積過(guò)多、性能瓶頸等問(wèn)題得到了極大的緩解,特別是IO堆積的問(wèn)題,在第一代方案下,負載較高時(shí)經(jīng)常觸發(fā)并導致性能損失和運維開(kāi)銷(xiāo),采用第二代IO加速技術(shù)后,該監控告警只有偶現的幾例觸發(fā)。
5寫(xiě)在最后
云主機IO加速技術(shù)極大提升了機械盤(pán)隨機寫(xiě)的處理能力,使得用戶(hù)可以利用較低的價(jià)格滿(mǎn)足業(yè)務(wù)需求。且該技術(shù)的本質(zhì)并不單單在于對機械盤(pán)加速,更是使系統層面具備了一種可以把性能和所處的存儲介質(zhì)進(jìn)行分離的能力,使得IO的性能并不受限于其所存儲的介質(zhì)。此外,一項底層技術(shù)在實(shí)際生產(chǎn)環(huán)境中的大規模應用,其設計非常關(guān)鍵,特別是版本熱升級、容錯以及性能考慮等都需要仔細斟酌。希望本文可以幫助大家更好的理解底層技術(shù)的特點(diǎn)及應用,并在以后的設計中做出更好的改進(jìn)。