Memcached深刻分析及内存调优

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

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

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

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的数据。 session

在存储数据时,若是这个item对应的slab尚未建立则申请一个page的内存,将这个page按照所在slab中chunk的大小进行分割,而后将item存入。 dom

若是已经建立存在了,判断对应的slab是否用完,没用完直接存储。 异步

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

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

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

liyd@ubuntu:~$ memcached -d -m256 -p11211 -u liyd -vv
liyd@ubuntu:~$ slab class 1: chunk size        96 perslab   10922
slab class 2: chunk size       120 perslab    8738
slab class 3: chunk size       152 perslab    6898
slab class 4: chunk size       192 perslab    5461
slab class 5: chunk size       240 perslab    4369
slab class 6: chunk size       304 perslab    3449
slab class 7: chunk size       384 perslab    2730
slab class 8: chunk size       480 perslab    2184
slab class 9: chunk size       600 perslab    1747
slab class 10: chunk size       752 perslab    1394
slab class 11: chunk size       944 perslab    1110
slab class 12: chunk size      1184 perslab     885
slab class 13: chunk size      1480 perslab     708
slab class 14: chunk size      1856 perslab     564
slab class 15: chunk size      2320 perslab     451
slab class 16: chunk size      2904 perslab     361
slab class 17: chunk size      3632 perslab     288
slab class 18: chunk size      4544 perslab     230
slab class 19: chunk size      5680 perslab     184
slab class 20: chunk size      7104 perslab     147
slab class 21: chunk size      8880 perslab     118
slab class 22: chunk size     11104 perslab      94
slab class 23: chunk size     13880 perslab      75
slab class 24: chunk size     17352 perslab      60
slab class 25: chunk size     21696 perslab      48
slab class 26: chunk size     27120 perslab      38
slab class 27: chunk size     33904 perslab      30
slab class 28: chunk size     42384 perslab      24
slab class 29: chunk size     52984 perslab      19
slab class 30: chunk size     66232 perslab      15
slab class 31: chunk size     82792 perslab      12
slab class 32: chunk size    103496 perslab      10
slab class 33: chunk size    129376 perslab       8
slab class 34: chunk size    161720 perslab       6
slab class 35: chunk size    202152 perslab       5
slab class 36: chunk size    252696 perslab       4
slab class 37: chunk size    315872 perslab       3
slab class 38: chunk size    394840 perslab       2
slab class 39: chunk size    493552 perslab       2
slab class 40: chunk size    616944 perslab       1
slab class 41: chunk size    771184 perslab       1
slab class 42: chunk size   1048576 perslab       1
<26 server listening (auto-negotiate)
<27 send buffer was 212992, now 268435456
<28 send buffer was 212992, now 268435456
<27 server listening (udp)
<28 server listening (udp)
<27 server listening (udp)
<28 server listening (udp)
<27 server listening (udp)
<28 server listening (udp)
<27 server listening (udp)
<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内部的状态,可是功能上也比较有限,就不细讲了,主要就是如下几个命令:

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

如今咱们再回过头去看Memcached的stats命令,是否是就颇有用了?这里贴上经常使用的一些参数说明。

stats统计项:

pid Memcached进程ID
uptime Memcached运行时间,单位:秒
time Memcached当前的UNIX时间
version Memcached的版本号
rusage_user 该进程累计的用户时间,单位:秒
rusage_system 该进程累计的系统时间,单位:秒
curr_connections 当前链接数量
total_connections Memcached运行以来接受的链接总数
connection_structures Memcached分配的链接结构的数量
cmd_get 查询请求总数
get_hits 查询成功获取数据的总次数
get_misses 查询成功未获取到数据的总次数
cmd_set 存储(添加/更新)请求总数
bytes Memcached当前存储内容所占用字节数
bytes_read Memcached从网络读取到的总字节数
bytes_written Memcached向网络发送的总字节数
limit_maxbytes Memcached在存储时被容许使用的字节总数
curr_items Memcached当前存储的内容数量
total_items Memcached启动以来存储过的内容总数
evictions LRU释放对象数,用来释放内存

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 使用过时对象空间存储对象次数

stats settings查看设置:

maxbytes 最大字节数限制,0无限制
maxconns 容许最大链接数
tcpport TCP端口
udpport UDP端口
verbosity 日志0=none,1=som,2=lots
oldest 最老对象过时时间
evictions on/off,是否禁用LRU
domain_socket socket的domain
umask 建立Socket时的umask
growth_factor 增加因子
chunk_size key+value+flags大小
num_threads 线程数,能够经过-t设置,默认4
stat_key_prefix stats分隔符
detail_enabled yes/no,显示stats细节信息
reqs_per_event 最大IO吞吐量(每event)
cas_enabled yes/no,是否启用CAS,-C禁用
tcp_backlog TCP监控日志
auth_enabled_sasl yes/no,是否启用SASL验证

原文地址:Memcached深刻分析及内存调优

相关文章
相关标签/搜索