閱讀423 返回首頁    go 技術社區[雲棲]


《Redis官方文檔》 redis 虛擬內存

重點提示:
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進程。

參考wikepedia page  了解支持稀疏文件的文件係統。

虛擬內存的監控

一旦使用了開啟虛擬內存的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。

最後更新:2017-05-22 09:31:55

  上一篇:go  Nodejs進階:Express常用中間件body-parser實現解析
  下一篇:go  《Apache Zookeeper 官方文檔》-3 快速指南:使用zookeeper來協調分布式應用