徐曉思
摘要:對(duì)于使用數(shù)據(jù)庫(kù)存儲(chǔ)數(shù)據(jù)的系統(tǒng)而言,硬盤(pán)較慢的讀取速度極大的限制了系統(tǒng)整體性能的提高。內(nèi)存緩存機(jī)制將常用的數(shù)據(jù)從數(shù)據(jù)庫(kù)緩存到內(nèi)存中并實(shí)時(shí)調(diào)整緩存數(shù)據(jù),有效的提高了數(shù)據(jù)的查詢(xún)效率,降低了系統(tǒng)的響應(yīng)時(shí)間。
關(guān)鍵詞:內(nèi)存緩存;.NET;命中率
中圖分類(lèi)號(hào):TP333 文獻(xiàn)標(biāo)識(shí)碼:A 文章編號(hào):1007-9416(2018)02-0139-05
1 引言
對(duì)于使用數(shù)據(jù)庫(kù)存儲(chǔ)數(shù)據(jù)的系統(tǒng)而言,面臨的主要問(wèn)題是如何高效的查詢(xún)數(shù)據(jù),而硬盤(pán)較慢的讀取速度極大的限制了系統(tǒng)整體性能的提高。由于數(shù)據(jù)庫(kù)存儲(chǔ)的數(shù)據(jù)量通常都比較大,如果一次性將所有數(shù)據(jù)全部緩存到內(nèi)存中,會(huì)導(dǎo)致內(nèi)存緊張甚至溢出,影響整個(gè)系統(tǒng)的性能和穩(wěn)定性。因此,需要在.NET平臺(tái)上設(shè)計(jì)并實(shí)現(xiàn)一個(gè)內(nèi)存緩存機(jī)制,將部分使用到的數(shù)據(jù)從數(shù)據(jù)庫(kù)緩存到內(nèi)存中,并根據(jù)緩存項(xiàng)的命中情況自動(dòng)調(diào)整緩存數(shù)據(jù),以提高數(shù)據(jù)讀取的效率。
2 設(shè)計(jì)
當(dāng)有數(shù)據(jù)讀取請(qǐng)求的時(shí)候,首先檢查是否命中,即要讀取的數(shù)據(jù)是否在緩存中。如果命中,則直接讀取緩存中的數(shù)據(jù)進(jìn)行使用,并更新緩存的狀態(tài)。如果數(shù)據(jù)不在緩存中,則首先讀取數(shù)據(jù)庫(kù)中的數(shù)據(jù)進(jìn)行使用,然后將數(shù)據(jù)添加到緩存中。為了防止內(nèi)存溢出,在程序中對(duì)緩存數(shù)據(jù)的數(shù)量設(shè)置了上限。當(dāng)需要將數(shù)據(jù)添加到緩存中的時(shí)候,首先會(huì)檢查緩存是否已滿(mǎn),如果緩存已滿(mǎn),則根據(jù)清理算法對(duì)緩存進(jìn)行清理后,再將新的數(shù)據(jù)添加到緩存中。數(shù)據(jù)讀取的流程圖如圖1所示。
為了提高命中率,在有數(shù)據(jù)庫(kù)寫(xiě)入操作的時(shí)候,同樣需要更新緩存中的數(shù)據(jù)。當(dāng)有數(shù)據(jù)庫(kù)寫(xiě)入請(qǐng)求的時(shí)候,首先將數(shù)據(jù)寫(xiě)入到數(shù)據(jù)庫(kù),然后檢查是否命中,即要寫(xiě)入的數(shù)據(jù)是否在緩存中。如果命中,則更新緩存項(xiàng)的數(shù)據(jù)和狀態(tài)。如果沒(méi)有命中,則需要將數(shù)據(jù)添加到緩存中。同樣,在添加的時(shí)候需要首先檢查緩存是否已滿(mǎn),如果已滿(mǎn)則需要首先清理緩存后,再將新的數(shù)據(jù)添加到緩存中。數(shù)據(jù)寫(xiě)入的流程圖如圖2所示。
內(nèi)存緩存機(jī)制使用特定的緩存清理算法,緩存項(xiàng)中除了記錄數(shù)據(jù),還記錄了該項(xiàng)的首次命中時(shí)間FirstTime(添加到緩存中的時(shí)間)、最后命中時(shí)間LastTime(最后一次被讀取或修改的時(shí)間)以及命中次數(shù)HitCount,并從以下四個(gè)角度去設(shè)計(jì)緩存清理算法:
(1)命中次數(shù):對(duì)內(nèi)存中所有緩存項(xiàng)按照HitCount進(jìn)行排序,清理所有HitCount低于閾值的緩存項(xiàng)。
(2)最后命中時(shí)間:對(duì)內(nèi)存中所有的緩存項(xiàng)按照LastTime進(jìn)行排序,清理所有LastTime早于閾值的緩存項(xiàng)。
(3)平均命中周期:根據(jù)當(dāng)前時(shí)間CurrentTime計(jì)算出緩存項(xiàng)的平均命中周期AveragePeriod并排序,清理所有AveragePeriod高于閾值的緩存項(xiàng),計(jì)算公式為AveragePeriod=(CurrentTime-FirstTime)/HitCount。
(4)首次命中時(shí)間:如果前三種算法都未生效,則對(duì)內(nèi)存中所有的緩存項(xiàng)按照FirstTime進(jìn)行排序,清理FirstTime最早的那一項(xiàng)。
所有的閾值都可以在配置文件中進(jìn)行設(shè)置。根據(jù)不同的部署環(huán)境設(shè)置不同的閾值能夠有效的保證緩存的命中率和清理算法的效率。
3 實(shí)現(xiàn)
內(nèi)存緩存機(jī)制依靠CacheItem、CacheGroup和CacheManager這三個(gè)類(lèi)來(lái)實(shí)現(xiàn),類(lèi)之間的關(guān)系如圖3所示。
CacheItem是緩存項(xiàng)在代碼中的實(shí)現(xiàn),用來(lái)存儲(chǔ)緩存的內(nèi)容。同時(shí),該類(lèi)還包含與命中有關(guān)的屬性,并提供了獲取和更新緩存內(nèi)容的方法。
CacheItem包含以下私有屬性:
(1)id:緩存項(xiàng)的唯一標(biāo)識(shí)符,String類(lèi)型。CacheManager必須通過(guò)id才能在CacheGroup中找到對(duì)應(yīng)的緩存項(xiàng),這個(gè)屬性在CacheItem創(chuàng)建的時(shí)候被賦值,并且在緩存項(xiàng)的生命周期中始終保持不變。因此,該屬性通過(guò)只讀公有字段Id開(kāi)放給外部讀取,但是不能被修改。
(2)content:用于存儲(chǔ)緩存的內(nèi)容,這個(gè)屬性是Object類(lèi)型的,因此可以存儲(chǔ).NET中的任何對(duì)象。由于對(duì)content的讀取和修改會(huì)引起該緩存項(xiàng)命中相關(guān)屬性的變化,因此外部無(wú)法直接操作該屬性,必須通過(guò)CacheItem提供的方法來(lái)對(duì)內(nèi)容進(jìn)行讀取和修改。
(3)hitCount:命中次數(shù),Integer類(lèi)型。該屬性記錄緩存項(xiàng)的命中次數(shù),在緩存內(nèi)容被讀取或修改的時(shí)候會(huì)自動(dòng)增長(zhǎng),因此通過(guò)只讀公有字段HitCount提供給外部讀取,但是不能被修改。
(4)firstTime:首次命中時(shí)間,DateTime類(lèi)型。該屬性記錄緩存項(xiàng)添加到緩存中的時(shí)間,在CacheItem創(chuàng)建的時(shí)候被賦值,并且在緩存項(xiàng)的生命周期中始終保持不變。因此,該屬性通過(guò)只讀公有字段FirstTime開(kāi)放給外部讀取,但是不能被修改。
(5)lastTime:最后命中時(shí)間,DateTime類(lèi)型。該屬性記錄緩存項(xiàng)最后一次被讀取或修改的時(shí)間,在緩存內(nèi)容被讀取或修改的時(shí)候會(huì)自動(dòng)更新,因此通過(guò)只讀公有字段LastTime提供給外部讀取,但是不能被修改。
除此之外,CacheItem還包含一個(gè)只讀公有字段Average Period,該字段根據(jù)公式計(jì)算緩存項(xiàng)的平均命中周期,在每次被讀取的時(shí)候自動(dòng)進(jìn)行計(jì)算。
CacheItem的構(gòu)造函數(shù)包括兩個(gè)參數(shù)id和content,用于在創(chuàng)建的時(shí)候?qū)儆诰彺骓?xiàng)的唯一標(biāo)識(shí)符和內(nèi)容。
CacheItem包含以下兩個(gè)公有方法:
(1)RetrieveContent:該方法用于返回緩存項(xiàng)的內(nèi)容,并自動(dòng)更新lastTime和hitCount兩個(gè)私有屬性。
(2)UpdateContent:該方法包含一個(gè)Object類(lèi)型的參數(shù),用于更新緩存項(xiàng)的內(nèi)容,并自動(dòng)更新lastTime和hitCount兩個(gè)私有屬性。
CacheItem的類(lèi)圖如圖4所示。
CacheGroup是緩存項(xiàng)的集合,繼承自KeyedCollection
CacheGroup的類(lèi)圖如圖5所示。
CacheManager用于管理CacheGroup及其中的所有CacheItem。該類(lèi)使用單實(shí)例模式,將構(gòu)造函數(shù)私有化,僅在首次被調(diào)用的時(shí)候私有的創(chuàng)建唯一的實(shí)例instance,并通過(guò)只讀公有字段Instance發(fā)布給外部使用。
CacheManager包含以下私有屬性:
(1)cacheGroup:CacheGroup類(lèi)的對(duì)象,用于存儲(chǔ)CacheItem。
(2)max:Integer類(lèi)型,表示cacheGroup中緩存項(xiàng)的數(shù)量上限。當(dāng)緩存項(xiàng)達(dá)到數(shù)量上限的時(shí)候,如果要再添加緩存項(xiàng),則首先需要對(duì)cacheGroup進(jìn)行清理。
(3)clearStrategies:List
(4)defaultStrategy:ClearStrategy類(lèi)型,包含默認(rèn)的緩存清理策略。
CacheManager包含以下私有方法:
(1)CheckCapacity:檢查cacheGroup中的緩存項(xiàng)是否達(dá)到數(shù)量上限。
(2)ClearCache:調(diào)用緩存清理策略清理緩存項(xiàng)。
(3)CreateCache:添加緩存項(xiàng)。在將緩存項(xiàng)添加到cacheGroup之前,會(huì)先調(diào)用CheckCapacity檢查緩存項(xiàng)數(shù)量,如果已經(jīng)達(dá)到上限,則調(diào)用ClearCache方法清理緩存。
(4)DeleteCache:刪除緩存項(xiàng)。
CacheManager包含以下公有方法:
(1)Start:該方法用于啟動(dòng)CacheManager,包含兩個(gè)參數(shù)max和clearStrategies,分別用來(lái)設(shè)置緩存項(xiàng)的數(shù)量上限以及用到的緩存清理策略。
(2)Stop:該方法用于在程序退出的時(shí)候關(guān)閉CacheManager,釋放占用的內(nèi)存。
(3)RetrieveContent:根據(jù)Id提供對(duì)應(yīng)緩存項(xiàng)的內(nèi)容。該方法有兩個(gè)參數(shù),一個(gè)是查詢(xún)的Id,另一個(gè)是用out關(guān)鍵字修飾的Object對(duì)象content,該對(duì)象會(huì)在方法結(jié)束的時(shí)候和返回值一起返回給調(diào)用者,返回值的類(lèi)型是Boolean。如果有緩存項(xiàng)命中,則將命中的內(nèi)容賦值給content并返回True,否則將content賦為空值并返回False。
(4)UpdateContent:該方法包含兩個(gè)參數(shù)id和content,用于更新id對(duì)應(yīng)緩存項(xiàng)的內(nèi)容。如果根據(jù)id無(wú)法命中緩存項(xiàng),則調(diào)用CreateCache方法添加緩存項(xiàng)。
CacheManager的類(lèi)圖如圖6所示。
CacheManager、CacheGroup和CacheItem只負(fù)責(zé)緩存讀寫(xiě)的邏輯,緩存清理的邏輯由緩存清理策略實(shí)現(xiàn)。緩存清理策略的實(shí)現(xiàn)類(lèi)圖如圖7所示。
抽象類(lèi)ClearStrategy是所有緩存策略類(lèi)的基類(lèi),該類(lèi)實(shí)現(xiàn)了IClearStrategy接口的SetThreshold和Clear方法,并擴(kuò)展了RemoveItems和RemoveItem方法,為子類(lèi)實(shí)現(xiàn)了設(shè)置閾值和刪除緩存項(xiàng)的功能。ClearStrategy定義了一個(gè)抽象方法GetOutdatedItems,這個(gè)方法返回List
4 測(cè)試
內(nèi)存緩存機(jī)制的測(cè)試基于應(yīng)用了該機(jī)制的智能會(huì)議系統(tǒng),并包括以下兩個(gè)部分:
(1)緩存命中率測(cè)試:按照一個(gè)中等規(guī)模會(huì)議室(30到50人)設(shè)置數(shù)據(jù)量和緩存參數(shù),對(duì)緩存命中率進(jìn)行測(cè)試,測(cè)試的結(jié)果如圖8所示。根據(jù)測(cè)試結(jié)果可以得到,命中率在測(cè)試初期較低,隨后快速上升,在300次請(qǐng)求后增速減緩,在850次請(qǐng)求后趨于穩(wěn)定。穩(wěn)定后的命中率在66%左右,即平均每3次數(shù)據(jù)讀取請(qǐng)求可以命中2次,只有1次需要讀取數(shù)據(jù)庫(kù)。
(2)系統(tǒng)響應(yīng)時(shí)間測(cè)試:在內(nèi)存緩存機(jī)制開(kāi)啟和關(guān)閉兩種情況下分別對(duì)系統(tǒng)響應(yīng)時(shí)間進(jìn)行測(cè)試,并對(duì)兩組響應(yīng)時(shí)間進(jìn)行比較。兩種情況下系統(tǒng)響應(yīng)時(shí)間測(cè)試的結(jié)果如表1所示。從表中可以看出,內(nèi)存緩存機(jī)制在開(kāi)啟情況下的響應(yīng)時(shí)間明顯低于關(guān)閉情況。
5 結(jié)語(yǔ)
本文基于.NET平臺(tái)討論了內(nèi)存緩存機(jī)制的設(shè)計(jì)、實(shí)現(xiàn)及應(yīng)用效果的測(cè)試。從測(cè)試結(jié)果可以看到,內(nèi)存緩存機(jī)制在命中率方面有不錯(cuò)的表現(xiàn),有效的提高了數(shù)據(jù)的查詢(xún)效率,降低了系統(tǒng)的響應(yīng)時(shí)間,實(shí)現(xiàn)了設(shè)計(jì)的目標(biāo)。
參考文獻(xiàn)
[1]常廣炎.Memcached分布式緩存系統(tǒng)的應(yīng)用[J].電腦編程技巧與維護(hù),2017,(07):24-25.
[2]邢蕾.內(nèi)存緩存技術(shù)在門(mén)戶(hù)網(wǎng)站開(kāi)發(fā)中的應(yīng)用研究[J].山東工業(yè)技術(shù),2016,(20):152-153.
[3]胡嘉瑜,華蓓.基于APU的內(nèi)存鍵值緩存系統(tǒng)[J].電子技術(shù),2016,45(09):54-59.
[4]石磊,黃高攀,喬雄.基于內(nèi)存數(shù)據(jù)庫(kù)的索引算法研究[J].信息技術(shù),2016,(11):139-142.
[5]許春聰,劉釗,文海雄,黃忠主,鄭強(qiáng).基于內(nèi)存的數(shù)據(jù)存儲(chǔ)技術(shù)研究[J].科技與創(chuàng)新,2018,(02):19-21.