memcache不會釋放內存,而是重新利用。
在緩存的清除方面,memcache是不釋放已分配內存。當已分配的內存所在的記錄失效后,這段以往的內存空間,memcache只會重復利用。
memcached的內存回收機制不是說你設置的key到了生命周期就自動從內存中清除的,這個時候必須有一個新的對象入駐請求這個大小的chunk或者 這個過期的對象被get的時候才會清除。
STAT 1:chunk_size 80 STAT 1:chunks_per_page 13107 STAT 1:total_pages 1 STAT 1:total_chunks 13107 STAT 1:used_chunks 13107 STAT 1:free_chunks 0 STAT 1:free_chunks_end 13107 STAT 2:chunk_size 100 STAT 2:chunks_per_page 10485 STAT 2:total_pages 1 STAT 2:total_chunks 10485 STAT 2:used_chunks 10485 STAT 2:free_chunks 0 STAT 2:free_chunks_end 10485 STAT 3:chunk_size 128 STAT 3:chunks_per_page 8192 STAT 3:total_pages 1 STAT 3:total_chunks 8192 STAT 3:used_chunks 8192 STAT 3:free_chunks 0 STAT 3:free_chunks_end 8192
以上就是前3個slab得詳細信息
chunk_size表示數據存放塊得大小,chunks_per_page表示一個內存頁page中擁有得chunk得數 量,total_pages表示每個slab下page得個數。total_chunks表示這個slab下chunk得總數(=total_pages * chunks_per_page),used_chunks表示該slab下已經使用得chunk得數量,free_chunks表示該slab下還可以 使用得chunks數量。
從上面得示例slab 1一共有1m得內存空間,而且現在已經被用完了,slab2也有1m得內存空間,也被用完了,slab3得情況依然如此。 而且從這3個slab中chunk得size可以看出來,第一個chunk為80b,第二個是100b,第3個是128b,基本上后一個是前一個得 1.25倍,但是這個增長情況我們是可以控制得,我們可以通過在啟動時得進程參數 –f來修改這個值,比如說 –f 1.1表示這個增長因子為1.1,那么第一個slab中得chunk為80b得話,第二個slab中得chunk應該是80*1.1左右。
解釋了這么多也該可以看出來我遇到得問題得原因了,如果還看不出來,那我再補充關鍵的一句:memcached中新的value過來存放的地址是 該value的大小決定的,value總是會被選擇存放到chunk與其最接近的一個slab中,比如上面的例子,如果我的value是80b,那么我這 所有的value總是會被存放到1號slab中,而1號slab中的free_chunks已經是0了,怎么辦呢,如果你在啟動memcached的時候 沒有追加-M(禁止LRU,這種情況下內存不夠時會out of memory),那么memcached會把這個slab中最近最少被使用的chunk中的數據清掉,然后放上最新的數據。這就解釋了為什么我的內存還有 40%的時候LRU就執行了,因為我的其他slab中的chunk_size都遠大於我的value,所以我的value根本不會放到那幾個slab中, 而只會放到和我的value最接近的chunk所在的slab中(而這些slab早就滿了,郁悶了)。這就導致了我的數據被不停的覆蓋,后者覆蓋前者。
問題找到了,解決方案還是沒有找到,因為我的數據必須要求命中率時100%,我只能通過調整slab的增長因子和page的大小來盡量來使命中率 接近100%,但是並不能100%保證命中率是100%(這話怎么讀起來這么別扭呢,自我檢討一下自己的語文水平),如果您說,這種方案不行啊,因為我的 memcached server不能停啊,不要緊還有另外一個方法,就是memcached-tool,執行move命令,如:move 3 1,代表把3號slab中的一個內存頁移動到1號slab中,有人問了,這有什么用呢,比如說我的20號slab的利用率非常低,但是page卻又很多, 比如200,那么就是200m,而2好slab經常發生LRU,明顯page不夠,我就可以move 20 2,把20號slab的一個內存頁移動到2號slab上,這樣就能更加有效的利用內存了(有人說了,一次只移動一個page,多麻煩啊?ahuaxuan 說,還是寫個腳本,循環一下吧)。
有人說不行啊,我的memcache中的數據不能丟失啊,ok,試試新浪的memcachedb吧,雖然我沒有用過,但是建議大家可以試試,它也使利用 memcache協議和berkeleyDB做的(寫到這里,我不得不佩服danga了,我覺得它最大的貢獻不是memcache server本身,而是memcache協議),據說它被用在新浪的不少應用上,包括新浪的博客。
補充,stats slab命令可以查看memcached中slab的情況,而stats命令可以查看你的memcached的一些健康情況,比如說命中率之類的,示例如下:
STAT pid 2232 STAT uptime 1348 STAT time 1218120955 STAT version 1.2.1 STAT pointer_size 32 STAT curr_items 0 STAT total_items 0 STAT bytes 0 STAT curr_connections 1 STAT total_connections 3 STAT connection_structures 2 STAT cmd_get 0 STAT cmd_set 0 STAT get_hits 0 STAT get_misses 0 STAT bytes_read 26 STAT bytes_written 16655 STAT limit_maxbytes 104857600
從上面的數據可以看到這個memcached進程的命中率很好,get_misses低達0個,怎么回事啊,因為這個進程使我剛啟動的,我只用 telnet連了一下,所以curr_connections為1,而total_items為0,因為我沒有放數據進去,get_hits為0,因為我 沒有調用get方法,最后的結果就是misses當然為0,哇哦,換句話說命中率就是100%,又yy了。
該到總結的時候了,從這篇文章里我們可以得到以下幾個結論:
結論一,memcached得LRU不是全局的,而是針對slab的,可以說是區域性的。
結論二,要提高memcached的命中率,預估我們的value大小並且適當的調整內存頁大小和增長因子是必須的。
結論三,帶着問題找答案理解的要比隨便看看的效果好得多。
參考:http://ahuaxuan.iteye.com/blog/225692