首
先說明下redis的虛擬內(nèi)存與os的虛擬內(nèi)存不是一碼事,但是思路和目的都是相同的。就是暫時(shí)把不經(jīng)常訪問的數(shù)據(jù)從內(nèi)存交換到磁盤中,從而騰出寶貴的 
內(nèi)存空間用于其他需要訪問的數(shù)據(jù)。尤其是對(duì)于redis這樣的內(nèi)存數(shù)據(jù)庫,內(nèi)存總是不夠用的。除了可以將數(shù)據(jù)分割到多個(gè)redis 
server外。另外的能夠提高數(shù)據(jù)庫容量的辦法就是使用vm把那些不經(jīng)常訪問的數(shù)據(jù)交換的磁盤上。如果我們的存儲(chǔ)的數(shù)據(jù)總是有少部分?jǐn)?shù)據(jù)被經(jīng)常訪問,大
 部分?jǐn)?shù)據(jù)很少被訪問,對(duì)于網(wǎng)站來說確實(shí)總是只有少量用戶經(jīng)?;钴S。當(dāng)少量數(shù)據(jù)被經(jīng)常訪問時(shí),使用vm不但能提高單臺(tái)redis 
server數(shù)據(jù)庫的容量,而且也不會(huì)對(duì)性能造成太多影響。
        redis沒有使用os提供的虛擬內(nèi)存機(jī)制而是自己在用戶態(tài)實(shí)現(xiàn)了自己的虛擬內(nèi)存機(jī)制,作者在自己的blog專門解釋了其中原因。http:///post/redis-virtual-memory-story.html
主要的理由有兩點(diǎn)
1.os
 
的虛擬內(nèi)存是已4k頁面為最小單位進(jìn)行交換的。而redis的大多數(shù)對(duì)象都遠(yuǎn)小于4k,所以一個(gè)os頁面上可能有多個(gè)redis對(duì)象。另外redis的集
 
合對(duì)象類型如list,set可能存在與多個(gè)os頁面上。最終可能造成只有10%key被經(jīng)常訪問,但是所有os頁面都會(huì)被os認(rèn)為是活躍的,這樣只有內(nèi)
 存真正耗盡時(shí)os才會(huì)交換頁面。
2.相比于os的交換方式。redis可以將被交換到磁盤的對(duì)象進(jìn)行壓縮,保存到磁盤的對(duì)象可以去除指針和對(duì)象元數(shù)據(jù)信息。一般壓縮后的對(duì)象會(huì)比內(nèi)存中的對(duì)象小10倍。這樣redis的vm會(huì)比os vm能少做很多io操作。
下面是vm相關(guān)配置
vm-enabled yes                          #開啟vm功能
vm-swap-file /tmp/redis.swap                 #交換出來的value保存的文件路徑/tmp/redis.swap
vm-max-memory 1000000                    #redis使用的最大內(nèi)存上限,超過上限后redis開始交換value到磁盤文件中。
vm-page-size 32                    #每個(gè)頁面的大小32個(gè)字節(jié)
vm-pages 134217728                 #最多使用在文件中使用多少頁面,交換文件的大小 = vm-page-size * vm-pages
vm-max-threads 4                    #用于執(zhí)行value對(duì)象換入換出的工作線程數(shù)量。0表示不使用工作線程(后面介紹)
      
 redis的vm在設(shè)計(jì)上為了保證key的查找速度,只會(huì)將value交換到swap文件中。所以如果是內(nèi)存問題是由于太多value很小的key造成
 
的,那么vm并不能解決。和os一樣redis也是按頁面來交換對(duì)象的。redis規(guī)定同一個(gè)頁面只能保存一個(gè)對(duì)象。但是一個(gè)對(duì)象可以保存在多個(gè)頁面中。
 
在redis使用的內(nèi)存沒超過vm-max-memory之前是不會(huì)交換任何value的。當(dāng)超過最大內(nèi)存限制后,redis會(huì)選擇較老的對(duì)象。如果兩個(gè)
 對(duì)象一樣老會(huì)優(yōu)先交換比較大的對(duì)象,精確的公式swappability = age*log(size_in_memory)。 
對(duì)于vm-page-size的設(shè)置應(yīng)該根據(jù)自己的應(yīng)用將頁面的大小設(shè)置為可以容納大多數(shù)對(duì)象的大小。太大了會(huì)浪費(fèi)磁盤空間,太小了會(huì)造成交換文件出現(xiàn)碎
 片。對(duì)于交換文件中的每個(gè)頁面,redis會(huì)在內(nèi)存中對(duì)應(yīng)一個(gè)1bit值來記錄頁面的空閑狀態(tài)。所以像上面配置中頁面數(shù)量(vm-pages 
134217728 
)會(huì)占用16M內(nèi)存用來記錄頁面空閑狀態(tài)。vm-max-threads表示用做交換任務(wù)的線程數(shù)量。如果大于0推薦設(shè)為服務(wù)器的cpu 
core的數(shù)量。如果是0則交換過程在主線程進(jìn)行。
參數(shù)配置討論完后,在來簡(jiǎn)單介紹下vm是如何工作的,
當(dāng)vm-max-threads設(shè)為0時(shí)(Blocking VM)
換出
主線程定期檢查發(fā)現(xiàn)內(nèi)存超出最大上限后,會(huì)直接已阻塞的方式,將選中的對(duì)象保存到swap文件中,并釋放對(duì)象占用的內(nèi)存,此過程會(huì)一直重復(fù)直到下面條件滿足
1.內(nèi)存使用降到最大限制以下
2.swap文件滿了
3.幾乎全部的對(duì)象都被交換到磁盤了
換入
當(dāng)有client請(qǐng)求value被換出的key時(shí)。主線程會(huì)以阻塞的方式從文件中加載對(duì)應(yīng)的value對(duì)象,加載時(shí)此時(shí)會(huì)阻塞所以client。然后處理client的請(qǐng)求
當(dāng)vm-max-threads大于0(Threaded VM)
(去掉其它程序的干擾(因?yàn)槟愕某绦蚩赡苷加昧舜蟛糠值腃PU資源),在單CPU單核的機(jī)器上,是兩個(gè)線程串行的進(jìn)行時(shí)間片的占用,而在雙核當(dāng)中,雖然也是分享時(shí)間片,但是當(dāng)A線程在執(zhí)行的時(shí)候,B線程還可以在另一個(gè)核心上執(zhí)行,所以在很多時(shí)間里面,他們幾乎是完全并行的。)
換出
當(dāng)主線程檢測(cè)到使用內(nèi)存超過最大上限,會(huì)將選中的要交換的對(duì)象信息放到一個(gè)隊(duì)列中交由工作線程后臺(tái)處理,主線程會(huì)繼續(xù)處理client請(qǐng)求。
換入
如果有client請(qǐng)求的key被換出了,主線程先阻塞發(fā)出命令的client,然后將加載對(duì)象的信息放到一個(gè)隊(duì)列中,讓工作線程去加載。加載完畢后工作線程通知主線程。主線程再執(zhí)行client的命令。這種方式只阻塞請(qǐng)求value被換出key的client
總
 的來說blocking 
vm的方式總的性能會(huì)好一些,因?yàn)椴恍枰€程同步,創(chuàng)建線程和恢復(fù)被阻塞的client等開銷。但是也相應(yīng)的犧牲了響應(yīng)性。threaded 
vm的方式主線程不會(huì)阻塞在磁盤io上,所以響應(yīng)性更好。如果我們的應(yīng)用不太經(jīng)常發(fā)生換入換出,而且也不太在意有點(diǎn)延遲的話則推薦使用blocking 
vm的方式。關(guān)于redis vm的更詳細(xì)介紹可以參考下面鏈接
http:///post/redis-virtual-memory-story.html
http:///topics/internals-vm
from:http://www.cnblogs.com/xhan/archive/2011/02/07/1949717.html