Linux 內(nèi)核包含4個(gè)IO調(diào)度器:
Noop IO scheduler
Anticipatory IO scheduler
Deadline IO scheduler
CFQ IO scheduler。
anticipatory, 預(yù)期的;提早發(fā)生的;期待著的
通常磁盤(pán)的讀寫(xiě)影響是由磁頭到柱面移動(dòng)造成了延遲,解決這種延遲內(nèi)核主要采用兩種策略:緩存和IO調(diào)度算法來(lái)進(jìn)行彌補(bǔ)。
本文做一簡(jiǎn)單介紹。
調(diào)度算法概念
當(dāng)向設(shè)備寫(xiě)入數(shù)據(jù)塊或是從設(shè)備讀出數(shù)據(jù)塊時(shí),請(qǐng)求都被安置在一個(gè)隊(duì)列中等待完成。
每個(gè)塊設(shè)備都有它自己的隊(duì)列。
I/O調(diào)度程序負(fù)責(zé)維護(hù)這些隊(duì)列的順序,以更有效地利用介質(zhì).I/O調(diào)度程序?qū)o(wú)序的I/O操作變?yōu)橛行虻腎/O操作。
內(nèi)核必須首先確定隊(duì)列中一共有多少個(gè)請(qǐng)求,然后才開(kāi)始進(jìn)行調(diào)度。
IO 調(diào)度器(IO Scheduler)
IO調(diào)度器(IO Scheduler)是操作系統(tǒng)用來(lái)決定塊設(shè)備上IO操作提交順序的方法。存在的目的有兩個(gè),一是提高IO吞吐量,二是降低IO響應(yīng)時(shí)間。然而IO吞吐量和IO響應(yīng)時(shí)間往往是矛盾的,為了盡量平衡這兩者,IO調(diào)度器提供了多種調(diào)度算法來(lái)適應(yīng)不同的IO請(qǐng)求場(chǎng)景。其中,對(duì)數(shù)據(jù)庫(kù)這種隨機(jī)讀寫(xiě)的場(chǎng)景最有利的算法是DEANLINE。
IO調(diào)度器在內(nèi)核棧中所處位置如下:
塊設(shè)備最悲劇的地方就是磁盤(pán)轉(zhuǎn)動(dòng),這個(gè)過(guò)程會(huì)很耗時(shí)間。
每個(gè)塊設(shè)備或者塊設(shè)備的分區(qū),都對(duì)應(yīng)有自身的請(qǐng)求隊(duì)列(request_queue),而每個(gè)請(qǐng)求隊(duì)列都可以選擇一個(gè)I/O調(diào)度器來(lái)協(xié)調(diào)所遞交的request。I/O調(diào)度器的基本目的是將請(qǐng)求按照它們對(duì)應(yīng)在塊設(shè)備上的扇區(qū)號(hào)進(jìn)行排列,以減少磁頭的移動(dòng),提高效率。每個(gè)設(shè)備的請(qǐng)求隊(duì)列里的請(qǐng)求將按順序被響應(yīng)。實(shí)際上,除了這個(gè)隊(duì)列,每個(gè)調(diào)度器自身都維護(hù)有不同數(shù)量的隊(duì)列,用來(lái)對(duì)遞交上來(lái)的request進(jìn)行處理,而排在隊(duì)列最前面的request將適時(shí)被移動(dòng)到請(qǐng)求隊(duì)列中等待響應(yīng)。
IO scheduler 的作用主要是為了減少磁盤(pán)轉(zhuǎn)動(dòng)的需求。主要通過(guò)2種方式實(shí)現(xiàn): ? ? ? 1. 合并
? ? ? 2. 排序
每個(gè)設(shè)備都會(huì)自己對(duì)應(yīng)請(qǐng)求隊(duì)列,所有的請(qǐng)求在被處理之前都會(huì)在請(qǐng)求隊(duì)列上。在新來(lái)一個(gè)請(qǐng)求的時(shí)候如果發(fā)現(xiàn)這個(gè)請(qǐng)求和前面的某個(gè)請(qǐng)求請(qǐng)求的位置是相鄰的,那么就可以合并為一個(gè)請(qǐng)求。如果不能找到合并的,就會(huì)按照磁盤(pán)的轉(zhuǎn)動(dòng)方向進(jìn)行排序。通常IO scheduler 的作用就是為了在進(jìn)行合并和排序的同時(shí),也不會(huì)太影響單個(gè)請(qǐng)求的處理時(shí)間。
1、NOOP
FIFO
1. noop是什么? noop是一種輸入輸出調(diào)度算法。NOOP, No Operation. 什么都不做,請(qǐng)求來(lái)一個(gè)處理一個(gè)。這種方式實(shí)施起來(lái)簡(jiǎn)單,也更有效。問(wèn)題就是disk seek 太多,對(duì)于傳統(tǒng)磁盤(pán),這是不能接受的。但對(duì)于SSD 磁盤(pán)就可以,因?yàn)镾SD 磁盤(pán)不需要轉(zhuǎn)動(dòng)。
2. noop的別稱(chēng) 又稱(chēng)為電梯調(diào)度算法。
3. noop原理是怎樣的?
將輸入輸出請(qǐng)求放到一個(gè)FIFO隊(duì)列中,然后按次序執(zhí)行隊(duì)列中的輸入輸出請(qǐng)求:當(dāng)來(lái)一個(gè)新請(qǐng)求時(shí): 1. 如果能合并就合并; 2. 如果不能合并,就會(huì)嘗試排序。如果隊(duì)列上的請(qǐng)求都已經(jīng)很老了,這個(gè)新的請(qǐng)求就不能插隊(duì),只能放到最后面。否則就插到合適的位置; 3. 如果既不能合并,又沒(méi)有合適的位置插入,就放到請(qǐng)求隊(duì)列的最后; 4. 適用場(chǎng)景
4.1 在不希望修改輸入輸出請(qǐng)求先后順序的場(chǎng)景下;
4.2 在輸入輸出之下具有更加智能調(diào)度算法的設(shè)備,如NAS存儲(chǔ)設(shè)備;
4.3 上層應(yīng)用程序已經(jīng)精心優(yōu)化過(guò)的輸入輸出請(qǐng)求;
4.4 非旋轉(zhuǎn)磁頭式的磁盤(pán)設(shè)備,如SSD磁盤(pán)
2、CFQ(Completely Fair Queuing, 完全公平排隊(duì))
CFQ(Completely Fair Queuing)算法,顧名思義,絕對(duì)公平算法。它試圖為競(jìng)爭(zhēng)塊設(shè)備使用權(quán)的所有進(jìn)程分配一個(gè)請(qǐng)求隊(duì)列和一個(gè)時(shí)間片,在調(diào)度器分配給進(jìn)程的時(shí)間片內(nèi),進(jìn)程可以將其讀寫(xiě)請(qǐng)求發(fā)送給底層塊設(shè)備,當(dāng)進(jìn)程的時(shí)間片消耗完,進(jìn)程的請(qǐng)求隊(duì)列將被掛起,等待調(diào)度。
每個(gè)進(jìn)程的時(shí)間片和每個(gè)進(jìn)程的隊(duì)列長(zhǎng)度取決于進(jìn)程的IO優(yōu)先級(jí),每個(gè)進(jìn)程都會(huì)有一個(gè)IO優(yōu)先級(jí),CFQ調(diào)度器將會(huì)將其作為考慮的因素之一,來(lái)確定該進(jìn)程的請(qǐng)求隊(duì)列何時(shí)可以獲取塊設(shè)備的使用權(quán)。
IO優(yōu)先級(jí)從高到低可以分為三大類(lèi): RT(real time) BE(best try)
IDLE(idle)
其中RT和BE又可以再劃分為8個(gè)子優(yōu)先級(jí)??梢酝ㄟ^(guò)ionice 去查看和修改。優(yōu)先級(jí)越高,被處理得越早,用于這個(gè)進(jìn)程的時(shí)間片也越多,一次處理的請(qǐng)求數(shù)也會(huì)越多。
實(shí)際上,我們已經(jīng)知道CFQ調(diào)度器的公平是針對(duì)于進(jìn)程而言的,而只有同步請(qǐng)求(read或syn write)才是針對(duì)進(jìn)程而存在的,他們會(huì)放入進(jìn)程自身的請(qǐng)求隊(duì)列,而所有同優(yōu)先級(jí)的異步請(qǐng)求,無(wú)論來(lái)自于哪個(gè)進(jìn)程,都會(huì)被放入公共的隊(duì)列,異步請(qǐng)求的隊(duì)列總共有8(RT)+8(BE)+1(IDLE)=17個(gè)。
從Linux 2.6.18起,CFQ作為默認(rèn)的IO調(diào)度算法。對(duì)于通用的服務(wù)器來(lái)說(shuō),CFQ是較好的選擇。具體使用哪種調(diào)度算法還是要根據(jù)具體的業(yè)務(wù)場(chǎng)景去做足benchmark來(lái)選擇,不能僅靠別人的文字來(lái)決定。
3、DEADLINE
DEADLINE在CFQ的基礎(chǔ)上,解決了IO請(qǐng)求餓死的極端情況。
除了CFQ本身具有的IO排序隊(duì)列之外,DEADLINE額外分別為讀IO和寫(xiě)IO提供了FIFO隊(duì)列。
讀FIFO隊(duì)列的最大等待時(shí)間為500ms,寫(xiě)FIFO隊(duì)列的最大等待時(shí)間為5s(當(dāng)然這些參數(shù)都是可以手動(dòng)設(shè)置的)。
FIFO隊(duì)列內(nèi)的IO請(qǐng)求優(yōu)先級(jí)要比CFQ隊(duì)列中的高,而讀FIFO隊(duì)列的優(yōu)先級(jí)又比寫(xiě)FIFO隊(duì)列的優(yōu)先級(jí)高。優(yōu)先級(jí)可以表示如下:
FIFO(Read) > FIFO(Write) > CFQ
deadline 算法保證對(duì)于既定的 IO 請(qǐng)求以最小的延遲時(shí)間,從這一點(diǎn)理解,對(duì)于 DSS 應(yīng)用應(yīng)該會(huì)是很適合的。
deadline 實(shí)際上是對(duì)Elevator 的一種改進(jìn):?
1. 避免有些請(qǐng)求太長(zhǎng)時(shí)間不能被處理。
2. 區(qū)分對(duì)待讀操作和寫(xiě)操作。
deadline IO 維護(hù)3個(gè)隊(duì)列。第一個(gè)隊(duì)列和Elevator 一樣, 盡量按照物理位置排序。第二個(gè)隊(duì)列和第三個(gè)隊(duì)列都是按照時(shí)間排序,不同的是一個(gè)是讀操作一個(gè)是寫(xiě)操作。
deadline IO 之所以區(qū)分讀和寫(xiě)是因?yàn)樵O(shè)計(jì)者認(rèn)為如果應(yīng)用程序發(fā)了一個(gè)讀請(qǐng)求,一般就會(huì)阻塞到那里,一直等到的結(jié)果返回。而寫(xiě)請(qǐng)求則不是通常是應(yīng)用請(qǐng)求寫(xiě)到內(nèi)存即可,由后臺(tái)進(jìn)程再寫(xiě)回磁盤(pán)。應(yīng)用程序一般不等寫(xiě)完成就繼續(xù)往下走。所以讀請(qǐng)求應(yīng)該比寫(xiě)請(qǐng)求有更高的優(yōu)先級(jí)。
在這種設(shè)計(jì)下,每個(gè)新增請(qǐng)求都會(huì)先放到第一個(gè)隊(duì)列,算法和Elevator的方式一樣,同時(shí)也會(huì)增加到讀或者寫(xiě)隊(duì)列的尾端。這樣首先處理一些第一隊(duì)列的請(qǐng)求,同時(shí)檢測(cè)第二/三隊(duì)列前幾個(gè)請(qǐng)求是否等了太長(zhǎng)時(shí)間,如果已經(jīng)超過(guò)一個(gè)閥值,就會(huì)去處理一下。這個(gè)閥值對(duì)于讀請(qǐng)求時(shí) 5ms, 對(duì)于寫(xiě)請(qǐng)求時(shí)5s。
個(gè)人認(rèn)為對(duì)于記錄數(shù)據(jù)庫(kù)變更日志的分區(qū),例如oracle 的online log, mysql 的binlog 等等,最好不要使用這種分區(qū)。因?yàn)檫@類(lèi)寫(xiě)請(qǐng)求通常是調(diào)用fsync 的。如果寫(xiě)完不成,也會(huì)很影響應(yīng)用性能的。
4、ANTICIPATORY
CFQ和DEADLINE考慮的焦點(diǎn)在于滿足零散IO請(qǐng)求上。對(duì)于連續(xù)的IO請(qǐng)求,比如順序讀,并沒(méi)有做優(yōu)化。
為了滿足隨機(jī)IO和順序IO混合的場(chǎng)景,Linux還支持ANTICIPATORY調(diào)度算法。ANTICIPATORY的在DEADLINE的基礎(chǔ)上,為每個(gè)讀IO都設(shè)置了6ms的等待時(shí)間窗口。如果在這6ms內(nèi)OS收到了相鄰位置的讀IO請(qǐng)求,就可以立即滿足。
小結(jié)
IO調(diào)度器算法的選擇,既取決于硬件特征,也取決于應(yīng)用場(chǎng)景。
在傳統(tǒng)的SAS盤(pán)上,CFQ、DEADLINE、ANTICIPATORY都是不錯(cuò)的選擇;對(duì)于專(zhuān)屬的數(shù)據(jù)庫(kù)服務(wù)器,DEADLINE的吞吐量和響應(yīng)時(shí)間都表現(xiàn)良好。
然而在新興的固態(tài)硬盤(pán)比如SSD、Fusion IO上,最簡(jiǎn)單的NOOP反而可能是最好的算法,因?yàn)槠渌齻€(gè)算法的優(yōu)化是基于縮短尋道時(shí)間的,而固態(tài)硬盤(pán)沒(méi)有所謂的尋道時(shí)間且IO響應(yīng)時(shí)間非常短。
編輯:黃飛
?
評(píng)論