
存儲 IO 重要的一個知識點

劃重點:存儲 IO 要對齊。
資深存儲人員為啥總叫你注意 IO 對齊的?機械磁盤 IO 為什么要 512 對齊呢,SSD 盤為啥要 4K 對齊?不對齊又會如何?
重要的知識點:
機械盤的 IO 要扇區(qū)對齊(絕大部分的扇區(qū)是 512 字節(jié)大小),磁盤的讀寫最小單元就是扇區(qū); SSD 盤的 IO 要 4K 對齊,SSD 盤的讀寫單元是 page,一個 page 為 4K 大小;
如果不對齊,會有問題?
性能極差; SSD 壽命縮短;
那你就會想了,出現(xiàn)這個問題的原因又是啥?
本質(zhì)原因是內(nèi)部 IO 流量和次數(shù)的放大。
那你又會想了,怎么會這樣呢,我不就寫 1 個字節(jié)數(shù)據(jù)而已嘛,放大個啥?
這個秘密就在于前面提到的,機械盤和 SSD 盤的 IO 都有最小單元的概念。機械盤是以扇區(qū)為最小的空間單位,SSD 盤則是 4k 的 page 作為 IO 的最小單元。所以當(dāng)在機械盤上讀 1 個字節(jié)的數(shù)據(jù),本質(zhì)上是至少讀一個扇區(qū),寫 1 個字節(jié)則更復(fù)雜,先要把這個扇區(qū)讀出來,然后在內(nèi)存里 update,最后又把這個扇區(qū)寫回到磁盤。
你可能又有疑問了:為啥機械盤和 SSD 盤都要按照一個單元來管理呢,為啥不 1 字節(jié) 1 字節(jié)管理呢?如果這樣的話,業(yè)務(wù)讀寫不就方便了嘛。
答案是:開銷。 考慮以下兩個方面:
第一個是存儲的開銷:數(shù)據(jù)存儲到磁盤上還有 SSD 盤上是會有校驗的(比如 ECC 校驗),如果每個字節(jié)都對應(yīng)一個校驗,存 1T 的數(shù)據(jù)有 1T 的校驗?那這個存儲開銷無比的大。那如果是現(xiàn)在 512 字節(jié)對應(yīng)一個 1 字節(jié)的校驗,則開銷完全可控; 第二個是性能的開銷:物理硬件是跟真實世界的設(shè)計匹配的,對于機械磁盤的寫是利用磁化介質(zhì)來存儲數(shù)據(jù),如果磁盤上是1 個字節(jié),甚至 1 個 bit 來獨立存儲,那磁盤磁頭的次數(shù)將無比龐大,性能也將無比的下降(每一次都是寫數(shù)據(jù)+校驗)。SSD 的寫則更復(fù)雜,因為 SSD 由于自身的存儲特點,是無法覆蓋寫的,每次寫都是寫新位置,舊的位置則是作為垃圾等待后臺 GC ,粒度太小則會導(dǎo)致擦寫的次數(shù)無比的多,性能和壽命都將不可接受;
所以說,在綜合因素的權(quán)衡下,硬件對于空間管理會劃分固定單元,并對 IO 也提出單元對齊的要求。至于磁盤固定單元為 512 字節(jié),SSD 的 IO 單元為 4K 則是經(jīng)過綜合的科學(xué)測試和驗證的一個數(shù)值而已。
舉個不嚴謹?shù)睦?/strong>:
在京東上買東西,你買 1 塊錢的貨,京東要收費 7 塊的運費。對你來講是不是劃不來?因為對京東來講,如果真是單獨送你這 1 塊錢的東西也劃不來。所以京東要你買的東西滿 79 元才給你免運費。
如果說真的有個愣頭青,每次都單獨買 1 塊錢的貨,買它 100 次,劃得來來不?
當(dāng)然劃不來,運費都要 700 了,加上貨本身,總費用 800 元(哈哈,可能京東被你折騰的更慘)。
那如果是 1 次買 100 件這個貨呢?
你只需要 100 塊。
所以,你再思考下為什么磁盤本身一定有固定大小的存儲單元,通俗話叫做:量大從優(yōu),專業(yè)一點叫做:減少邊際效應(yīng)。

對齊有哪些方面

對齊其實很簡單,只有兩個維度:
偏移對齊 長度對齊
是不是很簡單呀。偏移和長度就是我們常說的 offset
,length
,對齊通常就是既要保證偏移對齊也要保證長度對齊。

IO 讀寫的真實樣子

下面以機械盤扇區(qū)對齊和非對齊的舉例。為了簡化,以下例子討論的的對齊都是偏移和長度雙重對齊的。
場景:讀 512 個字節(jié)數(shù)據(jù)是怎么做的?
步驟如下:
磁頭擺到指定偏移; 讀取一個扇區(qū)的數(shù)據(jù)到內(nèi)存;

開銷:只需要一次磁盤讀 IO。
場景:寫 512 個字節(jié)數(shù)據(jù)是怎么做的?
步驟如下:
磁頭擺到指定偏移; 覆蓋寫一個扇區(qū)的數(shù)據(jù)到磁盤;

開銷:只需要一次磁盤寫 IO。
場景:讀 1 個字節(jié)數(shù)據(jù)是怎么做的?
步驟如下:
磁頭擺到這 1 個字節(jié)數(shù)據(jù)所在扇區(qū)位置,對齊到扇區(qū)開始的偏移; 讀取 1 個完整扇區(qū)( 512 字節(jié))的數(shù)據(jù)到內(nèi)存; 從這 512 字節(jié)的內(nèi)存中,copy 出用戶要用的 1 個字節(jié),給到用戶;

開銷:讀放大。如果是讀 512 字節(jié)的數(shù)據(jù),但是偏移不對齊,那么可能導(dǎo)致 2 次 IO。
場景:讀 512 個字節(jié),但是偏移不對齊?
步驟如下:
磁頭擺到這 512 個字節(jié)數(shù)據(jù)所在 2 個扇區(qū)位置,對齊到扇區(qū)開始的偏移; 讀取 2 個完整扇區(qū)(1024 Bytes)的數(shù)據(jù)到內(nèi)存; 從這 1024 字節(jié)的內(nèi)存中,copy 出用戶要用的 512 個字節(jié),給到用戶;

開銷:讀放大。雖然讀的是 1 個扇區(qū)的數(shù)據(jù),但是偏移卻沒對齊,所以必須要讀 2 個扇區(qū),也放大了一倍的流量。
場景:寫 1 個字節(jié)數(shù)據(jù)是怎么做的?
寫是比較復(fù)雜的,用戶現(xiàn)在手握 1 個字節(jié)的數(shù)據(jù),想要寫到磁盤,但是磁盤的 IO 單元是扇區(qū),所以本質(zhì)上是讀改寫的方式。步驟如下:
先要把這要改動的 1 字節(jié)所在的扇區(qū)完整的讀到內(nèi)存; 磁頭擺動到扇區(qū)偏移; 讀一個扇區(qū),讀到內(nèi)存; 然后在內(nèi)存中,把這 1 個字節(jié)對應(yīng)的位置的數(shù)據(jù)修改; 然后重新寫回扇區(qū); 磁盤尋道扇區(qū)偏移; 覆蓋寫著一個扇區(qū);

開銷:一次磁盤讀 IO,內(nèi)存合并,最后再一次磁盤寫 IO。明明是寫,卻必須要先讀,IO 即放大了流量,又放大了次數(shù)
所以你看出來了嗎,非對齊的 IO 多了很多步驟。存在 IO 流量和次數(shù)的放大。這樣會極度拖累性能。
本來只需要一次 IO 就能完成的操作,放大了一次,那么性能就至少下降一倍。就這么簡單。
場景:寫 1 個扇區(qū)的數(shù)據(jù),但是偏移不對齊會怎么樣?
操作步驟:
讀 2 個扇區(qū)的數(shù)據(jù)(1024 Bytes)上來; 合并內(nèi)存中的數(shù)據(jù); 把這 2 個新的扇區(qū)數(shù)據(jù),寫到磁盤;
開銷:所以,我們看到由于不對齊,讀的時候?qū)е露嘧x了一個扇區(qū),寫的時候?qū)е露鄬懥?1 個扇區(qū)。性能自然是極差的。

小伙伴經(jīng)常忽略的事情?

機械盤來說,隨機 iops 就是幾百的樣子,帶寬也就幾百兆。一次尋道都是 10ms 級別的。所以磁盤讀寫數(shù)據(jù)的代價遠比你想象中的大。
這個有多慢?cpu 執(zhí)行指令都是納秒和微秒級別的,一次 IO 性能和 cpu 或者內(nèi)存的操作相差十萬百千里。所以,但凡你能省 1 次 IO 都是非常大的性能提升。
而對于 SSD 來說,如果你 IO 不對齊,很有可能峰值能跑 5 萬 iops 的盤只能跑 2 萬甚至更低。大家一定要有個意識:IO 能節(jié)省就節(jié)省,多一次 IO 性能可能慢 1 倍。
這個時候你可能反問了,我讀寫文件從沒考慮過對齊的問題呀?
是的,你是沒考慮過,那是因為有一個苦逼幫你把這個活干了,誰呢?
文件系統(tǒng)。這個世界并不簡單,只是有人替你負重前行。
絕大部分的程序員都是基于文件系統(tǒng)之上操作磁盤。文件系統(tǒng)則會使用 buffer cache 自動幫用戶對齊 IO ,然后再下發(fā)磁盤。一旦你想要深入優(yōu)化 IO 的性能,IO 對齊一定是第一道要考量的坎。
還有一點要特別注意,一個特別重要的環(huán)節(jié):文件系統(tǒng)格式化化的時候。
格式化的時候,一定要注意對齊。 格式化文件系統(tǒng)的時候,一定要注意對齊的偏移,不要故意搞成非對齊的偏移,不然一旦文件系統(tǒng)格式化的時候都不對齊,后面誰也救不了,除非你重新格式化文件系統(tǒng)。
舉個例子,本來文件系統(tǒng)從偏移磁盤 0 這個位置格式化,你偏不,你偏要從 3 字節(jié)偏移的位置開始格式化。那后面的所有的貌似對齊的 IO 偏移都將是不對齊的,性能也自然是下降的。

總結(jié)

IO 對齊是做存儲必須要考量的一個因素; IO 對齊的兩個核心是:偏移和長度; 非 IO 對齊的請求會導(dǎo)致內(nèi)部 IO 流量和次數(shù)的放到,從而性能下降(SSD 則會因為放到而導(dǎo)致擦寫次數(shù)過多,更會影響壽命); 程序員一般很少要主動對齊,因為文件系統(tǒng)幫你 hole 住了一層。但是如果程序員自己不注意,還是會踩坑。比如明明是 SSD 盤,你偏要每次發(fā)送 512 字節(jié)的 IO 請求,那性能肯定慘不忍睹; 對齊的 IO 簡簡單單,不對齊的 IO 千奇百怪;
~完~
往期推薦