天天看點

【面經】面試官:講講Redis的虛拟記憶體?

關于Redis

與大多數的NoSQL資料庫一樣,Redis同樣遵循了Key/Value資料存儲模型。但是在有些情況下,Redis會将Keys/Values儲存在記憶體中以提高資料查詢和資料修改的效率,但是,這種方式也不是最優的。我們可以進一步優化,盡量在記憶體中隻保留Keys的資料,這樣可以保證資料檢索的效率,而Values資料在很少使用的時候則可以被持久化到磁盤。

在實際的應用中,大約隻有10%的Keys屬于相對比較常用的鍵,這樣Redis就可以通過虛拟記憶體将其餘不常用的Keys和Values持久化到磁盤上,而一旦這些被持久化的Keys或Values需要被讀取時,Redis則将其再次讀回到主記憶體中。

應用場景

對于大多數資料庫而言,最為理想的運作方式就是将所有的資料都加載到記憶體中,而之後的查詢操作則可以完全基于記憶體資料完成。但是,在現實中這樣的場景并不多,更多的情況則是隻有部分資料可以被加載到記憶體中。

在Redis中,有一個非常重要的概念,即keys一般不會被交換,是以如果你的資料庫中有大量的keys,其中每個key僅僅關聯很小的value,那麼這種場景就不是非常适合使用虛拟記憶體。如果恰恰相反,資料庫中隻是包含少量的keys,而每一個key所關聯的value卻非常大,那麼這種場景對于使用虛拟記憶體就非常合适了。

在實際的應用中,為了能讓虛拟記憶體更為充分的發揮作用以幫助我們提高系統的運作效率,我們可以将帶有很多較小值的Keys合并為帶有少量較大值的Keys。其中最主要的方法就是将原有的Key/Value模式改為基于Hash的模式,這樣可以讓很多原來的Keys成為Hash中的屬性。

配置Redis虛拟記憶體

(1)在配置檔案中添加以下配置項,以使目前Redis伺服器在啟動時打開虛拟記憶體功能。

vm-enabled yes      

(2)在配置檔案中設定Redis最大可用的虛拟記憶體位元組數。如果記憶體中的資料大于該值,則有部分對象被持久化到磁盤中,其中被持久化對象所占用的記憶體将被釋放,直到已用記憶體小于該值時才停止持久化。

vm-max-memory (bytes)      

Redis的交換規則是盡量考慮"最老"的資料,即最長時間沒有使用的資料将被持久化。如果兩個對象的age相同,那麼Value較大的資料将先被持久化。需要注意的是,Redis不會将Keys持久化到磁盤,是以如果僅僅keys的資料就已經填滿了整個虛拟記憶體,那麼這種資料模型将不适合使用虛拟記憶體機制,或者是将該值設定的更大,以容納整個Keys的資料。在實際的應用,如果考慮使用Redis虛拟記憶體,我們應盡可能的配置設定更多的記憶體交給Redis使用,以避免頻繁的将資料持久化到磁盤上。

(3)在配置檔案中設定頁的數量及每一頁所占用的位元組數。為了将記憶體中的資料傳送到磁盤上,我們需要使用交換檔案。這些檔案與資料持久性無關,Redis會在退出前會将它們全部删除。由于對交換檔案的通路方式大多為随機通路,是以建議将交換檔案存儲在固态磁盤上,這樣可以大大提高系統的運作效率。

vm-pages 134217728
vm-page-size 32      

在上面的配置中,Redis将需要持久化的檔案劃分為vm-pages個頁,其中每個頁所占用的位元組為vm-page-size,那麼Redis最終可用的交換檔案大小為:vm-pages *  vm-page-size。由于一個value可以存放在一個或多個頁上,但是一個頁不能持有多個value,鑒于此,我們在設定vm-page-size時需要充分考慮Redis的該特征。

(4)在Redis的配置檔案中有一個非常重要的配置參數,即:

vm-max-threads 4      

該參數表示Redis在對交換檔案執行IO操作時所應用的最大線程數量。通常而言,我們推薦該值等于主機的CPU cores。如果将該值設定為0,那麼Redis在與交換檔案進行IO互動時,将以同步的方式執行此操作。

Redis同步資料方式

對于Redis而言,如果操作交換檔案是以同步的方式進行,那麼當某一用戶端正在通路交換檔案中的資料時,其它用戶端如果再試圖通路交換檔案中的資料,該用戶端的請求就将被挂起,直到之前的操作結束為止。特别是在相對較慢或較忙的磁盤上讀取較大的資料值時,這種阻塞所帶來的影響就更為突兀了。

然而同步操作也并非一無是處,事實上,從全局執行效率視角來看,同步方式要好于異步方式,畢竟同步方式節省了線程切換、線程間同步,以及線程拉起等操作産生的額外開銷。特别是當大部分頻繁使用的資料都可以直接從主記憶體中讀取時,同步方式的表現将更為優異。

至于最終選用哪種配置方式,最好的方式是不斷的實驗和調優。