本發(fā)明屬于固態(tài)盤存儲(chǔ)技術(shù)領(lǐng)域,更具體地,涉及一種基于固態(tài)盤不同讀寫特性的I/O調(diào)度方法。
背景技術(shù):
固態(tài)盤(Solid state disk,簡稱SSD)是一種利用NAND閃存芯片作為數(shù)據(jù)永久存儲(chǔ)的硬盤,隨著NAND閃存芯片的生產(chǎn)成本下降,SSD的價(jià)格也越來越被人們所接受,SSD在數(shù)據(jù)中心、個(gè)人電腦、各種類型的移動(dòng)設(shè)備上的使用越來越廣泛。但是,由于長期以來構(gòu)建存儲(chǔ)系統(tǒng)的設(shè)備都是硬盤驅(qū)動(dòng)器(Hard disk drive,簡稱HDD),現(xiàn)有的系統(tǒng)軟件大多數(shù)是面向HDD進(jìn)行設(shè)計(jì)和優(yōu)化的,直接使用SSD替換掉HDD并不能最大限度地發(fā)揮SSD的高性能。因此,針對SSD進(jìn)行系統(tǒng)軟件優(yōu)化具有十分重要的意義。
HDD是一種機(jī)械旋轉(zhuǎn)式的硬盤,它的讀寫操作主要有以下幾個(gè)步驟:
1、尋道:磁頭傳動(dòng)裝置將所有的磁頭移動(dòng)到待訪問的柱面,并獲取當(dāng)前需要使用的磁頭號;2、旋轉(zhuǎn)等待:定位到相應(yīng)的盤面和磁道后,盤面就會(huì)旋轉(zhuǎn),在旋轉(zhuǎn)的過程中,磁頭會(huì)讀取其正下方的扇區(qū)中的扇區(qū)頭標(biāo)中的信息,與需要讀取/寫入的扇區(qū)號進(jìn)行比對,如果不匹配則盤面會(huì)繼續(xù)旋轉(zhuǎn),如果匹配則從此扇區(qū)開始讀/寫數(shù)據(jù);3、完成數(shù)據(jù)讀寫。HDD讀寫操作很大一部分時(shí)間消耗在尋道和旋轉(zhuǎn)等待上,而Linux內(nèi)核中的IO調(diào)度算法所做的優(yōu)化主要也是為了降低尋道和旋轉(zhuǎn)等待的時(shí)間消耗。
在Linux系統(tǒng)中,現(xiàn)有的IO調(diào)度算法主要是Noop算法,CFQ算法Deadline算法和Anticipatory算法。其中CFQ、Deadline和Anticipatory算法針對HDD尋道時(shí)間長,采取了合并連續(xù)的讀寫請求,這樣就可以在尋道 結(jié)束后進(jìn)行連續(xù)的讀寫。Noop算法對讀寫請求不予合并,只將新的請求插入隊(duì)尾。
然而,上述IO調(diào)度算法存在以下方面的問題:1、在SSD中,順序的寫和隨機(jī)的寫性能基本相同,所以對寫請求進(jìn)行合并并不能提高SSD的速率,反而會(huì)影響系統(tǒng)的性能;2、在SSD中,在不超過聚簇頁大小的前提下合并讀請求才會(huì)提高讀效率,讀請求大小超過聚簇頁大小后并不會(huì)提高讀效率。
技術(shù)實(shí)現(xiàn)要素:
針對現(xiàn)有技術(shù)的以上缺陷或改進(jìn)需求,本發(fā)明提供了一種基于固態(tài)盤不同讀寫特性的I/O調(diào)度方法,其目的在于,解決現(xiàn)有IO調(diào)度方法中存在的連續(xù)讀請求合并后過大或不能被合并、以及寫請求存在不必要的合并的技術(shù)問題。
為實(shí)現(xiàn)上述目的,按照本發(fā)明的一個(gè)方面,提供了一種基于固態(tài)盤讀寫特性的IO調(diào)度方法,包括以下步驟:
(1)接收來自上層應(yīng)用并經(jīng)過文件系統(tǒng)處理后的bio請求,并判斷該bio請求的類型是讀請求還是寫請求,如果是讀請求則轉(zhuǎn)入步驟(2),如果是寫請求則轉(zhuǎn)入步驟(3);
(2)判斷該讀請求是否能夠與其鄰近的讀請求進(jìn)行合并,若不能合并,則直接轉(zhuǎn)入步驟(4);若可以合并且合并后的大小不超過聚簇頁的大小,則將其與鄰近的讀請求進(jìn)行合并,合并后的讀請求仍然可以與其鄰近的讀請求進(jìn)行合并,并且應(yīng)當(dāng)確保合并后的大小不超過聚簇頁的大小。將最終合并后的讀請求放入讀隊(duì)列和讀紅黑樹中,以供系統(tǒng)讀取數(shù)據(jù)。然后轉(zhuǎn)入步驟(4)。
(3)判斷該寫請求是否能夠與緩存中的寫請求進(jìn)行合并,如果可以則進(jìn)行合并,并將合并后的寫請求插入調(diào)度器隊(duì)列末端,并轉(zhuǎn)入步驟(4);否則判斷其能否與哈希表中的寫請求進(jìn)行合并,如果可以則進(jìn)行合并,并 將將合并后的寫請求插入調(diào)度器隊(duì)列末端,并轉(zhuǎn)入步驟(4);
(4)將調(diào)度器隊(duì)列中的請求分發(fā)到設(shè)備驅(qū)動(dòng)器的請求隊(duì)列中。
優(yōu)選地,步驟(2)包括以下子步驟:
(2.1)針對該讀請求,判斷是否存在上次合并的讀請求,若存在,則跳轉(zhuǎn)到步驟(2.2);否則跳轉(zhuǎn)到步驟(2.3);
(2.2)判斷該讀請求與上次合并后的讀請求能否進(jìn)行合并。如果不能合并,則跳轉(zhuǎn)到步驟(2.3),如果能前向合并,則跳轉(zhuǎn)到步驟(2.4),如果能后向合并,則跳轉(zhuǎn)到步驟(2.5);
(2.3)判斷該讀請求能否與哈希鏈表中的請求進(jìn)行后向合并,如果能則跳轉(zhuǎn)到步驟(2.5);否則跳轉(zhuǎn)到步驟(2.6);
(2.4)完成可前向合并的讀請求Rfrq與該讀請求的合并,并判斷前向合并之后的讀請求Rfrq能否繼續(xù)與調(diào)度器中讀紅黑樹中按照請求的起始訪問地址排序的Rfrq的前一個(gè)讀請求Rprev繼續(xù)進(jìn)行前向合并。能則跳轉(zhuǎn)到步驟(2.7),否則跳轉(zhuǎn)到步驟(2.8);
(2.5)完成可后向合并的請求Rbrq與該讀請求的合并,并判斷后向合并之后的請求Rbrq能否繼續(xù)與調(diào)度器中讀紅黑樹中按照請求的起始訪問地址排序的Rbrq的后一個(gè)請求Rnext繼續(xù)進(jìn)行后向合并。能則跳轉(zhuǎn)到步驟(2.9),否則跳轉(zhuǎn)到步驟(2.10);
(2.6)判斷該讀請求能否與調(diào)度器中讀紅黑樹中的請求進(jìn)行前向合并,如果能則跳轉(zhuǎn)到步驟(2.4),否則跳轉(zhuǎn)到步驟(2.11);
(2.7)完成讀請求Rfrq與讀請求Rperv的前向合并,刪除調(diào)度器讀隊(duì)列、讀紅黑樹以及通用塊層哈希鏈表中的Rfrq請求;同時(shí)根據(jù)被合并的讀請求的大小改變Rprev在哈希鏈表中的位置;并將合并后的最晚服務(wù)時(shí)間設(shè)置為Rfrq和Rprev的最晚服務(wù)時(shí)間中較小的一個(gè);最后將上次合并的讀請求標(biāo)記為Rfrq。
(2.8)將上次合并的讀請求設(shè)置為Rfrq,并在讀紅黑樹中更新Rfrq的 起始地址;
(2.9)完成請求Rbrq與請求Rnext的后向合并,在調(diào)度器的讀隊(duì)列、讀紅黑樹以及通用塊層的哈希鏈表中刪除Rnext請求,更新Rbrq請求在哈希鏈表中的位置,將Rbrq和Rnext中較早的服務(wù)時(shí)間設(shè)置為合并后的讀請求的服務(wù)時(shí)間,將Rbrq標(biāo)記為上次合并的讀請求,并跳轉(zhuǎn)到步驟(2.14);
(2.10)將Rbrq標(biāo)記為上次合并的讀請求,并更新Rbrq請求在哈希鏈表中的位置,結(jié)束轉(zhuǎn)換;
(2.11)為該bio請求分配一個(gè)請求Rnrq,并用該bio請求初始化Rnrq,并判斷Rnrq是否具有合并屬性,如果有則跳轉(zhuǎn)到步驟(2.12);否則跳轉(zhuǎn)到步驟(2.13);
(2.12)將Rnrq請求加入哈希鏈表,并判斷是否存在上次合并的讀請求。如果存在,則直接跳轉(zhuǎn)到步驟(2.13);否則先將Rnrq標(biāo)記為上次合并的讀請求,并跳轉(zhuǎn)到步驟(2.13);
(2.13)將Rnrq請求加入調(diào)度器中讀隊(duì)列末尾以及讀紅黑樹中。
優(yōu)選地,步驟(3)包括以下子步驟:
(3.1)針對該寫請求,判斷是否存在上次合并的寫請求,如果存在,跳轉(zhuǎn)到步驟(3.2);否則跳轉(zhuǎn)到步驟(3.3);
(3.2)判斷該bio請求是否能夠與上次合并的寫請求進(jìn)行合并,如果能夠前向合并,跳轉(zhuǎn)到步驟(3.4);如果能夠進(jìn)行后向合并,跳轉(zhuǎn)到步驟(3.5);如果不能合并跳轉(zhuǎn)到步驟(3.3);
(3.3)判斷該bio請求能否與哈希鏈表中的請求進(jìn)行后向合并,如果能則跳轉(zhuǎn)到步驟(3.5);否則跳轉(zhuǎn)到步驟(3.6);
(3.4)將該bio請求與上次合并的寫請求進(jìn)行前向合并,并判斷合并之后還能否繼續(xù)與調(diào)度器中寫鏈表中其前一個(gè)請求Wprev繼續(xù)進(jìn)行合并。如果能與Wprev合并,則跳轉(zhuǎn)到步驟(3.7),否則跳轉(zhuǎn)到步驟(3.8);
(3.5)完成bio請求與可后向合并的請求Wbrq的后向合并,并判斷合并 之后的Wbrq能否與調(diào)度器寫鏈表中Wbrq的下一個(gè)請求Wnext繼續(xù)進(jìn)行合并。能則跳轉(zhuǎn)到步驟(3.9);否則跳轉(zhuǎn)到步驟(3.10);
(3.6)為該bio請求分配一個(gè)新請求Wnrq,并用該bio請求初始化Wnrq。然后判斷Wnrq是否具有合并屬性。有則跳轉(zhuǎn)到步驟(3.11);否則跳轉(zhuǎn)到步驟(3.12);
(3.7)完成Wfrq與Wprev的合并,并在調(diào)度器的寫鏈表、哈希鏈表中刪除Wfrq,接著需要調(diào)整Wprev在哈希鏈表中的位置,最后將Wprev標(biāo)記為上一次合并的寫請求,已經(jīng)將該bio請求轉(zhuǎn)化為了寫請求,結(jié)束本次轉(zhuǎn)換;
(3.8)將Wfrq標(biāo)記為上次合并的寫請求,已經(jīng)將該bio請求轉(zhuǎn)化為了寫請求,結(jié)束本次轉(zhuǎn)換;
(3.9)完成Wbrq與Wnext的合并,并在調(diào)度器的寫鏈表、哈希鏈表刪除Wnext,接著需要調(diào)整Wbrq在哈希鏈表中的位置,最后將Wbrq標(biāo)記為上次合并的寫請求,已經(jīng)將該bio請求轉(zhuǎn)化為了寫請求,結(jié)束本次轉(zhuǎn)換;
(3.10)調(diào)整Wbrq在哈希鏈表中的位置,并將Wbrq標(biāo)記為上次合并的寫請求,已經(jīng)將該bio請求轉(zhuǎn)化為了寫請求,結(jié)束本次轉(zhuǎn)換;
(3.11)將Wnrq加入哈希鏈表中,并判斷上次合并的寫請求是否存在。若不存在,則將Wnrq標(biāo)記為上次合并的寫請求,并跳轉(zhuǎn)到步驟(3.12);否則,直接跳到步驟(3.12);
(3.12)將Wnrq加入調(diào)度器寫鏈表的尾部,從而將該bio請求轉(zhuǎn)化為了寫請求。
優(yōu)選地,步驟(4)包括以下子步驟:
(4.1)判斷調(diào)度器隊(duì)列中目前分發(fā)請求所處的階段是處于讀批處理階段還是寫批處理階段,如果處于讀批處理階段,則跳轉(zhuǎn)到步驟(4.2);如果處于寫批處理階段,則跳轉(zhuǎn)到步驟(4.3),
(4.2)判斷讀批處理階段分發(fā)的請求總數(shù)是否已超過閾值。若已超過閾值,則跳轉(zhuǎn)到步驟(4.4),否則跳轉(zhuǎn)到步驟(4.5);
(4.3)判斷寫批處理階段分發(fā)的請求總數(shù)是否已達(dá)上限,若已達(dá)上限,跳轉(zhuǎn)到步驟(4.4),否則跳轉(zhuǎn)到步驟(4.6);
(4.4)創(chuàng)建一個(gè)批處理階段,并確定調(diào)度器隊(duì)列中是否存在對應(yīng)的讀請求嗎,若存在,跳轉(zhuǎn)到步驟(4.9);否則跳轉(zhuǎn)到步驟(4.10);
(4.5)將調(diào)度器中待分發(fā)的請求Drq設(shè)置為next_rq[read],并跳轉(zhuǎn)到步驟(4.7);
(4.6)將調(diào)度器中待分發(fā)的請求Drq設(shè)置為next_rq[write],并跳轉(zhuǎn)到步驟(4.8);
(4.7)將Drq分發(fā)到設(shè)備驅(qū)動(dòng)層的請求隊(duì)列中,從調(diào)度器的讀鏈表和讀紅黑樹中刪除該Drq,并將next_rq[read]設(shè)置為Drq在調(diào)度器的讀紅黑樹中的下一個(gè)請求,最后對該操作進(jìn)行計(jì)數(shù),結(jié)束本次請求分發(fā)過程;
(4.8)將Drq分發(fā)到設(shè)備驅(qū)動(dòng)層的請求隊(duì)列中,從調(diào)度器的寫鏈表中刪除Drq,設(shè)置next_rq[write]為Drq在調(diào)度器寫鏈表中的下一個(gè)請求,最后對該操作進(jìn)行計(jì)數(shù),結(jié)束本次請求分發(fā)過程;
(4.9)判斷調(diào)度器的寫鏈表中是否存在請求,如果不存在,則跳轉(zhuǎn)到步驟(4.11);如果存在,則繼續(xù)判斷是否存在超時(shí)的寫請求或者寫請求被饑餓的次數(shù)已達(dá)上限,如果判定結(jié)果為真,則跳轉(zhuǎn)到步驟(4.12);否則跳轉(zhuǎn)到步驟(4.11);
(4.10)判斷調(diào)度器的寫鏈表中是否存在請求,若存在,則跳轉(zhuǎn)到步驟(4.12);否則調(diào)度器中不存在待分發(fā)的請求,結(jié)束本次請求分發(fā)過程;
(4.11)判斷next_rq[read]是否存在。若存在,跳轉(zhuǎn)到步驟(4.13);否則跳轉(zhuǎn)到步驟(4.14);
(4.12)將寫請求被饑餓的次數(shù)置0。然后判斷是否存在超時(shí)的寫請求或者next_rq[write]是否為空。如果判定結(jié)果為真,跳轉(zhuǎn)到步驟(4.15);否者跳轉(zhuǎn)到步驟(4.16);
(4.13)將待分發(fā)請求Drq設(shè)置為next_rq[read],設(shè)置batching=0,開始 創(chuàng)建一個(gè)讀批處理階段,跳轉(zhuǎn)到步驟(4.7);
(4.14)將待分發(fā)請求Drq設(shè)置為調(diào)度器讀鏈表中的第一個(gè)請求,設(shè)置batching=0,開始創(chuàng)建一個(gè)讀批處理階段,跳轉(zhuǎn)到步驟(4.7);
(4.15)將待分發(fā)請求Drq設(shè)置為調(diào)度器寫鏈表中的第一個(gè)請求,設(shè)置batching=0,開始創(chuàng)建一個(gè)寫批處理階段,跳轉(zhuǎn)到步驟(4.8);
(4.16)將待分發(fā)請求Drq設(shè)置為next_rq[write],設(shè)置batching=0,開始創(chuàng)建一個(gè)寫批處理階段,跳轉(zhuǎn)到步驟(4.8)。
總體而言,通過本發(fā)明所構(gòu)思的以上技術(shù)方案與現(xiàn)有技術(shù)相比,能夠取得下列有益效果:
(1)本發(fā)明能夠解決現(xiàn)有方法中存在的連續(xù)的讀請求合并后過大或不合并的問題:由于采用了步驟(2.2)步驟(2.4)步驟(2.5)和步驟(2.7),因此可以解決現(xiàn)有Noop算法中對讀請求不合并,以及CFQ、Deadline、Anticipatory算法中對讀請求合并過大的問題。
(2)本發(fā)明能夠解決現(xiàn)有方法中存在的對連續(xù)的寫請求不必要的合并的問題:由于采用了步驟(3.4)步驟(3.5)步驟(3.7)和步驟(3.9),因此可以解決現(xiàn)有IO調(diào)度算法中對連續(xù)的寫請求進(jìn)行合并的問題。
(3)本發(fā)明充分利用固態(tài)盤在不同訪問模式下讀寫性能:考慮到SSD中順序模式下讀請求的性能遠(yuǎn)遠(yuǎn)高于隨機(jī)模式下讀請求的性能,對讀請求不僅按照請求到來的時(shí)間在鏈表中排隊(duì),還按照讀請求的起始訪問地址在紅黑樹中排序,以構(gòu)造讀請求的順序性,對排序之后的讀請求進(jìn)行前向合并和后向合并;考慮到順序模式下寫請求的性能和隨機(jī)模式下寫請求的性能基本相同,寫請求只需要按照請求到來的時(shí)間在鏈表中排隊(duì),不需要在紅黑樹中排序構(gòu)造寫請求的順序性,對寫請求也只進(jìn)行后向合并。
(4)本發(fā)明充分利用固態(tài)盤豐富的并行性:合并讀寫請求時(shí),考慮到SSD中最小的讀寫操作單元是頁,而為了利用SSD內(nèi)部的并行性,讀寫操作有可能是以聚簇頁為最小操作單元,通過黑盒測試的方式獲取聚簇頁的 大小,并合并請求時(shí),保證合并之后的請求不超過聚簇頁的大小。當(dāng)請求大小達(dá)到聚簇頁大小時(shí),繼續(xù)合并請求,不會(huì)帶來性能的提升,反而會(huì)造成SSD設(shè)備空閑等待,降低性能。
附圖說明
圖1是Linux操作系統(tǒng)固態(tài)盤訪問的I/O路徑。
圖2是本發(fā)明基于固態(tài)盤不同讀寫特性的I/O調(diào)度方法的流程圖。
圖3是本調(diào)度方法中讀bio請求到請求的轉(zhuǎn)變。
圖4是本調(diào)度方法中寫bio請求到請求的轉(zhuǎn)變。
圖5是本調(diào)度方法中分發(fā)請求到設(shè)備驅(qū)動(dòng)層。
具體實(shí)施方式
為了使本發(fā)明的目的、技術(shù)方案及優(yōu)點(diǎn)更加清楚明白,以下結(jié)合附圖及實(shí)施例,對本發(fā)明進(jìn)行進(jìn)一步詳細(xì)說明。應(yīng)當(dāng)理解,此處所描述的具體實(shí)施例僅僅用以解釋本發(fā)明,并不用于限定本發(fā)明。此外,下面所描述的本發(fā)明各個(gè)實(shí)施方式中所涉及到的技術(shù)特征只要彼此之間未構(gòu)成沖突就可以相互組合。
如圖1所示,上層應(yīng)用通過系統(tǒng)調(diào)用讀寫模塊發(fā)起的IO請求,首先會(huì)經(jīng)過虛擬文件系統(tǒng)層(Virtual file system,簡稱VFS),并到達(dá)真實(shí)需要訪問的文件系統(tǒng)層,接著會(huì)經(jīng)過通用塊層和IO調(diào)度層,最后達(dá)到SCSI設(shè)備驅(qū)動(dòng)層,才能向底層磁盤請求數(shù)據(jù)。本發(fā)明基于固態(tài)盤不同讀寫特性的I/O調(diào)度方法工作在I/O調(diào)度層。具體完成如下兩個(gè)功能:
1、配合通用塊層將文件系統(tǒng)層下發(fā)的bio請求按照一定的策略封裝成請求,并加入調(diào)度層的請求隊(duì)列;
2、將IO調(diào)度層請求隊(duì)列中的請求按照一定的策略分發(fā)到下層的SCSI設(shè)備驅(qū)動(dòng)層的請求隊(duì)列中。使得到達(dá)固態(tài)盤的讀請求呈現(xiàn)更強(qiáng)的順序性,能夠合理適度地利用固態(tài)盤內(nèi)部的并行性以及避免讀寫請求之間的相互干擾,從而能夠提高整個(gè)固態(tài)盤系統(tǒng)的I/O性能。
本發(fā)明的整體思路在于,其充分考慮了固態(tài)盤中讀寫請求的相互干擾,將讀寫請求分離,批量處理讀請求和寫請求;考慮到順序模式下讀請求的性能遠(yuǎn)遠(yuǎn)高于隨機(jī)模式下讀請求的性能,對讀請求不僅按照請求到來的時(shí)間在鏈表中排隊(duì),還按照讀請求的起始訪問地址在紅黑樹中排序,以構(gòu)造讀請求的順序性,對排序之后的讀請求進(jìn)行前向合并和后向合并;考慮到順序模式下寫請求的性能和隨機(jī)模式下寫請求的性能基本相同,寫請求只需要按照請求到來的時(shí)間在鏈表中排隊(duì),不需要在紅黑樹中排序構(gòu)造寫請求的順序性,對寫請求也只進(jìn)行后向合并;考慮到固態(tài)盤中存在著可利用的最優(yōu)并行度,當(dāng)合并請求達(dá)到聚簇頁大小時(shí),不繼續(xù)進(jìn)行合并,請求達(dá)到聚簇頁大小時(shí)已經(jīng)可以充分利用固態(tài)盤中豐富的并行性,繼續(xù)合并請求,不會(huì)帶來性能提升,反而會(huì)造成SSD設(shè)備空閑等待,降低性能。
本發(fā)明在Linux內(nèi)核的I/O調(diào)度層實(shí)現(xiàn),具體完成如下兩個(gè)功能:1、配合通用塊層將文件系統(tǒng)層下發(fā)的bio請求按照一定的策略封裝成請求,并加入調(diào)度層的請求隊(duì)列;2、將IO調(diào)度層請求隊(duì)列中的請求按照一定的策略分發(fā)到下層的SCSI設(shè)備驅(qū)動(dòng)層的請求隊(duì)列中。使得到達(dá)固態(tài)盤的讀請求呈現(xiàn)更強(qiáng)的順序性,能夠合理適度地利用固態(tài)盤內(nèi)部的并行性以及避免讀寫請求之間的相互干擾,從而能夠提高整個(gè)固態(tài)盤系統(tǒng)的I/O性能。
如圖2所示,本發(fā)明基于固態(tài)盤讀寫特性的IO調(diào)度方法包括以下步驟:
(1)接收來自上層應(yīng)用并經(jīng)過文件系統(tǒng)(在本實(shí)施方式中,該文件系統(tǒng)是ext4文件系統(tǒng))處理后的bio請求,并判斷該bio請求的類型是讀請求還是寫請求,如果是讀請求則轉(zhuǎn)入步驟(2),如果是寫請求則轉(zhuǎn)入步驟(3);
(2)判斷該讀請求是否能夠與其鄰近的讀請求進(jìn)行合并,若不能合并,則直接轉(zhuǎn)入步驟(4);若可以合并且合并后的大小不超過聚簇頁的大小,則將其與鄰近的讀請求進(jìn)行合并,合并后的讀請求仍然可以與其鄰近的讀請求進(jìn)行合并,并且應(yīng)當(dāng)確保合并后的大小不超過聚簇頁的大小。將最終合并后的讀請求放入讀隊(duì)列和讀紅黑樹中,以供系統(tǒng)讀取數(shù)據(jù)。然后轉(zhuǎn)入 步驟(4)。
(3)判斷該寫請求是否能夠與緩存中的寫請求進(jìn)行合并,如果可以則進(jìn)行合并,并將合并后的寫請求插入調(diào)度器隊(duì)列末端,并轉(zhuǎn)入步驟(4);否則判斷其能否與哈希表中的寫請求進(jìn)行合并,如果可以則進(jìn)行合并,并將將合并后的寫請求插入調(diào)度器隊(duì)列末端,并轉(zhuǎn)入步驟(4);
(4)將調(diào)度器隊(duì)列中的請求分發(fā)到設(shè)備驅(qū)動(dòng)器的請求隊(duì)列中,過程結(jié)束。
如圖3所示,本發(fā)明方法中的步驟(2)包括以下子步驟:
(2.1)針對該讀請求,判斷是否存在上次合并的讀請求,若存在,則跳轉(zhuǎn)到步驟(2.2);否則跳轉(zhuǎn)到步驟(2.3);
(2.2)判斷該讀請求與上次合并后的讀請求能否進(jìn)行合并。如果不能合并,則跳轉(zhuǎn)到步驟(2.3),如果能前向合并,則跳轉(zhuǎn)到步驟(2.4),如果能后向合并,則跳轉(zhuǎn)到步驟(2.5);具體而言,如果該讀請求與前一讀請求在地址上是連續(xù)的,而且合并后的請求大小不超過聚簇頁大小,則表示能夠前向合并,如果該讀請求的地址與后一讀請求在地址上是連續(xù)的,且合并后的讀請求大小不超過聚簇頁大小,則表示能夠后向合并;
本步驟的優(yōu)點(diǎn)在于:通過緩存上一次合并的請求,在幾乎不增加開銷的情況下可以大大縮短搜尋能與當(dāng)前讀請求合并的請求的時(shí)延,提高合并請求的效率,增加性能;另外合并之后請求的大小不超過聚簇頁大小,可以充分利用SSD內(nèi)部豐富的并行性,又不至于過度合并造成SSD設(shè)備空閑等待,可以進(jìn)一步提高性能;
(2.3)判斷該讀請求能否與哈希鏈表中的請求進(jìn)行后向合并,如果能則跳轉(zhuǎn)到步驟(2.5);否則跳轉(zhuǎn)到步驟(2.6);
(2.4)完成可前向合并的讀請求Rfrq與該讀請求的合并,并判斷前向合并之后的讀請求Rfrq能否繼續(xù)與調(diào)度器中讀紅黑樹中按照請求的起始訪問地址排序的Rfrq的前一個(gè)讀請求Rprev繼續(xù)進(jìn)行前向合并。能則跳轉(zhuǎn)到步 驟(2.7);否則跳轉(zhuǎn)到步驟(2.8);
(2.5)完成可后向合并的請求Rbrq與該讀請求的合并,并判斷后向合并之后的請求Rbrq能否繼續(xù)與調(diào)度器中讀紅黑樹中按照請求的起始訪問地址排序的Rbrq的后一個(gè)請求Rnext繼續(xù)進(jìn)行后向合并。能則跳轉(zhuǎn)到步驟(2.9),否則跳轉(zhuǎn)到步驟(2.10);
(2.6)判斷該讀請求能否與調(diào)度器中讀紅黑樹中的請求進(jìn)行前向合并,如果能則跳轉(zhuǎn)到步驟(2.4),否則跳轉(zhuǎn)到步驟(2.11);
(2.7)完成讀請求Rfrq與讀請求Rperv的前向合并,刪除調(diào)度器讀隊(duì)列、讀紅黑樹以及通用塊層哈希鏈表中的Rfrq請求;同時(shí)根據(jù)被合并的讀請求的大小改變Rprev在哈希鏈表中的位置;并將合并后的最晚服務(wù)時(shí)間設(shè)置為Rfrq和Rprev的最晚服務(wù)時(shí)間中較小的一個(gè);最后將上次合并的讀請求標(biāo)記為Rfrq,本次轉(zhuǎn)換結(jié)束。具體而言,以上步驟就是刪除被合并后讀請求的副本,以及調(diào)整合并后的讀請求的服務(wù)時(shí)間和在哈希鏈表中的位置,并記錄上次合并的讀請求的地址;
本步驟的優(yōu)點(diǎn)在于:通過前向合并,可以將小請求聚合成大請求,可以大大提高系統(tǒng)的吞吐量;
(2.8)將上次合并的讀請求設(shè)置為Rfrq,并在讀紅黑樹中更新Rfrq的起始地址;
(2.9)完成請求Rbrq與請求Rnext的后向合并,在調(diào)度器的讀隊(duì)列、讀紅黑樹以及通用塊層的哈希鏈表中刪除Rnext請求,更新Rbrq請求在哈希鏈表中的位置,將Rbrq和Rnext中較早的服務(wù)時(shí)間設(shè)置為合并后的讀請求的服務(wù)時(shí)間,將Rbrq標(biāo)記為上次合并的讀請求,并跳轉(zhuǎn)到步驟(2.14);
本步驟的優(yōu)點(diǎn)在于:通過后向合并,可以將小請求聚合成大請求,可以大大提高系統(tǒng)的吞吐量;
(2.10)將Rbrq標(biāo)記為上次合并的讀請求,并更新Rbrq請求在哈希鏈表中的位置;結(jié)束轉(zhuǎn)換;
(2.11)為該bio請求分配一個(gè)請求Rnrq,并用該bio請求初始化Rnrq,并判斷Rnrq是否具有合并屬性,如果有則跳轉(zhuǎn)到步驟(2.12);否則跳轉(zhuǎn)到步驟(2.13);
(2.12)將Rnrq請求加入哈希鏈表,并判斷是否存在上次合并的讀請求。如果存在,則直接跳轉(zhuǎn)到步驟(2.13);否則先將Rnrq標(biāo)記為上次合并的讀請求,并跳轉(zhuǎn)到步驟(2.13);
(2.13)將Rnrq請求加入調(diào)度器中讀隊(duì)列末尾以及讀紅黑樹中;
本步驟的優(yōu)點(diǎn)在于:設(shè)置讀請求的最晚需要被服務(wù)時(shí)間,優(yōu)先服務(wù)超時(shí)的讀請求,避免某一讀請求長期得不到服務(wù);另外對讀請求不僅按照請求到來的時(shí)間在鏈表中排隊(duì),還按照讀請求的起始訪問地址在紅黑樹中排序,以構(gòu)造讀請求的順序性,以充分利用順序模式下遠(yuǎn)遠(yuǎn)優(yōu)于隨機(jī)模式下的讀性能;
如圖4所示,本發(fā)明方法中的步驟(3)包括以下子步驟:
(3.1)針對該寫請求,判斷是否存在上次合并的寫請求,如果存在,跳轉(zhuǎn)到步驟(3.2);否則跳轉(zhuǎn)到步驟(3.3);
(3.2)判斷該bio請求是否能夠與上次合并的寫請求進(jìn)行合并,如果能夠前向合并,跳轉(zhuǎn)到步驟(3.4);如果能夠進(jìn)行后向合并,跳轉(zhuǎn)到步驟(3.5);如果不能合并跳轉(zhuǎn)到步驟(3.3);
本步驟的優(yōu)點(diǎn)在于:通過緩存上一次合并的請求,在幾乎不增加開銷的情況下可以大大縮短搜尋能與當(dāng)前bio請求合并的請求的時(shí)延,提高合并請求的效率,增加性能;另外合并之后請求的大小不超過聚簇頁大小,可以充分利用SSD內(nèi)部豐富的并行性,又不至于過度合并造成SSD設(shè)備空閑等待,可以進(jìn)一步提高性能;
(3.3)判斷該bio請求能否與哈希鏈表中的請求進(jìn)行后向合并,如果能則跳轉(zhuǎn)到步驟(3.5);否則跳轉(zhuǎn)到步驟(3.6);
(3.4)將該bio請求與上次合并的寫請求進(jìn)行前向合并,并判斷合并之 后還能否繼續(xù)與調(diào)度器中寫鏈表中其前一個(gè)請求Wprev繼續(xù)進(jìn)行合并。如果能與Wprev合并,則跳轉(zhuǎn)到步驟(3.7),否則跳轉(zhuǎn)到步驟(3.8);
(3.5)完成bio請求與可后向合并的請求Wbrq的后向合并,并判斷合并之后的Wbrq能否與調(diào)度器寫鏈表中Wbrq的下一個(gè)請求Wnext繼續(xù)進(jìn)行合并。能則跳轉(zhuǎn)到步驟(3.9);否則跳轉(zhuǎn)到步驟(3.10);
本步驟的優(yōu)點(diǎn)在于:通過后向合并,可以將小請求聚合成大請求,可以大大提高系統(tǒng)的吞吐量;
(3.6)為該bio請求分配一個(gè)新請求Wnrq,并用該bio請求初始化Wnrq。然后判斷Wnrq是否具有合并屬性。有則跳轉(zhuǎn)到步驟(3.11);否則跳轉(zhuǎn)到步驟(3.12);
(3.7)完成Wfrq與Wprev的合并,并在調(diào)度器的寫鏈表、哈希鏈表中刪除Wfrq,接著需要調(diào)整Wprev在哈希鏈表中的位置,最后將Wprev標(biāo)記為上一次合并的寫請求,已經(jīng)將該bio請求轉(zhuǎn)化為了寫請求,結(jié)束本次轉(zhuǎn)換;
(3.8)將Wfrq標(biāo)記為上次合并的寫請求,已經(jīng)將該bio請求轉(zhuǎn)化為了寫請求,結(jié)束本次轉(zhuǎn)換;
(3.9)完成Wbrq與Wnext的合并,并在調(diào)度器的寫鏈表、哈希鏈表刪除Wnext,接著需要調(diào)整Wbrq在哈希鏈表中的位置,最后將Wbrq標(biāo)記為上次合并的寫請求,已經(jīng)將該bio請求轉(zhuǎn)化為了寫請求,結(jié)束本次轉(zhuǎn)換;
(3.10)調(diào)整Wbrq在哈希鏈表中的位置,并將Wbrq標(biāo)記為上次合并的寫請求,已經(jīng)將該bio請求轉(zhuǎn)化為了寫請求,結(jié)束本次轉(zhuǎn)換;
(3.11)將Wnrq加入哈希鏈表中,并判斷上次合并的寫請求是否存在。若不存在,則將Wnrq標(biāo)記為上次合并的寫請求,并跳轉(zhuǎn)到步驟(3.12);否則,直接跳到步驟(3.12);
(3.12)將Wnrq加入調(diào)度器寫鏈表的尾部,從而將該bio請求轉(zhuǎn)化為了寫請求;
本步驟的優(yōu)點(diǎn)在于:充分考慮到SSD中順序?qū)懻埱蟮男阅芘c隨機(jī)寫請求 的性能基本相同,對寫請求只按照到來時(shí)間在鏈表中排隊(duì),不需要按照寫請求的起始訪問地址在紅黑樹中排序,構(gòu)造寫請求的順序性,消除了排序的性能花銷,提高了性能;
如圖5所示,本發(fā)明方法中的步驟(4)包括以下子步驟:
(4.1)判斷調(diào)度器隊(duì)列中目前分發(fā)請求所處的階段是處于讀批處理階段還是寫批處理階段。如果處于讀批處理階段,則跳轉(zhuǎn)到步驟(4.2);如果處于寫批處理階段,則跳轉(zhuǎn)到步驟(4.3);具體而言,就是通過獲取程序運(yùn)行時(shí)next_rq[dir]變量的值來判斷分發(fā)請求是處于讀批處理階段還是寫批處理階段。本步驟的優(yōu)點(diǎn)在于:批量分發(fā)讀請求或?qū)懻埱?,避免SSD中讀寫請求之間的相互干擾造成的性能下降;
(4.2)判斷讀批處理階段分發(fā)的請求總數(shù)是否已超過閾值。若已超過閾值,則跳轉(zhuǎn)到步驟(4.4),否則跳轉(zhuǎn)到步驟(4.5);在本發(fā)明中,該閾值的取值范圍是(0,16]。
(4.3)判斷寫批處理階段分發(fā)的請求總數(shù)是否已達(dá)上限,若已達(dá)上限,跳轉(zhuǎn)到步驟(4.4);否則跳轉(zhuǎn)到步驟(4.6);
(4.4)創(chuàng)建一個(gè)批處理階段,并確定調(diào)度器隊(duì)列中是否存在對應(yīng)的讀請求嗎,若存在,跳轉(zhuǎn)到步驟(4.9);否則跳轉(zhuǎn)到步驟(4.10);
(4.5)將調(diào)度器中待分發(fā)的請求Drq設(shè)置為next_rq[read],并跳轉(zhuǎn)到步驟(4.7);
(4.6)將調(diào)度器中待分發(fā)的請求Drq設(shè)置為next_rq[write],并跳轉(zhuǎn)到步驟(4.8);
(4.7)將Drq分發(fā)到設(shè)備驅(qū)動(dòng)層的請求隊(duì)列中,從調(diào)度器的讀鏈表和讀紅黑樹中刪除該Drq,并將next_rq[read]設(shè)置為Drq在調(diào)度器的讀紅黑樹中的下一個(gè)請求,最后對該操作進(jìn)行計(jì)數(shù),結(jié)束本次請求分發(fā)過程;
本步驟的優(yōu)點(diǎn)在于:批量分發(fā)讀請求階段,從紅黑樹種獲取下一個(gè)讀請求,以利用紅黑樹的排序功能,構(gòu)造讀請求的順序性,充分利用SSD中順 序讀的性能遠(yuǎn)遠(yuǎn)高于隨機(jī)讀的性能;
(4.8)將Drq分發(fā)到設(shè)備驅(qū)動(dòng)層的請求隊(duì)列中,從調(diào)度器的寫鏈表中刪除Drq,設(shè)置next_rq[write]為Drq在調(diào)度器寫鏈表中的下一個(gè)請求,最后對該操作進(jìn)行計(jì)數(shù),結(jié)束本次請求分發(fā)過程;
本步驟的優(yōu)點(diǎn)在于:批量分發(fā)寫請求階段,從鏈表中獲取下一個(gè)寫請求,不需要構(gòu)造寫請求的順序性,從而省去了排序的開銷,充分利用SSD中隨機(jī)寫的性能基本與順序?qū)懙男阅芟嗤?/p>
(4.9)判斷調(diào)度器的寫鏈表中是否存在請求,如果不存在,則跳轉(zhuǎn)到步驟(4.11);如果存在,則繼續(xù)判斷是否存在超時(shí)的寫請求或者寫請求被饑餓的次數(shù)已達(dá)上限。如果判定結(jié)果為真,則跳轉(zhuǎn)到步驟(4.12);否則跳轉(zhuǎn)到步驟(4.11);
本步驟的優(yōu)點(diǎn)在于:優(yōu)先創(chuàng)建讀請求的批量分發(fā)過程,賦予讀請求較高的優(yōu)先級,已滿足用戶對讀請求響應(yīng)時(shí)間要求比較嚴(yán)格的需求,另外為了防止寫請求被餓死,也設(shè)置了寫請求最晚需要被服務(wù)的時(shí)間,當(dāng)有寫請求超時(shí)時(shí),優(yōu)先分發(fā)超時(shí)的寫請求;
(4.10)判斷調(diào)度器的寫鏈表中是否存在請求。若存在,則跳轉(zhuǎn)到步驟(4.12);否則調(diào)度器中不存在待分發(fā)的請求,結(jié)束本次請求分發(fā)過程;
(4.11)判斷next_rq[read]是否存在。若存在,跳轉(zhuǎn)到步驟(4.13);否則跳轉(zhuǎn)到步驟(4.14);
(4.12)準(zhǔn)備進(jìn)行寫請求的批量處理階段,將寫請求被饑餓的次數(shù)置0。然后判斷是否存在超時(shí)的寫請求或者next_rq[write]是否為空。如果判定結(jié)果為真,跳轉(zhuǎn)到步驟(4.15);否者跳轉(zhuǎn)到步驟(4.16);
(4.13)將待分發(fā)請求Drq設(shè)置為next_rq[read],設(shè)置batching=0,開始創(chuàng)建一個(gè)讀批處理階段,跳轉(zhuǎn)到步驟(4.7);
(4.14)將待分發(fā)請求Drq設(shè)置為調(diào)度器讀鏈表中的第一個(gè)請求,設(shè)置batching=0,開始創(chuàng)建一個(gè)讀批處理階段,跳轉(zhuǎn)到步驟(4.7);
(4.15)將待分發(fā)請求Drq設(shè)置為調(diào)度器寫鏈表中的第一個(gè)請求,設(shè)置batching=0,開始創(chuàng)建一個(gè)寫批處理階段,跳轉(zhuǎn)到步驟(4.8);
(4.16)將待分發(fā)請求Drq設(shè)置為next_rq[write],設(shè)置batching=0,開始創(chuàng)建一個(gè)寫批處理階段,跳轉(zhuǎn)到步驟(4.8)。
本領(lǐng)域的技術(shù)人員容易理解,以上所述僅為本發(fā)明的較佳實(shí)施例而已,并不用以限制本發(fā)明,凡在本發(fā)明的精神和原則之內(nèi)所作的任何修改、等同替換和改進(jìn)等,均應(yīng)包含在本發(fā)明的保護(hù)范圍之內(nèi)。