你管這破玩意兒叫Redis虛擬內(nèi)存?
Redis作為分布式緩存的標配,在開發(fā)分布式和微服務系統(tǒng)時被廣泛應用。但是,很少有小伙伴會去了解有關Redis的虛擬內(nèi)存。這不,一哥們出去面試就被問到這個問題。今天,我們就一起來聊聊Redis的虛擬內(nèi)存。
關于Redis
與大多數(shù)的NoSQL數(shù)據(jù)庫一樣,Redis同樣遵循了Key/Value數(shù)據(jù)存儲模型。但是在有些情況下,Redis會將Keys/Values保存在內(nèi)存中以提高數(shù)據(jù)查詢和數(shù)據(jù)修改的效率,但是,這種方式也不是最優(yōu)的。
我們可以進一步優(yōu)化,盡量在內(nèi)存中只保留Keys的數(shù)據(jù),這樣可以保證數(shù)據(jù)檢索的效率,而Values數(shù)據(jù)在很少使用的時候則可以被持久化到磁盤。
在實際的應用中,大約只有10%的Keys屬于相對比較常用的鍵,這樣Redis就可以通過虛擬內(nèi)存將其余不常用的Keys和Values持久化到磁盤上,而一旦這些被持久化的Keys或Values需要被讀取時,Redis則將其再次讀回到主內(nèi)存中。
應用場景
對于大多數(shù)數(shù)據(jù)庫而言,最為理想的運行方式就是將所有的數(shù)據(jù)都加載到內(nèi)存中,而之后的查詢操作則可以完全基于內(nèi)存數(shù)據(jù)完成。但是,在現(xiàn)實中這樣的場景并不多,更多的情況則是只有部分數(shù)據(jù)可以被加載到內(nèi)存中。
在Redis中,有一個非常重要的概念,即keys一般不會被交換,所以如果你的數(shù)據(jù)庫中有大量的keys,其中每個key僅僅關聯(lián)很小的value,那么這種場景就不是非常適合使用虛擬內(nèi)存。
如果恰恰相反,數(shù)據(jù)庫中只是包含少量的keys,而每一個key所關聯(lián)的value卻非常大,那么這種場景對于使用虛擬內(nèi)存就非常合適了。
在實際的應用中,為了能讓虛擬內(nèi)存更為充分的發(fā)揮作用以幫助我們提高系統(tǒng)的運行效率,我們可以將帶有很多較小值的Keys合并為帶有少量較大值的Keys。
其中最主要的方法就是將原有的Key/Value模式改為基于Hash的模式,這樣可以讓很多原來的Keys成為Hash中的屬性。
配置Redis虛擬內(nèi)存
(1)在配置文件中添加以下配置項,以使當前Redis服務器在啟動時打開虛擬內(nèi)存功能。
vm-enabled yes
(2)在配置文件中設定Redis最大可用的虛擬內(nèi)存字節(jié)數(shù)。如果內(nèi)存中的數(shù)據(jù)大于該值,則有部分對象被持久化到磁盤中,其中被持久化對象所占用的內(nèi)存將被釋放,直到已用內(nèi)存小于該值時才停止持久化。
vm-max-memory (bytes)
Redis的交換規(guī)則是盡量考慮"最老"的數(shù)據(jù),即最長時間沒有使用的數(shù)據(jù)將被持久化。如果兩個對象的age相同,那么Value較大的數(shù)據(jù)將先被持久化。
需要注意的是,Redis不會將Keys持久化到磁盤,因此如果僅僅keys的數(shù)據(jù)就已經(jīng)填滿了整個虛擬內(nèi)存,那么這種數(shù)據(jù)模型將不適合使用虛擬內(nèi)存機制,或者是將該值設置的更大,以容納整個Keys的數(shù)據(jù)。
在實際的應用,如果考慮使用Redis虛擬內(nèi)存,我們應盡可能的分配更多的內(nèi)存交給Redis使用,以避免頻繁的將數(shù)據(jù)持久化到磁盤上。
(3)在配置文件中設定頁的數(shù)量及每一頁所占用的字節(jié)數(shù)。為了將內(nèi)存中的數(shù)據(jù)傳送到磁盤上,我們需要使用交換文件。這些文件與數(shù)據(jù)持久性無關,Redis會在退出前會將它們?nèi)縿h除。
由于對交換文件的訪問方式大多為隨機訪問,因此建議將交換文件存儲在固態(tài)磁盤上,這樣可以大大提高系統(tǒng)的運行效率。
vm-pages 134217728
vm-page-size 32
在上面的配置中,Redis將需要持久化的文件劃分為vm-pages個頁,其中每個頁所占用的字節(jié)為vm-page-size,那么Redis最終可用的交換文件大小為:vm-pages * vm-page-size。
由于一個value可以存放在一個或多個頁上,但是一個頁不能持有多個value,鑒于此,我們在設置vm-page-size時需要充分考慮Redis的該特征。
(4)在Redis的配置文件中有一個非常重要的配置參數(shù),即:
vm-max-threads 4
該參數(shù)表示Redis在對交換文件執(zhí)行IO操作時所應用的最大線程數(shù)量。通常而言,我們推薦該值等于主機的CPU cores。
如果將該值設置為0,那么Redis在與交換文件進行IO交互時,將以同步的方式執(zhí)行此操作。
Redis同步數(shù)據(jù)方式
對于Redis而言,如果操作交換文件是以同步的方式進行,那么當某一客戶端正在訪問交換文件中的數(shù)據(jù)時,其它客戶端如果再試圖訪問交換文件中的數(shù)據(jù),該客戶端的請求就將被掛起,直到之前的操作結(jié)束為止。特別是在相對較慢或較忙的磁盤上讀取較大的數(shù)據(jù)值時,這種阻塞所帶來的影響就更為突兀了。
然而同步操作也并非一無是處,事實上,從全局執(zhí)行效率視角來看,同步方式要好于異步方式,畢竟同步方式節(jié)省了線程切換、線程間同步,以及線程拉起等操作產(chǎn)生的額外開銷。特別是當大部分頻繁使用的數(shù)據(jù)都可以直接從主內(nèi)存中讀取時,同步方式的表現(xiàn)將更為優(yōu)異。
至于最終選用哪種配置方式,最好的方式是不斷的實驗和調(diào)優(yōu)。