淺淡Linux的IO和磁盤IO的檢測(cè)
IO的分類
文件讀寫方式的各種差異,導(dǎo)致 I/O 的分類多種多樣。最常見的有,
- 緩沖與非緩沖 I/O。根據(jù)是否使用了標(biāo)準(zhǔn)庫(kù)的緩存接口,自己編寫的緩存等:
1.緩沖 I/O,是指利用標(biāo)準(zhǔn)庫(kù)緩存來加速文件的訪問,而標(biāo)準(zhǔn)庫(kù)內(nèi)部再通過系統(tǒng)調(diào)度訪問文件。
2.非緩沖 I/O,是指直接通過系統(tǒng)調(diào)用來訪問文件,不再經(jīng)過標(biāo)準(zhǔn)庫(kù)緩存。
- 直接與非直接 I/O。根據(jù)是否使用了內(nèi)核的緩存。使用內(nèi)核緩存的是非直接io。open系統(tǒng)調(diào)用O_DIRECT參數(shù):
1.直接 I/O,是指跳過操作系統(tǒng)的頁緩存,直接跟文件系統(tǒng)交互來訪問文件。
2.非直接 I/O 正好相反,文件讀寫時(shí),先要經(jīng)過系統(tǒng)的頁緩存,然后再由內(nèi)核或額外的系統(tǒng)調(diào)用,真正寫入磁盤。
- 同步的阻塞與非阻塞 I/O。根據(jù)應(yīng)用程序是否阻塞自身運(yùn)行,可以把文件 I/O 分為阻塞 I/O 和非阻塞 I/O:
1.阻塞 I/O,是指應(yīng)用程序執(zhí)行 I/O 操作后,如果沒有獲得響應(yīng),就會(huì)阻塞當(dāng)前線程,自然就不能執(zhí)行其他任務(wù)。
2.非阻塞 I/O,是指應(yīng)用程序執(zhí)行 I/O 操作后,不會(huì)阻塞當(dāng)前的線程,而會(huì)立刻返回。設(shè)置 O_NONBLOCK 標(biāo)志,就表示用非阻塞方式訪問,可以繼續(xù)執(zhí)行其他的任務(wù),隨后再通過輪詢或者事件通知的形式,獲取調(diào)用的結(jié)果。嚴(yán)格講是把阻塞點(diǎn)的位置換了(select,poll,epoll等)。主要是使用在標(biāo)準(zhǔn)輸出和網(wǎng)絡(luò)上。
- 同步與異步 I/O 。根據(jù)是否等待響應(yīng)結(jié)果,可以把文件 I/O 分為同步和異步 I/O:
1.同步 I/O,是指應(yīng)用程序執(zhí)行 I/O 操作后,要一直等到整個(gè) I/O 完成后,才能獲得 I/O 響應(yīng)。
2.異步 I/O,是指應(yīng)用程序執(zhí)行 I/O 操作后,不用等待完成和完成后的響應(yīng),而是繼續(xù)執(zhí)行就可以。等到這次 I/O 完成后,響應(yīng)會(huì)用事件通知的方式,告訴應(yīng)用程序。
Linux上的文件系統(tǒng) I/O
進(jìn)程要想往文件系統(tǒng)里面讀寫數(shù)據(jù),需要很多層的組件一起合作。具體是怎么合作的呢?我們一起來看一看。
在應(yīng)用層,進(jìn)程在進(jìn)行文件讀寫操作時(shí),可通過系統(tǒng)調(diào)用如 sys_open、sys_read、sys_write 等。在內(nèi)核,每個(gè)進(jìn)程都需要為打開的文件,維護(hù)一定的數(shù)據(jù)結(jié)構(gòu)。在內(nèi)核,整個(gè)系統(tǒng)打開的文件,也需要維護(hù)一定的數(shù)據(jù)結(jié)構(gòu)。

通用塊層
通用塊層是一個(gè)內(nèi)核組件,它處理來自系統(tǒng)中的所有塊設(shè)備的請(qǐng)求。
- 將數(shù)據(jù)從磁盤映射到內(nèi)存中。僅當(dāng)cpu訪問數(shù)據(jù)時(shí),才將頁框映射為內(nèi)核中的線性地址中,并在數(shù)據(jù)訪問結(jié)束時(shí)取消映射。
- 通過一些附件手段,如DMA等,實(shí)現(xiàn)一個(gè)“零-拷貝”模式,將磁盤數(shù)據(jù)直接存放在用戶態(tài)的地址空間中而不是首先復(fù)制到內(nèi)核地址空間。因?yàn)?,?nèi)核為I/O數(shù)據(jù)傳送使用的緩沖區(qū)所在的葉框就映射在進(jìn)程的用戶態(tài)線性地址中。
- 管理邏輯卷,例如LVM和RAID(軟件RAID)使用的邏輯卷。
通用塊層是 Linux 磁盤 I/O 的核心。向上,它為文件系統(tǒng)和應(yīng)用程序,提供訪問了塊設(shè)備的標(biāo)準(zhǔn)接口;向下,把各種異構(gòu)的磁盤設(shè)備,抽象為統(tǒng)一的塊設(shè)備,并會(huì)對(duì)文件系統(tǒng)和應(yīng)用程序發(fā)來的 I/O 請(qǐng)求進(jìn)行重新排序、請(qǐng)求合并等,提高了磁盤訪問的效率。
I/O調(diào)度程序?qū)?/h3>
事實(shí)上,Linux 內(nèi)核支持四種 I/O 調(diào)度算法,分別是 NOOP、CFQ 、DeadLine與Anticipatory。這里我也分別介紹一下。
第一種 NOOP ,也被稱為電梯算法。是最簡(jiǎn)單的一種 I/O 調(diào)度算法。它實(shí)際上是一個(gè)先入先出的隊(duì)列,只做一些最基本的請(qǐng)求合并,常用于 SSD 磁盤。
第二種 CFQ(Completely Fair Scheduler),也被稱為完全公平調(diào)度器,是現(xiàn)在很多發(fā)行版的默認(rèn) I/O 調(diào)度器,它為每個(gè)進(jìn)程維護(hù)了一個(gè) I/O 調(diào)度隊(duì)列,并按照時(shí)間片來均勻分布每個(gè)進(jìn)程的 I/O 請(qǐng)求。
類似于進(jìn)程 CPU 調(diào)度,CFQ 還支持進(jìn)程 I/O 的優(yōu)先級(jí)調(diào)度,所以它適用于運(yùn)行大量進(jìn)程的系統(tǒng),像是桌面環(huán)境、多媒體應(yīng)用等。
第三種 DeadLine 最后期限調(diào)度算法。使用了四個(gè)隊(duì)列。其中兩個(gè)排序隊(duì)列分別包含讀和寫請(qǐng)求,其中的請(qǐng)求是根據(jù)起始扇區(qū)排序的。另外兩個(gè)最后期限隊(duì)列包含了相同的讀和寫請(qǐng)求,但是這是根據(jù)它們的最后期限排隊(duì)的。可以提高機(jī)械磁盤的吞吐量,并確保達(dá)到最終期限(deadline)的請(qǐng)求被優(yōu)先處理。此算法在全局吞吐量和延遲方面做了權(quán)衡,犧牲了一定的全局吞吐量來避免饑餓請(qǐng)求的可能。當(dāng)系統(tǒng)存在大量順序I/O請(qǐng)求的時(shí)候,此算法可能導(dǎo)致I/O請(qǐng)求無法被很好的排序,引發(fā)頻繁尋道。
第四種 Anticipatory 預(yù)期算法。借用了“最后期限調(diào)度算法”的基本機(jī)制:兩個(gè)最后期限隊(duì)列和兩個(gè)排序隊(duì)列,I/O調(diào)度程序在讀和寫請(qǐng)求之間交互掃描排序隊(duì)列,不過更傾向于讀請(qǐng)求。掃描基本是連續(xù)的,除非有某個(gè)請(qǐng)求超時(shí)。為每個(gè)讀IO都設(shè)置了大約7ms的等待時(shí)間窗口。如果在這7ms內(nèi)OS收到了相鄰位置的讀IO請(qǐng)求,就可以立即滿足。為了滿足隨機(jī)IO和順序IO混合的場(chǎng)景,此算法適合寫入較多的環(huán)境,不適合MySQL等隨機(jī)讀取較多的數(shù)據(jù)庫(kù)環(huán)境。
磁盤IO檢測(cè)
在磁盤測(cè)試中最關(guān)心的幾個(gè)指標(biāo)分別為:
- iops(每秒執(zhí)行的IO次數(shù))、bw(帶寬,每秒的吞吐量)、lat(每次IO操作的延遲)
- 當(dāng)每次IO操作的block較小時(shí),如512bytes/4k/8k等,測(cè)試的主要是iops
- 當(dāng)每次IO操作的block較大時(shí),如256k/512k/1M等,測(cè)試的主要是bw
使用fio工具來進(jìn)行磁盤io檢測(cè)
1. FIO 簡(jiǎn)介
FIO 是一款 用于對(duì)磁盤進(jìn)行性能測(cè)試的工具。可以測(cè)試IOPS,吞吐量,IO延遲等主要性能指標(biāo)。而且支持多種IO引擎。
2. FIO 下載
下載地址:http://brick.kernel.dk/snaps/
打開以上網(wǎng)址,選擇自己需要的版本并下載。比如:
- wget http://brick.kernel.dk/snaps/fio-3.5.tar.gz
3. 解壓并安裝
- # tar -xzvf ./fio-3.5.tar.gz
- .... 省略輸出
- # cd fio-3.5
- # make && make install
- .... 省略輸出# which fio
- /usr/local/bin/fio
4. 使用說明
- filename=/dev/sdb1 測(cè)試文件名稱,通常選擇需要測(cè)試的盤的data目錄。
- direct=1 測(cè)試過程繞過機(jī)器自帶的buffer。使測(cè)試結(jié)果更真實(shí)。
- rw=randwrite 測(cè)試隨機(jī)寫的I/O
- rw=randrw 測(cè)試隨機(jī)寫和讀的I/O
- bs=16k 單次io的塊文件大小為16k
- bsrange=512-2048 同上,指定數(shù)據(jù)塊的大小范圍
- size=5g 本次的測(cè)試文件大小為5g,以每次4k的io進(jìn)行測(cè)試。
- numjobs=30 本次的測(cè)試線程為30.
- runtime=1000 測(cè)試時(shí)間為1000秒,如果不寫則一直將5g文件分4k每次寫完為止。
- ioengine=psync io引擎使用pync方式
- rwmixwrite=30 在混合讀寫的模式下,寫占30%
- group_reporting 關(guān)于顯示結(jié)果的,匯總每個(gè)進(jìn)程的信息
- lockmem=1g 只使用1g內(nèi)存進(jìn)行測(cè)試。
- zero_buffers 用0初始化系統(tǒng)buffer。
- nrfiles=8 每個(gè)進(jìn)程生成文件的數(shù)量
5. 測(cè)試示例
- 混合測(cè)試:
- fio -filename=/tmp/test -direct=1 -iodepth 1 -thread -rw=randrw -rwmixread=70 -ioengine=psync -bs=512b -size=200m -numjobs=10 -runtime=60 -group_reporting -name=mytest
- 順序讀:
- fio -filename=/dev/test -direct=1 -iodepth 1 -thread -rw=read -ioengine=psync -bs=16k -size=2G -numjobs=10 -runtime=60 -group_reporting -name=mytest
- 隨機(jī)寫:
- fio -filename=/dev/test -direct=1 -iodepth 1 -thread -rw=randwrite -ioengine=psync -bs=16k -size=2G -numjobs=10 -runtime=60 -group_reporting -name=mytest
- 順序?qū)懀?nbsp;
- fio -filename=/dev/test -direct=1 -iodepth 1 -thread -rw=write -ioengine=psync -bs=16k -size=2G -numjobs=10 -runtime=60 -group_reporting -name=mytest
6. IO讀寫測(cè)試參考腳本
- https://github.com/sunsharing-note/fio_test.git
本文轉(zhuǎn)載自微信公眾號(hào)「運(yùn)維開發(fā)故事」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系運(yùn)維開發(fā)故事眾號(hào)。