Memcached深入分析及內存調優


到這里memcached的初步使用我們已經沒問題了,但是了解一些它內部的機制還是十分必要的,這直接涉及到你能否把memcached給真正“用好”。

Memcached的守護進程機制使用的是Unix下的daemon,Socket則使用了非阻塞(non-blocked)高性能的NIO,事件處理上大家都已經知道了,是基於libevent,支持異步的事件處理。

最主要的是要知道它的內存管理機制,使用如下命令啟動memcached:

  1. liyd@ubuntu:~$ memcached -d -m256 -p11211 -u liyd

這里我們分配了256M的內存給memcached,那么memcached又是怎么樣來分配內存的呢?先看下圖:

QQ圖片20150427203745

Memcached在分配內存時是以Page為單位的,默認情況下一個Page是1M,內部是一個個chunk,當chunk的大小等於Page大小時也就是Memcached所能存儲的最大數據大小了,可以在啟動時通過-l來指定它,最大可以支持128M。

Memcached並不是將所有大小的數據都存放在一起的,而是將內存空間划分為一個個的slab,每個slab只負責一定范圍內的數據。上圖中,slab1只負責96bytes的數據,slab2負責120bytes的數據。

在存儲數據時,如果這個item對應的slab還沒有創建則申請一個page的內存,將這個page按照所在slab中chunk的大小進行分割,然后將item存入。

如果已經創建存在了,判斷對應的slab是否用完,沒用完直接存儲。

如果對應的slab已經用完了,看內存是否用完,沒用完會申請一個新的page進行分割存儲,用完了則直接進行LRU。

那么我們怎么樣來查看各個slab的狀況及里面的chunk大小呢?

在前面的啟動參數中我們發現有-v –vv -vvv三個選項,一般我們用的最多的是-vv:

  1. liyd@ubuntu:~$ memcached -d -m256 -p11211 -u liyd -vv
  2. liyd@ubuntu:~$ slab class 1: chunk size 96 perslab 10922
  3. slab class 2: chunk size 120 perslab 8738
  4. slab class 3: chunk size 152 perslab 6898
  5. slab class 4: chunk size 192 perslab 5461
  6. slab class 5: chunk size 240 perslab 4369
  7. slab class 6: chunk size 304 perslab 3449
  8. slab class 7: chunk size 384 perslab 2730
  9. slab class 8: chunk size 480 perslab 2184
  10. slab class 9: chunk size 600 perslab 1747
  11. slab class 10: chunk size 752 perslab 1394
  12. slab class 11: chunk size 944 perslab 1110
  13. slab class 12: chunk size 1184 perslab 885
  14. slab class 13: chunk size 1480 perslab 708
  15. slab class 14: chunk size 1856 perslab 564
  16. slab class 15: chunk size 2320 perslab 451
  17. slab class 16: chunk size 2904 perslab 361
  18. slab class 17: chunk size 3632 perslab 288
  19. slab class 18: chunk size 4544 perslab 230
  20. slab class 19: chunk size 5680 perslab 184
  21. slab class 20: chunk size 7104 perslab 147
  22. slab class 21: chunk size 8880 perslab 118
  23. slab class 22: chunk size 11104 perslab 94
  24. slab class 23: chunk size 13880 perslab 75
  25. slab class 24: chunk size 17352 perslab 60
  26. slab class 25: chunk size 21696 perslab 48
  27. slab class 26: chunk size 27120 perslab 38
  28. slab class 27: chunk size 33904 perslab 30
  29. slab class 28: chunk size 42384 perslab 24
  30. slab class 29: chunk size 52984 perslab 19
  31. slab class 30: chunk size 66232 perslab 15
  32. slab class 31: chunk size 82792 perslab 12
  33. slab class 32: chunk size 103496 perslab 10
  34. slab class 33: chunk size 129376 perslab 8
  35. slab class 34: chunk size 161720 perslab 6
  36. slab class 35: chunk size 202152 perslab 5
  37. slab class 36: chunk size 252696 perslab 4
  38. slab class 37: chunk size 315872 perslab 3
  39. slab class 38: chunk size 394840 perslab 2
  40. slab class 39: chunk size 493552 perslab 2
  41. slab class 40: chunk size 616944 perslab 1
  42. slab class 41: chunk size 771184 perslab 1
  43. slab class 42: chunk size 1048576 perslab 1
  44. <26 server listening (auto-negotiate)
  45. <27 send buffer was 212992, now 268435456
  46. <28 send buffer was 212992, now 268435456
  47. <27 server listening (udp)
  48. <28 server listening (udp)
  49. <27 server listening (udp)
  50. <28 server listening (udp)
  51. <27 server listening (udp)
  52. <28 server listening (udp)
  53. <27 server listening (udp)
  54. <28 server listening (udp)

我們看到,一共有42個slab,第一個slab中chunk大小為96bytes,第二個為120bytes,第三個為152bytes,每個slab中chunk的大小都不一樣,這個chunk就是memcached具體存儲數據的地方。

Memcached通過指定的成長因子(-f指定,默認1.25倍)來決定每個slab中chunk增長的范圍,第一個slab的大小可以通過-n來設定。

當數據進來時Memcached會選擇一個大於等於最接近的slab來進行存儲。例如當item大小為95時將存儲到chunk為96bytes的slab1,item大小為97時則會存儲到chunk大小為120的slab2.

這樣分配的好處是速度快,避免大量重復的初始化和清理操作,有效的避免了內存碎片的問題,但內存利用率上會有所浪費。

另外Memcached是懶檢測機制,當存儲在內存中的對象過期甚至是flush_all時,它並不會做檢查或刪除操作,只有在get時才檢查數據對象是否應該刪除。

刪除數據時,Memcached同樣是懶刪除機制,只在對應的數據對象上做刪除標識並不回收內存,在下次分配時直接覆蓋使用。

了解了Memcached的內存分配機制,如何進行調優是不是自然而然的就明白了?

應該盡量的根據實際情況來設定slab的chunk的初始大小和增長因子,盡量減少內存的浪費。在某些情況下數據的長度都會集中在一個區域,如session。甚至會有定長的情況,如數據統計等。

還有一個重要調優的地方就是提高緩存命中率了,這個沒有固定的方法,還得具體場景做具體業務分析,需要注意的就是,Memcached中LRU的操作是基於slab而非全局,分析時最好考慮這一點,這也就是有時候內存還沒用完但數據卻被回收了的原因。

我們也可以借助類似memcached-tool這類對memcache的狀態性能分析工具來更直觀的查看memcache內部的狀態,但是功能上也比較有限,就不細講了,主要就是以下幾個命令:

  1. #memcached-tool
  2. #Usage: memcached-tool <host[:port]> [mode]
  3. memcached-tool 127.0.0.1:11211 display # shows slabs
  4. memcached-tool 127.0.0.1:11211 # same. (default is display)
  5. memcached-tool 127.0.0.1:11211 stats # shows general stats
  6. memcached-tool 127.0.0.1:11211 dump # dumps keys and value

現在我們再回過頭去看Memcached的stats命令,是不是就很有用了?這里貼上常用的一些參數說明。

stats統計項:

  1. pid Memcached進程ID
  2. uptime Memcached運行時間,單位:秒
  3. time Memcached當前的UNIX時間
  4. version Memcached的版本號
  5. rusage_user 該進程累計的用戶時間,單位:秒
  6. rusage_system 該進程累計的系統時間,單位:秒
  7. curr_connections 當前連接數量
  8. total_connections Memcached運行以來接受的連接總數
  9. connection_structures Memcached分配的連接結構的數量
  10. cmd_get 查詢請求總數
  11. get_hits 查詢成功獲取數據的總次數
  12. get_misses 查詢成功未獲取到數據的總次數
  13. cmd_set 存儲(添加/更新)請求總數
  14. bytes Memcached當前存儲內容所占用字節數
  15. bytes_read Memcached從網絡讀取到的總字節數
  16. bytes_written Memcached向網絡發送的總字節數
  17. limit_maxbytes Memcached在存儲時被允許使用的字節總數
  18. curr_items Memcached當前存儲的內容數量
  19. total_items Memcached啟動以來存儲過的內容總數
  20. evictions LRU釋放對象數,用來釋放內存

stats slabs區塊統計:

  1. chunk_size chunk大小,byte
  2. chunks_per_page 每個pagechunk數量
  3. total_pages page數量
  4. total_chunks chunk數量*page數量
  5. get_hits get命中數
  6. cmd_set set
  7. delete_hits delete命中數
  8. incr_hits incr命中數
  9. decr_hits decr命中數
  10. cas_hits cas命中數
  11. cas_badval cas數據類型錯誤數
  12. used_chunks 已被分配的chunk
  13. free_chunks 剩余chunk
  14. free_chunks_end 分完page浪費chunk
  15. mem_requested 請求存儲的字節數
  16. active_slabs slab數量
  17. total_malloced 總內存數量

被浪費內存數=(total_chunks * chunk_size) - mem_requested,如果太大,則需要調整factor

stats items數據項統計:

  1. number slab中對象數,不包含過期對象
  2. age LRU隊列中最老對象的過期時間
  3. evicted LRU釋放對象數
  4. evicted_nonzero 設置了非0時間的LRU釋放對象數
  5. evicted_time 最后一次LRU秒數,監控頻率
  6. outofmemory 不能存儲對象次數,使用-M會報錯
  7. tailrepairs 修復slabs次數
  8. reclaimed 使用過期對象空間存儲對象次數

stats settings查看設置:

  1. maxbytes 最大字節數限制,0無限制
  2. maxconns 允許最大連接數
  3. tcpport TCP端口
  4. udpport UDP端口
  5. verbosity 日志0=none,1=som,2=lots
  6. oldest 最老對象過期時間
  7. evictions on/off,是否禁用LRU
  8. domain_socket socketdomain
  9. umask 創建Socket時的umask
  10. growth_factor 增長因子
  11. chunk_size key+value+flags大小
  12. num_threads 線程數,可以通過-t設置,默認4
  13. stat_key_prefix stats分隔符
  14. detail_enabled yes/no,顯示stats細節信息
  15. reqs_per_event 最大IO吞吐量(每event)
  16. cas_enabled yes/no,是否啟用CAS,-C禁用
  17. tcp_backlog TCP監控日志
  18. auth_enabled_sasl yes/no,是否啟用SASL驗證

 

查看key和value

1. cmd上登錄memcache

 telnet 127.0.0.1 11211

退出 quit

2. 列出所有keys

stats items

3. 通過itemid獲取key

接下來基於列出的items id,本例中為7,第2個參數為列出的長度,0為全部列出

 stats cachedump 7 0

4. 通過get獲取key值

上面的stats cachedump命令列出了我的session key,接下來就用get命令查找對應的session值


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM