423
技術社區[雲棲]
《Redis官方文檔》 redis 虛擬內存
虛擬內存
Redis 虛擬內存這一特性將首次出現在Redis 2.0的一個穩定發布版中。目前Git上Redis 不穩定分支的虛擬內存(從現在起稱之為VM)已經可以使用,並且經試驗證明足夠穩定。
簡介
實際應用中,如果內存中有一個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