<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    yeshucheng
    追逐自己,追逐方向,心隨悟所動
    posts - 24,comments - 24,trackbacks - 0
    Memcached,人所皆知的remote distribute cache(不知道的可以javaeye一下下,或者google一下下,或者baidu一下下,但是鑒于baidu的排名商業味道太濃(從最近得某某事件可以看出),所以還是建議javaeye一下下),使用起來也非常的簡單,它被用在了很多網站上面,幾乎很少有大型的網站不會使用memcached。

    曾經我也看過很多剖析memcached內部機制的文章,有一點收獲,但是看過之后又忘記了,而且沒有什么深刻的概念,但是最近我遇到一個問題,這個問題迫使我重新來認識memcache,下面我闡述一下我遇到的問題

    問題:我有幾千萬的數據,這些數據會經常被用到,目前來看,它必須要放到memcached中,以保證訪問速度,但是我的memcached中數據經常會有丟失,而業務需求是memcached中的數據是不能丟失的。我的數據丟失的時候,memcached server的內存才使用到60%,也就是還有40%內存被嚴重的浪費掉了。但不是所有的應用都是這樣,其他應用內存浪費的就比較少。為什么內存才使用到60%的時候LRU就執行了呢(之所以確定是LRU執行是因為我發現我的數據丟失的總是前面放進去的,而且這個過程中,這些數據都沒有被訪問,比如第一次訪問的時候,只能訪問第1000w條,而第300w條或者之前的數據都已經丟失了,從日志里看,第300w條肯定是放進去了)。

    帶著這些疑問,我開始重新審視memcached這個產品,首先從它的內存模型開始:我們知道c++里分配內存有兩種方式,預先分配和動態分配,顯然,預先分配內存會使程序比較快,但是它的缺點是不能有效利用內存,而動態分配可以有效利用內存,但是會使程序運行效率下降,memcached的內存分配就是基于以上原理,顯然為了獲得更快的速度,有時候我們不得不以空間換時間。

    也就是說memcached會預先分配內存,對了,memcached分配內存方式稱之為allocator,首先,這里有3個概念:
    1 slab
    2 page
    3 chunk
    解釋一下,一般來說一個memcahced進程會預先將自己劃分為若干個slab,每個slab下又有若干個page,每個page下又有多個chunk,如果我們把這3個咚咚看作是object得話,這是兩個一對多得關系。再一般來說,slab得數量是有限得,幾個,十幾個,或者幾十個,這個跟進程配置得內存有關。而每個slab下得page默認情況是1m,也就是說如果一個slab占用100m得內存得話,那么默認情況下這個slab所擁有得page得個數就是100,而chunk就是我們得數據存放得最終地方。

    舉一個例子,我啟動一個memcached進程,占用內存100m,再打開telnet,telnet localhost 11211,連接上memcache之后,輸入stats  slabs,回車,出現如下數據:
    Java代碼 復制代碼
    1. STAT 1:chunk_size 80  
    2. STAT 1:chunks_per_page 13107  
    3. STAT 1:total_pages 1  
    4. STAT 1:total_chunks 13107  
    5. STAT 1:used_chunks 13107  
    6. STAT 1:free_chunks 0  
    7. STAT 1:free_chunks_end 13107  
    8. STAT 2:chunk_size 100  
    9. STAT 2:chunks_per_page 10485  
    10. STAT 2:total_pages 1  
    11. STAT 2:total_chunks 10485  
    12. STAT 2:used_chunks 10485  
    13. STAT 2:free_chunks 0  
    14. STAT 2:free_chunks_end 10485  
    15. STAT 3:chunk_size 128  
    16. STAT 3:chunks_per_page 8192  
    17. STAT 3:total_pages 1  
    18. STAT 3:total_chunks 8192  
    19. STAT 3:used_chunks 8192  
    20. STAT 3:free_chunks 0  
    21. 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的一些健康情況,比如說命中率之類的,示例如下:
    Java代碼 復制代碼
    1. STAT pid 2232  
    2. STAT uptime 1348  
    3. STAT time 1218120955  
    4. STAT version 1.2.1  
    5. STAT pointer_size 32  
    6. STAT curr_items 0  
    7. STAT total_items 0  
    8. STAT bytes 0  
    9. STAT curr_connections 1  
    10. STAT total_connections 3  
    11. STAT connection_structures 2  
    12. STAT cmd_get 0  
    13. STAT cmd_set 0  
    14. STAT get_hits 0  
    15. STAT get_misses 0  
    16. STAT bytes_read 26  
    17. STAT bytes_written 16655  
    18. 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大小并且適當的調整內存頁大小和增長因子是必須的。
    結論三,帶著問題找答案理解的要比隨便看看的效果好得多。
    posted on 2010-08-17 17:45 葉澍成 閱讀(228) 評論(0)  編輯  收藏 所屬分類: 分布式
    主站蜘蛛池模板: 国产乱人免费视频| 99re免费在线视频| 国产成人亚洲综合色影视| 最好看最新的中文字幕免费| 美女免费视频一区二区| 亚洲高清视频在线观看| 久久影院亚洲一区| 在线观看人成网站深夜免费| AAAAA级少妇高潮大片免费看| 国产精品亚洲专区在线观看 | 久久亚洲国产最新网站| 久久精品国产亚洲av成人| 成人性生交大片免费看好| 亚洲啪啪免费视频| 亚洲黄网在线观看| 亚洲国产精品lv| 亚洲视频.com| 亚洲一本综合久久| 亚洲AV无码一区二区三区系列| jizzjizz亚洲| 亚洲精品国产电影| 亚洲精品午夜无码专区| 亚洲中文字幕在线第六区| 国产亚洲成人久久| 亚洲成a人片77777kkkk| 亚洲国产一区在线| 天天爽亚洲中文字幕| 亚洲人成电影网站免费| 国产亚洲精品国产福利在线观看| 国产一区二区三区亚洲综合| 一级毛片**免费看试看20分钟 | 精品亚洲福利一区二区| 亚洲欧美日韩综合久久久久| 国产精品亚洲精品爽爽| 中文字幕永久免费视频| 在线永久免费的视频草莓| 国产精品无码一二区免费| 亚洲人成人一区二区三区| 亚洲AV无码精品蜜桃| 亚洲精品国产日韩无码AV永久免费网 | 亚洲中文字幕无码一区|