本發(fā)明涉及數(shù)據(jù)存儲領(lǐng)域,特別是指一種混合存儲系統(tǒng)中ssd管理方法及裝置。
背景技術(shù):
目前存儲系統(tǒng)的發(fā)展趨向于大容量,低成本和高性能,而任何單一的存儲器件如非易失性隨機(jī)存儲器(nonvolatilerandomaccessmemory,nvram)、固態(tài)硬盤(solidstatedrives,ssd)、磁盤等由于其物理特性的限制,并不能滿足以上需求?;旌洗鎯Τ浞掷貌煌鎯ζ骷奶匦越M成高效的存儲系統(tǒng),既能支持存儲系統(tǒng)容量的大幅擴(kuò)展,又能在保持系統(tǒng)低成本的前提下,顯著提高存儲系統(tǒng)的性能。
現(xiàn)有的混合存儲系統(tǒng)僅僅將ssd作為一個數(shù)據(jù)熱點cachememory(高速緩沖存儲器)使用,將熱點數(shù)據(jù)置于ssd中來加快讀數(shù)據(jù)的訪問。對數(shù)據(jù)的組織方式和應(yīng)用并沒有改變,只是簡單地做了一層緩存到磁盤的映射的查詢。在隨機(jī)寫時,存在寫放大,系統(tǒng)隨機(jī)寫的性能低。
技術(shù)實現(xiàn)要素:
本發(fā)明提供一種混合存儲系統(tǒng)中ssd管理方法及裝置,本發(fā)明能夠?qū)⑺袘?yīng)用層的隨機(jī)io都轉(zhuǎn)換成順序?qū)?,并避免寫放大,有效地提高了隨機(jī)寫的性能,減少了寫入延遲,有效地發(fā)揮了混合存儲系統(tǒng)的優(yōu)勢。
為解決上述技術(shù)問題,本發(fā)明提供技術(shù)方案如下:
一方面,本發(fā)明提供一種混合存儲系統(tǒng)中ssd管理方法,該方法包括:
將ssd按照一定大小劃分成多個bucket,并使用b-tree管理bucket;
當(dāng)需要將緩存數(shù)據(jù)寫入ssd時,執(zhí)行如下操作:
聚合連續(xù)io和/或同一用戶的緩存數(shù)據(jù);
選擇合適的bucket,作為可用bucket;
從可用bucket的數(shù)據(jù)偏移位置開始順序?qū)懭刖彺鏀?shù)據(jù),所述數(shù)據(jù)偏移位置記錄bucket的已使用緩存空間的位置;
更新可用bucket的數(shù)據(jù)偏移位置,以便下次寫入緩存數(shù)據(jù)。
進(jìn)一步的,所述選擇合適的bucket,作為可用bucket包括:
判斷是否有空閑bucket,若是,選擇一個空閑bucket作為可用bucket,否則,執(zhí)行下列步驟;
判斷是否有后備bucket,若是,選擇一個后備bucket作為可用bucket。
進(jìn)一步的,如果沒有后備bucket,則執(zhí)行如下步驟:
將所有bucket按照優(yōu)先級從小到大排序,所述優(yōu)先級表示bucket的使用頻率;
將優(yōu)先級小的若干個bucket中的熱點數(shù)據(jù)轉(zhuǎn)存到其中一個bucket中,釋放其他bucket,釋放后的bucket作為后備bucket。
進(jìn)一步的,所述方法還包括:
以bkey為單位將緩存數(shù)據(jù)寫回磁盤,并向b-tree更新節(jié)點。
進(jìn)一步的,所述方法還包括:
使用日志按照插入時間排序記錄b-tree葉子節(jié)點上bkey的更新。
進(jìn)一步的,所述方法還包括:
判斷要讀取的數(shù)據(jù)是否已經(jīng)作為緩存數(shù)據(jù)全部寫入ssd中,若是,直接從ssd讀出數(shù)據(jù),否則,從磁盤讀取數(shù)據(jù)至ssd中,并向b-tree更新節(jié)點。
另一方面,本發(fā)明提供一種混合存儲系統(tǒng)中ssd管理裝置,該裝置包括:
bucket劃分模塊,用于將ssd按照一定大小劃分成多個bucket,并使用b-tree管理bucket;
當(dāng)需要將緩存數(shù)據(jù)寫入ssd時,執(zhí)行bucket管理模塊,所述bucket管理模塊包括:
聚合單元,用于聚合連續(xù)io和/或同一用戶的緩存數(shù)據(jù);
bucket選擇單元,用于選擇合適的bucket,作為可用bucket;
寫入單元,用于從可用bucket的數(shù)據(jù)偏移位置開始順序?qū)懭刖彺鏀?shù)據(jù),所述數(shù)據(jù)偏移位置記錄bucket的已使用緩存空間的位置;
更新單元,用于更新可用bucket的數(shù)據(jù)偏移位置,以便下次寫入緩存數(shù)據(jù)。
進(jìn)一步的,所述bucket選擇單元包括:
空閑bucket選擇單元,用于判斷是否有空閑bucket,若是,選擇一個空閑bucket作為可用bucket,否則,執(zhí)行后備bucket選擇單元;
后備bucket選擇單元,用于判斷是否有后備bucket,若是,選擇一個后備bucket作為可用bucket。
進(jìn)一步的,如果沒有后備bucket,則bucket選擇單元還包括:
bucket排序單元,用于將所有bucket按照優(yōu)先級從小到大排序,所述優(yōu)先級表示bucket的使用頻率;
bucket釋放單元,用于將優(yōu)先級小的若干個bucket中的熱點數(shù)據(jù)轉(zhuǎn)存到其中一個bucket中,釋放其他bucket,釋放后的bucket作為后備bucket。
進(jìn)一步的,所述裝置還包括:
日志模塊,用于使用日志按照插入時間排序記錄b-tree葉子節(jié)點上bkey的更新。
本發(fā)明具有以下有益效果:
本發(fā)明中,bucket內(nèi)空間是追加分配的,只記錄當(dāng)前分配到哪個偏移了,下一次分配的時候從當(dāng)前記錄位置往后分配。在向bucket寫入緩存數(shù)據(jù)時,有兩個優(yōu)先原則:1)優(yōu)先考慮io連續(xù)性,即使io可能來自于不同的生產(chǎn)者;2)其次考慮相關(guān)性,同一個用戶(進(jìn)程)產(chǎn)生的數(shù)據(jù)盡量緩存到相同的bucket里。我們將上述緩存數(shù)據(jù)合并,一次寫入bucket,這樣所有應(yīng)用層的隨機(jī)io都轉(zhuǎn)換成順序?qū)?,并避免寫放大,有效地提高了隨機(jī)寫的性能,減少了寫入延遲,有效地發(fā)揮了混合存儲系統(tǒng)的優(yōu)勢。
附圖說明
圖1為本發(fā)明的混合存儲系統(tǒng)中ssd管理方法流程圖;
圖2為為本發(fā)明中bkey的示意圖;
圖3為本發(fā)明的混合存儲系統(tǒng)中ssd管理裝置示意圖。
具體實施方式
為使本發(fā)明要解決的技術(shù)問題、技術(shù)方案和優(yōu)點更加清楚,下面將結(jié)合附圖及具體實施例進(jìn)行詳細(xì)描述。
一方面,本發(fā)明提供一種混合存儲系統(tǒng)中ssd管理方法,如圖1所示,包括:
步驟100:將ssd按照一定大小劃分成多個bucket,并使用b-tree管理bucket。
緩存設(shè)備(ssd)會按照bucket大小劃分成很多bucket(存儲桶),bucket的大小最好是設(shè)置成與緩存設(shè)備ssd的擦除大小一致,建議128k~2m+,默認(rèn)是512k。
bucket的管理是使用b+樹(b-tree,b+tree,btree)索引,而b+樹節(jié)點中的關(guān)鍵結(jié)構(gòu)就是bkey,bkey就是記錄緩存設(shè)備緩存數(shù)據(jù)和后端設(shè)備數(shù)據(jù)的映射關(guān)系的,其結(jié)構(gòu)圖2。
當(dāng)需要將緩存數(shù)據(jù)寫入ssd時,執(zhí)行如下操作:
步驟210:聚合連續(xù)io和/或同一用戶的緩存數(shù)據(jù)。
步驟220:選擇合適的bucket,作為可用bucket。
步驟230:從可用bucket的數(shù)據(jù)偏移位置開始順序?qū)懭刖彺鏀?shù)據(jù),數(shù)據(jù)偏移位置記錄bucket的已使用緩存空間的位置。
步驟240:更新可用bucket的數(shù)據(jù)偏移位置,以便下次寫入緩存數(shù)據(jù)。
本發(fā)明中,bucket內(nèi)空間是追加分配的,只記錄當(dāng)前分配到哪個偏移了,下一次分配的時候從當(dāng)前記錄位置往后分配。在向bucket寫入緩存數(shù)據(jù)時,有兩個優(yōu)先原則:1)優(yōu)先考慮io連續(xù)性,即使io可能來自于不同的生產(chǎn)者;2)其次考慮相關(guān)性,同一個用戶(進(jìn)程)產(chǎn)生的數(shù)據(jù)盡量緩存到相同的bucket里。我們將上述緩存數(shù)據(jù)合并,一次寫入bucket,這樣所有應(yīng)用層的隨機(jī)io都轉(zhuǎn)換成順序?qū)?,并避免寫放大,有效地提高了隨機(jī)寫的性能,減少了寫入延遲,有效地發(fā)揮了混合存儲系統(tǒng)的優(yōu)勢。
本發(fā)明中,bucket的分配和管理有多種方法,優(yōu)選的,選擇合適的bucket,作為可用bucket(步驟220)包括:
步驟221:判斷是否有空閑bucket,若是,選擇一個空閑bucket作為可用bucket,否則,執(zhí)行下列步驟。
步驟222:判斷是否有后備bucket,若是,選擇一個后備bucket作為可用bucket。
如果沒有后備bucket,則執(zhí)行如下步驟:
步驟223:將所有bucket按照優(yōu)先級從小到大排序,優(yōu)先級表示bucket的使用頻率。
步驟224:將優(yōu)先級小的若干個bucket中的熱點數(shù)據(jù)轉(zhuǎn)存到其中一個bucket中,釋放其他bucket,釋放后的bucket作為后備bucket。
步驟221-224的一個具體實施方式如下:
每個bucket有個優(yōu)先級編號(16bit的priority),每次hit(命中)都會增加,然后所有的bucket的優(yōu)先級編號都會周期性地減少,不常用的會被回收,這個優(yōu)先級編號主要是用來實現(xiàn)lru替換的。bucket還有8bit的generation,用來invalidatebucket用的。
bucket的分配如下:
a.先查看當(dāng)前是否有空閑的bucket,可用下列函數(shù)查看:
fifo_pop(&ca->free[reserve_none],r)||fifo_pop(&ca->free[reserve],r));
b.若無空閑的bucket可用,則當(dāng)前線程進(jìn)入等待,直到有可用的bucket;
c.喚醒分配線程;
d.更新bucket信息,若該bucket分配給元數(shù)據(jù)使用,設(shè)置bucket標(biāo)識為gc_mark_metadata不能隨意回收標(biāo)識,設(shè)置bucket目前不需要垃圾收集器處理標(biāo)識。否則設(shè)置bucket為可回收標(biāo)識。
分配線程如下:
a.如果后備free_inc不為空,fifo_pop(&ca->free_inc,bucket)一個后備bucket,將其加入ca->free中,這樣保證分配函數(shù)有可用的bucket.然后喚醒等待分配桶的線程。若ca->free已滿,則分配線程阻塞。
b.如果free_inc已經(jīng)空了,則需要invalidate當(dāng)前正在使用的bucket;
遍歷ssd的每個bucket{
若不能回收則continue;
將bucket加入到heap中,比較函數(shù)為bucket_max_cmp,用來比較桶的優(yōu)先級大??;
}
按優(yōu)先級從小到大排序heap(bucket_min_cmps);
一次從堆中取出bucket,做sarw_invalidate_one_bucket;直到ca->free_inc滿;
若ca->free_inc未滿,則喚醒垃圾回收線程。
c.更新存儲在磁盤中的bucket的gen信息sarw_prio_write。
垃圾回收線程如下:
其主要思路是:合并包含較少key的btreenode,來釋放bucket,移動葉節(jié)點對應(yīng)bucket(bucket->gen<=key->gen)數(shù)據(jù)區(qū)未用滿的bucket來節(jié)省bucket;
它會掃描整個btree,判斷哪些bkey是可以gc(回收)的,把能夠gc的bkey加到moving_gc_keys鏈表中,然后就根據(jù)這個可以gc的key先從ssd中讀出數(shù)據(jù),然后同樣根據(jù)key中記錄的hdd上的偏移寫到hdd中,成功后把該key從moving_gc_keys中移除。
bucket分配器在inc_free未滿的情況下會喚醒垃圾回收線程線程,其流程如下:
a.sarw_gc_start設(shè)置軟件標(biāo)記表明gc開始工作。
b.sarw_root工作調(diào)用sarw_btree_gc_root來遍歷btree,分析哪些bucket可被gc回收。
c.sarw_btree_gc_finish標(biāo)記不能gc的bucket為meta,并統(tǒng)計能gc的bucket數(shù)目。
d.喚醒分配器線程。
e.完成實際垃圾回收工作。
它遍歷b+tree的每個node,對每個node執(zhí)行btree_gc_coalesce。該函數(shù)判斷若一個到多個node的keys所占用的空間較小,則通過合并btreenode的方式來減少bucket的使用量。
本發(fā)明還包括寫回過程,包括:
步驟300:以bkey為單位將緩存數(shù)據(jù)寫回磁盤,并向b-tree更新節(jié)點。
一個bucket里面緩存的數(shù)據(jù)可能對應(yīng)hdd(磁盤)上的不同位置,甚至有可能在不同的hdd。它是以bkey為單位來寫回,而不是以bucket為單位。它有一個writeback_keys鏈表,記錄需要寫回的bkeys。當(dāng)滿足刷臟數(shù)據(jù)(寫回)的條件時(臟數(shù)據(jù)比例),就會遍歷整個b+樹,查找dirty的bkey,放到writeback_keys鏈表中(writeback_keys有個大小限制),然后按照磁盤偏移排序,再進(jìn)行刷臟數(shù)據(jù)的動作,數(shù)據(jù)寫到hdd后,會把對應(yīng)的bkey從writeback_keys鏈表中移除,并去掉該bkey的dirty標(biāo)記。這樣的好處在于刷臟數(shù)據(jù)的時候可以盡量考慮hdd上的連續(xù)性,減少磁頭的移動,而如果以bucket為單位刷,一個bucket可能緩存hdd上不同位置的數(shù)據(jù),比較隨機(jī),刷臟數(shù)據(jù)的效率不高。
寫回過程的一個具體實施方式包括
a.查看是否和已有要writeback的區(qū)域有重合,若有,取消當(dāng)前區(qū)域的bypass。
b.若bio為req_discard,則采用bypass。
c.向b+tree更新節(jié)點。
具體的實現(xiàn)過程為;
對于葉節(jié)點執(zhí)行:
a.若node未dirty則延遲調(diào)用后臺刷寫.
b.已dirty,如果bset的大小已經(jīng)很大則sarw_btree_node_write(b,null);注意對于多數(shù)情況并不會立即更新node以提高性能。這時就靠前面的sarw_journal,來記錄更新的日志來保證更改不會丟失了。
對于非頁節(jié)點執(zhí)行:
將分三種情況實際更新b+tree
case1:要插入key<btree->key,則直接調(diào)用btree_insert_key插入。
case2:和btree已有key部分重合,計算不重合部分插入;
bkey_copy(&temp.key,insert_keys->keys);
sarw_cut_back(&b->key,&temp.key);
sarw_cut_front(&b->key,insert_keys->keys);
ret|=btree_insert_key(b,&temp.key,replace_key)。
case3:完全包含與btree->key則不插入。
本發(fā)明使用b+tree和日志(journal)混合方法來跟蹤緩存數(shù)據(jù),此時,本發(fā)明的方法還包括:
步驟400:使用日志按照插入時間排序記錄b-tree葉子節(jié)點上bkey的更新。
journal不是為了一致性恢復(fù)用的,而是為了提高性能。在寫回提到?jīng)]有journal之前每次寫操作都會更新元數(shù)據(jù)(一個bset),為了減少這個開銷,引入journal,journal就是插入的keys的log,按照插入時間排序,只用記錄葉子節(jié)點上bkey的更新,非葉子節(jié)點在分裂的時候就已經(jīng)持久化了。這樣每次寫操作在數(shù)據(jù)寫入后就只用記錄一下log,在崩潰恢復(fù)的時候就可以根據(jù)這個log重新插入key。
日志就是插入的keys的log,按照插入時間排序,只用記錄葉子節(jié)點上bkey的更新,非葉子節(jié)點在分裂的時候就已經(jīng)持久化了。這樣每次寫操作在數(shù)據(jù)寫入后就只用記錄一下log,在崩潰恢復(fù)的時候就可以根據(jù)這個log重新插入key。
本發(fā)明還包括讀取過程,包括:
步驟500:判斷要讀取的數(shù)據(jù)是否已經(jīng)作為緩存數(shù)據(jù)全部寫入ssd中,若是,直接從ssd讀出數(shù)據(jù),否則,從磁盤讀取數(shù)據(jù)至ssd中,并向b-tree更新節(jié)點。
讀取過程的一個實施方式為:
a.如果device沒有對應(yīng)的緩存設(shè)備,則直接將向主設(shè)備提交bio,并返回。
b.如果有cachedevice根據(jù)要傳輸?shù)腷io,用search_alloc建立structsearchs。
c.調(diào)用check_should_bypasscheck是否應(yīng)該bypass這個bio。
d.根據(jù)讀寫分別調(diào)用cached_dev_read或cached_dev_write。
具體如下:
遍歷b+tree葉子節(jié)點,來查找bkey:key(inode,bi_sector,0);當(dāng)遍歷到頁節(jié)點時lookup_fn函數(shù)會被調(diào)用。
a.若帶搜索的key比當(dāng)前key小,則返回map_continue讓上層搜索下一個key。
b.若key不在b+tree或key中的數(shù)據(jù)只有部分在b+tree則調(diào)用cache_miss(b,s,bio,sectors)。
c.如果數(shù)據(jù)已在緩存中(bkey在b+tree中,且key中的數(shù)據(jù)范圍也完全在緩存中)了,則直接從緩存disk讀取,命中后需將bucket的prio重新設(shè)為32768。
d.從主設(shè)備讀取數(shù)據(jù),并將bio記錄到iop.bio中以便上層。
e.當(dāng)iop.bio不為0時,表明有新的數(shù)據(jù)要添加到管理緩存的b+tree中,所以首先bio_copy_data(s->cache_miss,s->iop.bio)將數(shù)據(jù)拷貝到cache_missbio中,然后調(diào)用sarw_data_insert將數(shù)據(jù)更新到cache設(shè)備中。
另一發(fā)面,本發(fā)明提供一種混合存儲系統(tǒng)中ssd管理裝置,如圖3所示,包括:
bucket劃分模塊1,用于將ssd按照一定大小劃分成多個bucket,并使用b-tree管理bucket。
當(dāng)需要將緩存數(shù)據(jù)寫入ssd時,執(zhí)行bucket管理模塊2,bucket管理模塊2包括:
聚合單元21,用于聚合連續(xù)io和/或同一用戶的緩存數(shù)據(jù)。
bucket選擇單元22,用于選擇合適的bucket,作為可用bucket。
寫入單元23,用于從可用bucket的數(shù)據(jù)偏移位置開始順序?qū)懭刖彺鏀?shù)據(jù),數(shù)據(jù)偏移位置記錄bucket的已使用緩存空間的位置。
更新單元24,用于更新可用bucket的數(shù)據(jù)偏移位置,以便下次寫入緩存數(shù)據(jù)。
本發(fā)明中,bucket內(nèi)空間是追加分配的,只記錄當(dāng)前分配到哪個偏移了,下一次分配的時候從當(dāng)前記錄位置往后分配。在向bucket寫入緩存數(shù)據(jù)時,有兩個優(yōu)先原則:1)優(yōu)先考慮io連續(xù)性,即使io可能來自于不同的生產(chǎn)者;2)其次考慮相關(guān)性,同一個用戶(進(jìn)程)產(chǎn)生的數(shù)據(jù)盡量緩存到相同的bucket里。我們將上述緩存數(shù)據(jù)合并,一次寫入bucket,這樣所有應(yīng)用層的隨機(jī)io都轉(zhuǎn)換成順序?qū)懀⒈苊鈱懛糯?,有效地提高了隨機(jī)寫的性能,減少了寫入延遲,有效地發(fā)揮了混合存儲系統(tǒng)的優(yōu)勢。
本發(fā)明中,bucket的分配和管理有多種方法,優(yōu)選的,bucket選擇單元包括:
空閑bucket選擇單元,用于判斷是否有空閑bucket,若是,選擇一個空閑bucket作為可用bucket,否則,執(zhí)行后備bucket選擇單元。
后備bucket選擇單元,用于判斷是否有后備bucket,若是,選擇一個后備bucket作為可用bucket。
如果沒有后備bucket,則bucket選擇單元還包括:
bucket排序單元,用于將所有bucket按照優(yōu)先級從小到大排序,優(yōu)先級表示bucket的使用頻率。
bucket釋放單元,用于將優(yōu)先級小的若干個bucket中的熱點數(shù)據(jù)轉(zhuǎn)存到其中一個bucket中,釋放其他bucket,釋放后的bucket作為后備bucket。
本發(fā)明使用b+tree和日志(journal)混合方法來跟蹤緩存數(shù)據(jù),此時,本發(fā)明的裝置還包括:
日志模塊,用于使用日志按照插入時間排序記錄b-tree葉子節(jié)點上bkey的更新。
以上所述是本發(fā)明的優(yōu)選實施方式,應(yīng)當(dāng)指出,對于本技術(shù)領(lǐng)域的普通技術(shù)人員來說,在不脫離本發(fā)明所述原理的前提下,還可以作出若干改進(jìn)和潤飾,這些改進(jìn)和潤飾也應(yīng)視為本發(fā)明的保護(hù)范圍。