linux系统数据落盘之细节
本文節(jié)選自這里,原文以mysql innodb系統(tǒng)為例,介紹了數(shù)據(jù)經(jīng)過的各層級的buffer和cache,其它系統(tǒng)也有相似的原理,摘錄于此。
3.??VFS層
該層的緩沖都放在主機(jī)內(nèi)存中,它的目的主要是在操作系統(tǒng)層緩沖數(shù)據(jù),避免慢速塊設(shè)備讀寫操作影響了IO的響應(yīng)時間。
3.1.??細(xì)究O_DIRECT/O_SYNC標(biāo)簽
在前面redo log buffer和innodb buffer pool的討論中涉及到很多數(shù)據(jù)刷新和數(shù)據(jù)安全的問題,我們在本節(jié)中,專門討論O_DIRECT/O_SYNC標(biāo)簽的含義。
我們打開一個文件并寫入數(shù)據(jù),VFS和文件系統(tǒng)是怎么把數(shù)據(jù)寫到硬件層列,下圖展示了關(guān)鍵的數(shù)據(jù)結(jié)構(gòu):
?
圖?4??VFS cache圖
該圖引用自The linux kernel’s VFS Layer。
圖中,我們看到該層中主要有page_cache/buffer cache/Inode-cache/Directory cache。其中page_cache/buffer cache主要用于緩沖內(nèi)存結(jié)構(gòu)數(shù)據(jù)和塊設(shè)備數(shù)據(jù)。而inode-cache用于緩沖inode,directory-cache用于緩沖目錄結(jié)構(gòu)數(shù)據(jù)。
根據(jù)文件系統(tǒng)和操作系統(tǒng)的不同,一般來說對一個文件的寫入操作包括兩部分,對數(shù)據(jù)本身的寫入操作,以及對文件屬性(metadata元數(shù)據(jù))的寫入操作(這里的文件屬性包括目錄,inode等)。
了解了這些以后,我們就能夠比較簡單的說清楚各個標(biāo)志的意義了:
| ? | page cache | buffer cache | inode cache | dictory cache |
| O_DIRECT | write bypass | write bypass | write & no flush | write & no flush |
| O_DSYNC/fdatasync() | write & flush | write & flush | write & no flush | write & no flush |
| O_SYNC/fsync() | write & flush | write & flush | write & flush | write & flush |
表格?3?VFS cache刷新表
?
l???O_DSYNC和fdatasync()的區(qū)別在于:是在每一個IO提交的時刻都針對對應(yīng)的page cache和buffer cache進(jìn)行刷新(即O_DSYNC,在write操作成功返回前已完成刷新);還是在一定數(shù)據(jù)的寫操作以后調(diào)用fdatasync()的時刻對整個page cache和buffer cache進(jìn)行刷新。O_SYNC和fsync()的區(qū)別同理。
l???page cache和buffer cache的主要區(qū)別在于一個是面向?qū)嶋H文件數(shù)據(jù),一個是面向塊設(shè)備。在VFS上層使用open()方式打開那些使用mkfs做成文件系統(tǒng)的文件,你就會用到page cache和buffer cache,而如果你在Linux操作系統(tǒng)上使用dd這種方式來操作Linux的塊設(shè)備,你就只會用到buffer cache。
l???O_DSYNC和O_SYNC的區(qū)別在于:O_DSYNC告訴內(nèi)核,當(dāng)向文件寫入數(shù)據(jù)的時候,只有當(dāng)數(shù)據(jù)寫到了磁盤時,寫入操作才算完成(write才返回成功)。O_SYNC比O_DSYNC更嚴(yán)格,不僅要求數(shù)據(jù)已經(jīng)寫到了磁盤,而且對應(yīng)的數(shù)據(jù)文件的屬性(例如文件inode,相關(guān)的目錄變化等)也需要更新完成才算write操作成功。可見O_SYNC較之O_DSYNC要多做一些操作。
l???Open()的referense中還有一個O_ASYNC,它主要用于terminals, pseudoterminals, sockets,?和pipes/FIFOs,是信號驅(qū)動的IO,當(dāng)設(shè)備可讀寫時發(fā)送一個信號(SIGIO),應(yīng)用進(jìn)程捕獲這個信號來進(jìn)行IO操作。
l???O_SYNC和O_DIRECT都是同步寫,也就是說只有寫成功了才會返回。
回過頭來,我們再來看innodb_flush_log_at_trx_commit的配置就比較好理解了。O_DIRECT直接IO繞過了page cache/buffer cache以后為什么還需要fsync()了,就是為了把directory cache和inode cache元數(shù)據(jù)也刷新到存儲設(shè)備上。
而由于內(nèi)核和文件系統(tǒng)的更新,有些文件系統(tǒng)能夠保證保證在O_DIRECT方式下不用fsync()同步元數(shù)據(jù)也不會導(dǎo)致數(shù)據(jù)安全性問題,所以InnoDB又提供了O_DIRECT_NO_FSYNC的方式。
?
當(dāng)然,O_DIRECT對讀和對寫都是有效的,特別是對讀,它可以保證讀到的數(shù)據(jù)是從存儲設(shè)備中讀到的,而不是緩存中的。避免緩存中的數(shù)據(jù)和存儲設(shè)備上的數(shù)據(jù)是不一致的情況(比如你通過DRBD將底層塊設(shè)備的數(shù)據(jù)更新了,對于非分布式文件系統(tǒng),緩存中的內(nèi)容和存儲設(shè)備上的數(shù)據(jù)就不一致了)。但是我們這里主要討論緩沖(寫buffer),就不深入討論了。這個問題了。
3.2.??O_DIRECT優(yōu)劣勢
在大部分的innodb_flush_method參數(shù)值的推薦中都會建議使用O_DIRECT,甚至在percona server分支中還提供了ALL_O_DIRECT,對日志文件也使用了O_DIRECT方式打開。
3.2.1.??優(yōu)勢:
l???節(jié)省操作系統(tǒng)內(nèi)存:O_DIRECT直接繞過page cache/buffer cache,這樣避免InnoDB在讀寫數(shù)據(jù)少占用操作系統(tǒng)的內(nèi)存,把更多的內(nèi)存留個innodb buffer pool來使用。
l???節(jié)省CPU。另外,內(nèi)存到存儲設(shè)備的傳輸方式主要有poll,中斷和DMA方式。使用O_DIRECT方式提示操作系統(tǒng)盡量使用DMA方式來進(jìn)行存儲設(shè)備操作,節(jié)省CPU。
3.2.2.??劣勢
l???字節(jié)對齊。O_DIRECT方式要求寫數(shù)據(jù)時,內(nèi)存是字節(jié)對齊的(對齊的方式根據(jù)內(nèi)核和文件系統(tǒng)的不同而不同)。這就要求數(shù)據(jù)在寫的時候需要有額外的對齊操作。可以通過/sys/block/sda/queue/logical_block_size知道對齊的大小,一般都是512個字節(jié)。
l???無法進(jìn)行IO合并。O_DIRECT繞過page cache/buffer cache直接寫存儲設(shè)備,這樣如果對同一塊數(shù)據(jù)進(jìn)行重復(fù)寫就無法在內(nèi)存中命中,page cache/buffer cache合并寫的功能就無法生效了。
l???降低順序讀寫效率。如果使用O_DIRECT打開文件,則讀/寫操作都會跳過cache,直接在存儲設(shè)備上讀/寫。因?yàn)闆]有了cache,所以文件的順序讀寫使用O_DIRECT這種小IO請求的方式效率是比較低的。
?
總的來說,使用O_DIRECT來設(shè)置innodb_flush_method并不是100%對所有應(yīng)用和場景都是適用的。
4.??存儲控制器層
該層的緩沖都放在存儲控制器的對應(yīng)板載cache中,它的目的主要是在存儲控制器層緩沖數(shù)據(jù),避免慢速塊設(shè)備讀寫操作影響了IO的響應(yīng)時間。
當(dāng)數(shù)據(jù)被fsync()等刷到存儲層時,首先會發(fā)送到存儲控制器層。常見的存儲控制器就是Raid卡,而目前大部分的Raid卡都有1G或者更大的存儲容量。這個緩沖一般為易失性的存儲,通過板載電池/電容來保證該“易失性的存儲”的數(shù)據(jù)在機(jī)器斷電以后仍然會同步到底層的磁盤存儲介質(zhì)上。
關(guān)于存儲控制器我們有一些幾個方面需要注意的:
針對是否使用緩沖,一般的存儲控制器都提供write back和write through兩種方式。write back方式下,操作系統(tǒng)提交的寫數(shù)據(jù)請求直接寫入到緩沖中就返回成功;write through方式下,操作系統(tǒng)提交的寫數(shù)據(jù)請求必須要真正寫到底層磁盤介質(zhì)上才返回成功。
為了保證機(jī)器掉電以后在“易失性”緩沖中的數(shù)據(jù)能夠及時刷新到底層磁盤介質(zhì)上,存儲控制器上都有電池/電容來保證。普通的電池有容量衰減的問題,也就是說每隔一段時間,板載的電池都要被控制充放電一次,以保證電池的容量。在電池充放過程中,被設(shè)置為write-back的存儲控制器會自動變?yōu)閣rite through。這個充放電的周期(Learn Cycle周期)一般為90天,LSI卡可以通過MegaCli來查看:
#MegaCli -AdpBbuCmd -GetBbuProperties-aAll
BBU Properties for Adapter: 0
??Auto Learn Period: 90 Days
??Next Learn time: Tue Oct 14 05:38:43 2014
??Learn Delay Interval:0 Hours
??Auto-Learn Mode: Enabled
如果你每隔一段時間發(fā)現(xiàn)IO請求響應(yīng)時間突然慢下來了,就有可能是這個問題哦。通過MegaCli -AdpEventLog -GetEvents -f mr_AdpEventLog.txt -aALL的日志中的Event Description: Battery started charging就可以確定是否發(fā)生了發(fā)生了充放電的情況。
由于電池有這個問題,新的Raid卡會配置電容來保證“易失性”緩沖中的數(shù)據(jù)能夠及時刷新到底層磁盤介質(zhì)上,這樣就沒有充放電的問題了。
HP的smart array提供對cache的讀和寫的區(qū)別(Accelerator Ratio),
hpacucli ctrl all show config detail|grep 'Accelerator Ratio'
Accelerator Ratio: 25% Read / 75% Write
這樣你就可以根據(jù)應(yīng)用的實(shí)際情況來設(shè)置用于緩存讀和緩沖寫的cache的比例了。
為了能夠讓上層的設(shè)備使用Direct IO方式來繞過raid卡,對Raid需要設(shè)置開啟DirectIO方式:
/opt/MegaRAID/MegaCli/MegaCli64 -LDSetProp -Direct -Immediate -Lall -aAll
上面我們提到了“易失性”緩沖,如果我們現(xiàn)在有一個非易失性的緩沖,并且容量達(dá)到幾百G,這樣的存儲控制器緩沖是不是更能給底層設(shè)備提速?作為老牌的Raid卡廠商,LSI目前就有這樣的存儲控制器,使用write back方式和比較依賴存儲控制器緩沖的應(yīng)用可以考慮使用這種類型的存儲控制器。
目前raid卡的cache是否有電池或者電容保護(hù)對Linux來說是不可見的,所以Linux為了保證日志文件系統(tǒng)的一致性,默認(rèn)會打開write barriers,也就是說,它會不斷的刷新“易失性”緩沖,這樣會大大降低IO性能。所以如果你確信底層的電池能夠保證“易失性”緩沖會刷到底層磁盤設(shè)備的話,你可以在磁盤mount的時候加上-o nobarrier。
5.??磁盤控制器層
該層的緩沖都放在磁盤控制器的對應(yīng)板載cache中。存儲設(shè)備固件(firmware)會按規(guī)則排序?qū)懖僮髡嬲降浇橘|(zhì)中去。這里主要是保證寫的順序性,對機(jī)械磁盤來說,這樣可以盡量讓一次磁頭的移動能夠完成更多的磁碟寫入操作。
一般來說,DMA控制器也是放在磁盤這一層的,通過DMA控制器直接進(jìn)行內(nèi)存訪問,能夠節(jié)省CPU的資源。
對于機(jī)械硬盤,因?yàn)橐话愕拇疟P設(shè)備上并沒有電池電容等,無法保證在機(jī)器掉電時磁盤cache里面的所有數(shù)據(jù)能夠及時同步到介質(zhì)上,所以我們強(qiáng)烈建議把disk cache關(guān)閉掉。
Disk cache可以在存儲控制器層關(guān)閉。例如,使用MegaCli關(guān)閉的命令如下:
MegaCli -LDSetProp -DisDskCache???-Lall -aALL
轉(zhuǎn)載于:https://www.cnblogs.com/wuhuiyuan/p/4648725.html
總結(jié)
以上是生活随笔為你收集整理的linux系统数据落盘之细节的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jdbc写入和读取过程
- 下一篇: 7月14日总结