五、Memcached深入分析及内存调优

【转载自】http://hi.baidu.com/mouhainy/blog/item/a3b2bf3377fa02fd1b4cfffc.html

到这里memcached的初步使用我们已经没问题了,但是了解一些它内部的机制还是十分必要的,这直接涉及到你能否把memcached给真正“用好”。

Memcached的守护进程机制使用的是Unix下的daemon,Socket则使用了非阻塞(non-blocked)高性能的NIO,事件处理上大家都已经知道了,是基于libevent,支持异步的事件处理。

最主要的是要知道它的内存管理机制,使用如下命令启动memcached:

# /usr/local/memcached/bin/memcached -d -u root -p 11211 -vv

这里我们分配了默认的内存64M的内存给memcached,那么memcached又是怎么样来分配内存的呢?先看下图:


Memcached在分配内存时是以Page为单位的,默认情况下一个Page是1M,内部是一个个chunk,当chunk的大小等于Page大小时也就是Memcached所能存储的最大数据大小了,可以在启动时通过-l来指定它。

Memcached并不是将所有大小的数据都存放在一起的,而是将内存空间划分为一个个的slab,每个slab只负责一定范围内的数据。上图中,slab1只负责96bytes的数据,slab2负责120bytes的数据。

在存储数据时,如果这个item对应的slab还没有创建则申请一个page的内存,将这个page按照所在slab中chunk的大小进行分割,然后将item存入。

如果已经创建存在了,判断对应的slab是否用完,没用完直接存储。

如果对应的slab已经用完了,看内存是否用完,没用完会申请一个新的page进行分割存储,用完了则直接进行LRU。

那么我们怎么样来查看各个slab的状况及里面的chunk大小呢?

在前面的启动参数中我们发现有-v –vv -vvv三个选项,一般我们用的最多的是-vv:

[root@iZ25bep053pZ ~]# /usr/local/memcached/bin/memcached -d -u root -p 11211 -vv
[root@iZ25bep053pZ ~]# slab class   1: chunk size    104 perslab 10082
slab class   2: chunk size    136 perslab  7710
slab class   3: chunk size    176 perslab  5957
slab class   4: chunk size    224 perslab  4681
slab class   5: chunk size    280 perslab  3744
slab class   6: chunk size    352 perslab  2978
slab class   7: chunk size    440 perslab  2383
slab class   8: chunk size    552 perslab  1899
slab class   9: chunk size    696 perslab  1506
slab class  10: chunk size    872 perslab  1202
slab class  11: chunk size   1096 perslab   956
slab class  12: chunk size   1376 perslab   762
slab class  13: chunk size   1720 perslab   609
slab class  14: chunk size   2152 perslab   487
slab class  15: chunk size   2696 perslab   388
slab class  16: chunk size   3376 perslab   310
slab class  17: chunk size   4224 perslab   248
slab class  18: chunk size   5280 perslab   198
slab class  19: chunk size   6600 perslab   158
slab class  20: chunk size   8256 perslab   127
slab class  21: chunk size  10320 perslab   101
slab class  22: chunk size  12904 perslab    81
slab class  23: chunk size  16136 perslab    64
slab class  24: chunk size  20176 perslab    51
slab class  25: chunk size  25224 perslab    41
slab class  26: chunk size  31536 perslab    33
slab class  27: chunk size  39424 perslab    26
slab class  28: chunk size  49280 perslab    21
slab class  29: chunk size  61600 perslab    17
slab class  30: chunk size  77000 perslab    13
slab class  31: chunk size  96256 perslab    10
slab class  32: chunk size 120320 perslab     8
slab class  33: chunk size 150400 perslab     6
slab class  34: chunk size 188000 perslab     5
slab class  35: chunk size 235000 perslab     4
slab class  36: chunk size 293752 perslab     3
slab class  37: chunk size 367192 perslab     2
slab class  38: chunk size 458992 perslab     2
<6 server listening (replication)
replication: listen
<7 server listening
<8 server listening
<9 send buffer was 212992, now 268435456
<9 server listening (udp)
<10 send buffer was 212992, now 268435456
<10 server listening (udp)

我们看到,一共有38个slab,第一个slab中chunk大小为104bytes,第二个为136bytes,第三个为176bytes,每个slab中chunk的大小都不一样,这个chunk就是memcached具体存储数据的地方。

Memcached通过指定的成长因子(-f指定,默认1.25倍)来决定每个slab中chunk增长的范围,第一个slab的大小可以通过-n来设定。

当数据进来时Memcached会选择一个大于等于最接近的slab来进行存储。例如当item大小为100时将存储到chunk为104bytes的slab1,item大小为110时则会存储到chunk大小为136的slab2.

这样分配的好处是速度快,避免大量重复的初始化和清理操作,有效的避免了内存碎片的问题,但内存利用率上会有所浪费。典型的拿空间换效率,如图所示:


另外Memcached是懒检测机制,当存储在内存中的对象过期甚至是flush_all时,它并不会做检查或删除操作,只有在get时才检查数据对象是否应该删除。

删除数据时,Memcached同样是懒删除机制,只在对应的数据对象上做删除标识并不回收内存,在下次分配时直接覆盖使用。

了解了Memcached的内存分配机制,如何进行调优是不是自然而然的就明白了?

应该尽量的根据实际情况来设定slab的chunk的初始大小和增长因子,尽量减少内存的浪费。在某些情况下数据的长度都会集中在一个区域,如session。甚至会有定长的情况,如数据统计等。

还有一个重要调优的地方就是提高缓存命中率了,这个没有固定的方法,还得具体场景做具体业务分析,需要注意的就是,Memcached中LRU的操作是基于slab而非全局,分析时最好考虑这一点,这也就是有时候内存还没用完但数据却被回收了的原因。

现在我们再回过头去看Memcached的stats命令,是不是就很有用了?这里贴上常用的一些参数说明。

stats统计项:

STAT pid 22438               memcache服务器的进程ID  
STAT uptime 2642             服务器已经运行的秒数     
STAT time 1488435021         服务器当前的unix时间戳  
STAT version 1.2.8           memcache版本  
STAT pointer_size 64         当前操作系统的指针大小(32位系统一般是32bit,64就是64位操作系统)  
STAT rusage_user 0.033049    进程的累计用户时间  
STAT rusage_system 0.066099  进程的累计系统时间  
STAT curr_items 0            当前存储的数据总数  
STAT total_items 0           启动以来存储的数据总数  
STAT bytes 0                 当前存储占用的字节数  
STAT curr_connections 5      当前打开着的连接数  
STAT total_connections 8     从服务器启动以后曾经打开过的连接数  
STAT connection_structures 6 服务器分配的连接构造数  
STAT cmd_flush 0             flush命令请求次数  
STAT cmd_get 0               get命令(获取)总请求次数  
STAT cmd_set 0               set命令(保存)总请求次数  
STAT get_hits 0              总命中次数  
STAT get_misses 0            总未命中次数  
STAT evictions 0             为获取空闲内存而删除的items数(分配给memcache的空间用满后需要删除旧的items来得到空间分配给新的items)  
STAT bytes_read 30           总读取字节数(请求字节数)  
STAT bytes_written 1240      总发送字节数(结果字节数)  
STAT limit_maxbytes 67108864 分配给memcache的内存大小(字节)  
STAT threads 2               当前线程数  
STAT accepting_conns 1       服务器是否达到过最大连接  
STAT listen_disabled_num 0   失效的监听数  
STAT replication MASTER    
STAT repcached_version 2.2  
STAT repcached_qi_free 8192  
END 

stats slabs区块统计:

chunk_size                   chunk大小,byte
chunks_per_page              每个page的chunk数量
total_pages                  page数量
total_chunks                 chunk数量*page数量
get_hits                     get命中数
cmd_set                      set数
delete_hits                  delete命中数
incr_hits                    incr命中数
decr_hits                    decr命中数
cas_hits                     cas命中数
cas_badval                   cas数据类型错误数
used_chunks                  已被分配的chunk数
free_chunks                  剩余chunk数
free_chunks_end              分完page浪费chunk数
mem_requested                请求存储的字节数
active_slabs                 slab数量
total_malloced               总内存数量

被浪费内存数=(total_chunks * chunk_size) - mem_requested,如果太大,则需要调整factor

stats items数据项统计:

number                       该slab中对象数,不包含过期对象
age                          LRU队列中最老对象的过期时间
evicted                      LRU释放对象数
evicted_nonzero              设置了非0时间的LRU释放对象数
evicted_time                 最后一次LRU秒数,监控频率
outofmemory                  不能存储对象次数,使用-M会报错
tailrepairs                  修复slabs次数
reclaimed                    使用过期对象空间存储对象次数
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值