1. 程式人生 > >《Redis官方文件》 redis 虛擬記憶體

《Redis官方文件》 redis 虛擬記憶體

原文連結 譯文連結 譯者: youxin2012 重點提示: Redis 的虛擬記憶體(VM) 目前不被提倡使用,Redis 2.4將是有虛擬記憶體特性的最新版本(但它同樣提示不鼓勵使用虛擬記憶體)。我們發現使用虛擬記憶體會有一些不足和問題。對於Redis的未來,至少目前在不考慮支援比RAM更大的資料庫時,我們希望能提供最好的記憶體資料庫(持久化仍然在磁碟上)。我們隨後的成果將關注提供指令碼,叢集以及更好的持久化方面。

虛擬記憶體

Redis 虛擬記憶體這一特性將首次出現在Redis 2.0的一個穩定釋出版中。目前Git上Redis 不穩定分支的虛擬記憶體(從現在起稱之為VM)已經可以使用,並且經試驗證明足夠穩定。

簡介

Redis遵循 key-value模型。同時key和value通常都儲存在記憶體中。然而有時這並不是一個最好的選擇,所以在設計過程中我們要求key必須儲存在記憶體中(為了保證快速查詢),而value在很少使用時,可以從記憶體被交換出至磁碟上。

實際應用中,如果記憶體中有一個10萬條記錄的key值資料集,而只有10%被經常使用,那麼開啟虛擬記憶體的Redis將把與較少使用的key相對應的value轉移至磁碟上。當客戶端請求獲取這些value時,他們被將從swap 檔案中讀回,並載入到記憶體中。

何時使用虛擬記憶體

在確定使用VM之前,請首先確認是否真的需要使用這一特性。Redis是一個磁碟備份,記憶體型資料庫。使用Redis 的正確方法通常是使用足夠大的RAM去裝載所有資料。然而,有些場景下是無法做到這樣的:

  • 資料訪問不均勻。只有很少部分的key被大量訪問,而每一個key又有大量的資料要放入記憶體。
  • 在不考慮資料讀取方式以及value儲存空間大小的前提下,僅由於沒有足夠的空間將所有資料放入記憶體。這種場景下,Redis可以被配置為在記憶體中儲存key,在磁碟中儲存value。此時key的查詢操作較快,而value的讀取則相對較慢。

謹記Redis的key是不做swap操作的,所以如果你的記憶體有大量的key和少量的value時,那麼VM並不能解決你的問題。

然而當由於value佔用空間較大(如佔用空間較多的strings以及含有大量元素的lists, sets 或者 hashes)導致記憶體不足時,那麼VM無疑是一個很好的選擇。

有時你可以通過雜湊表將相關的資料歸組到一個key的相應欄位,從而將“大量key與小儲存的value”的問題轉化為“少量key與大儲存的value”的問題。例如你可以為每一個物件設定一個單獨的key,並用雜湊表的多個欄位代表物件的不同屬性,而非為物件的每一個屬性設定一個單獨的key。

VM 配置

VM的配置相對簡單,可以根據需求設定最佳引數。通過編輯redis.conf來開啟並配置VM。首先開啟VM:

         vm-enabled yes

很多配置項可以改變VM的行為。事實上,為了獲取最佳效能,你常常需要對配置做微調,而非使用預設引數。

vm-max-memory設定

vm-max-memory 指 Redis 在將value交換至磁碟(進行swap操作)之前有多大記憶體可使用。

通常,如果未達到記憶體上限,則不需要進行磁碟交換,Redis將所有物件放在記憶體中操作。然而一旦到達上限,將會有大量的物件被交換出記憶體至磁碟,以釋放記憶體空間,直到低於限制。

交換過程(swap操作)中,首先被交換的物件是那些有著較大“年齡”(指未被訪問的時長)的物件,同時一個物件的“交換能力”(”swappability”)與它在記憶體中大小的對數成正(swappability = age*log(size_in_memory))。當兩個物件有著相同的“年齡”時,佔用空間較大的物件將會首先被交換出去。

提醒:由於key不能被交換出記憶體,所以當僅由於key佔用空間較多而達到記憶體上限時, Redis是不能通過改變 vm-max-memory 來解決問題的。

最好將該值設定到可以用RAM裝載整個資料的工作集(working set)。實際中,當Redis有足夠的記憶體時,交換操作(swap)也將進行的更加順利。

配置swap檔案

Redis利用swap檔案將資料從記憶體轉移到磁碟。swap檔案並不對資料的儲存時間做處理,當一個Redis應用結束時,swap檔案可以被清除。然而,當Redis執行時不能以任何形式移動,刪除或改變 swap檔案。由於Redis的swap檔案通常以隨機讀取的方式被使用,所以用ssd(固態硬碟)儲存swap檔案效能將更好。

swap檔案按“頁”(page)切分。一個值可以被交換(swap)到一個或多個頁中,但是一個頁最多隻能儲存一個值。

沒有直接的方式可以獲取Redis的swap檔案將有多少位元組被使用。然而,可以利用兩個不同的配置引數,將其做乘積計算出使用的位元組總數。這兩個引數分別表示交換檔案的頁數和頁大小,它們可以在redis.conf檔案中配置:

  • vm-pages 用於配置swap檔案中頁的總數
  • vm-page-size 用於配置頁的位元組數

例:如果頁大小被設定為32 byte,同時 頁的總數被設定為1千萬, 則交換檔案總共可以裝載320MB的資料。

由於單頁最多隻能裝載一個value(但是一個value可以被儲存在多個頁上),因此應特別注意這些引數的設定。通常通過改變頁大小來完成設定,這樣可以用少量的頁來完成大部分value的交換。

執行緒式虛擬記憶體 vs 阻塞式虛擬記憶體

另一個重要的配置引數是 vm-max-threads:

         # The default vm-max-threads configuration
                           vm-max-threads 4

該引數用於設定Redis與swap檔案進行I/O的最大執行緒數。通常令其等於系統的cpu核數。

當該引數設定為“0”時,將開啟阻塞式虛擬記憶體。此時,它將以同步阻塞的方式進行I/0. 阻塞式虛擬記憶體有如下特性:

  • 當客戶端從磁碟上讀取被交換出去的key時,將阻塞其他客戶端,所以該方式經歷時延較長,尤其當磁碟較慢或者有大儲存的資料發生交換時。
  • 總體說來,由於在進行同步、增加執行緒和恢復由於等待value而阻塞的客戶端時沒有時間損耗,阻塞式虛擬記憶體表現更好一些。所以如果你能接受偶爾較高的時延,阻塞式虛擬記憶體將是一個好的選擇。尤其在發生交換較少,同時大部分你經常訪問的資料恰好可以放入記憶體時。

相反,如果有大量的換入換出操作時,同時系統有多核可以使用,而你又不希望進行swap操作的客戶端阻塞其他客戶端時(通常幾毫秒,當待交換資料佔用空間較大時,時間會更長),用執行緒式虛擬記憶體效果將更好。我們鼓勵你嘗試用不同的配置做測試。

要知道的一些事情

swap檔案的存放

在很多配置中swap檔案可以很大,達到40GB或者更大。然而並不是所有的檔案系統都可以很好的處理大檔案,尤其是Mac OS X的檔案系統,常常會顯得異常蹩腳。

建議使用 linux ext3檔案系統,或者其他可以很好支援稀疏檔案的檔案系統。

什麼是稀疏檔案?

稀疏檔案指有大量內容為空的檔案。高階一些的檔案系統例如ext2, ext3, ext4,ReiserFS, Reiser4和其他一些檔案 可以用一種更高效的方式編碼這些檔案,同時當檔案有更多的塊(block)需要被使用時,則為該檔案分配更多的空間。

swap檔案很稀疏的。當一次建立一個很大的檔案時,不支援稀疏檔案的檔案系統可能會阻塞Redis程序。

虛擬記憶體的監控

一旦使用了開啟虛擬記憶體的Redis,你可能很感興趣它是怎樣工作的:總共多少個物件被交換,每秒交換與載入的物件量等等。

下面是一個用於檢查VM是如何工作的工具(見此處)。作為Redis 工具的一部分,redis-stat簡單易用:

$ ./redis-stat vmstat
--------------- objects --------------- ------ pages ------ ----- memory -----
load-in  swap-out  swapped   delta      used     delta      used     delta
138837   1078936   800402    +800402    807620   +807620    209.50M  +209.50M
4277     38011     829802    +29400     837441   +29821     206.47M  -3.03M
3347     39508     862619    +32817     870340   +32899     202.96M  -3.51M
4445     36943     890646    +28027     897925   +27585     199.92M  -3.04M
10391    16902     886783    -3863      894104   -3821      200.22M  +309.56K
8888     19507     888371    +1588      895678   +1574      200.05M  -171.81K
8377     20082     891664    +3293      899850   +4172      200.10M  +53.55K
9671     20210     892586    +922       899917   +67        199.82M  -285.30K
10861    16723     887638    -4948      895003   -4914      200.13M  +312.35K
9541     21945     890618    +2980      898004   +3001      199.94M  -197.11K
9689     17257     888345    -2273      896405   -1599      200.27M  +337.77K
10087    18784     886771    -1574      894577   -1828      200.36M  +91.60K
9330     19350     887411    +640       894817   +240       200.17M  -189.72K

上面是一個redis-server 在虛擬記憶體開啟,內部含有大約 1千萬條key,同時利用redis-load 工具做大量模擬負載時的輸出結果。從輸出中你可以看到每秒有大量的“載入”和“交換”操作。請注意第一行顯示從伺服器開啟時到現在的實際數值,下面幾行不同於之前讀取的數值。

如果你分配了足夠的記憶體,可能會看到很多不太明顯的交換,而redis-stat 是一個非常有用的工具,可以幫你判斷是否需要更換RAM了。

開啟虛擬記憶體的Redis :.rdb檔案還是 AOF(Append Only File)檔案更合適 ?

當虛擬記憶體開啟時,儲存和讀取資料庫操作都將變慢。當伺服器被配置為用最少的記憶體時(即vm-max-memory 被設定為0),一個通常2s載入一次的DB操作,在開啟虛擬記憶體時耗時將長達13s,所以你可能希望切換使用AOF的配置來實現持久化,以便可以進行BGREWRITEAOF操作。

請注意 當程序進行 BGSAVE 或者 BGREWRITEAOF 操作時,Redis不會在磁碟上交換新的value.

當有子程序訪問虛擬記憶體時,虛擬記憶體將是隻讀的。所以,當有一個子程序有大量的寫操作時,記憶體使用將增加。

減少使用記憶體

將 vm-max-memory設定為0,可以使Redis轉為僅有key在記憶體中的磁碟資料庫。當你希望使用盡可能少的記憶體儲存大容量數值, 同時不介意時延或者相對糟糕的效能時,這是不錯的選擇。

該設定中你應該首先嚐試著將虛擬記憶體設定為阻塞式(vm-max-threads 0)的。大量的交換入和交換出操作將帶來巨大的開銷,與單執行緒阻塞式虛擬記憶體相比,執行緒式虛擬記憶體將消耗大量的資源 。

虛擬記憶體的穩定性

虛擬記憶體仍處於試驗階段,但在過去的數週裡,它已經以各種方式被應用到開發環境中,甚至一些產品中。目前,在測試階段並沒有發現bug,然而更多不確定的bug可能會在日後某些不可控的環境中發生,而這些環境常常由於一些原因而無法復現。

當前階段,我們鼓勵你在開發過程中嘗試使用虛擬記憶體,甚至在產品中,如果你的db不是至關重要的話。

請報告任何你注意到的問題到the Redis Google Group,或者通過IRC加入 #redis IRC。