Memcache内核机制


  • 内存如何分配给item
  • 额外内存的作用
  • 内存回收时机
  • 单个item占用多少内存
  • item被强制回收的时机

对于使用memcache的开发者来说,了解一下其内部运行机制还是很有必要的。虽然过分关注位和字节是浪费时间,但是随着经验的增长,你将受益于对底层的了解。(注:知其然知其所以然并没有坏处)
掌握了解内存的分配和释放,以及这种特殊的LRU机制是重中之重。

内存如何分配给item

在memcached服务启动的时候可以通过命令行指令-m为数据存储分配内存。数据空间被默认拆分成n个大小为1Mb的page,然后这些page被分配到slab classes集合类中(每个page对应一个slab class),最后每个slab被切割成固定大小的chunk。

注:

  1. 不指定默认64M,只是代表存储上限,逐步分配,并不立即分配这么多内存;
  2. 分配的内存不包括服务自身占用的管理空间;
  3. 单个slab下的page中的chunk size相同;
  4. 不同slab根据增长因子(由-f指定)他们的chunk不同。有点绕呢!

一旦一个page被分配给一个slab class,则它就一直待在内存中了(除非重启服务)。所以如果你给slab class 3分配了80%的内存,那么slab class 4分配的内存就很少了(显然这种分配不合理)。最优的考虑方案就是将内存划分成许多独立的小内存区间,每个区间都有自己的计数器和LRU。


在启动memcached服务时可以通过命令-vv来查看slab class、chunk和page分配情况,如下:

$ ./memcached -vv
slab class   1: chunk size        80 perslab   13107
slab class   2: chunk size       104 perslab   10082
slab class   3: chunk size       136 perslab    7710
slab class   4: chunk size       176 perslab    5957
slab class   5: chunk size       224 perslab    4681
slab class   6: chunk size       280 perslab    3744
slab class   7: chunk size       352 perslab    2978
slab class   8: chunk size       440 perslab    2383
slab class   9: chunk size       552 perslab    1899
slab class  10: chunk size       696 perslab    1506
[...etc...]

以上,先看slab class 1,每个chunk占用80字节,每个page包括13107个chunks。1MB-13107*80=16字节

注:1MB=1048576Bytes,显然也会造成少量内存浪费。

当你新增一条数据时,这条数据将会被存入chunk大小与它最接近的slab class中。如果你的key+value+其他数据(过期标识等)总共50字节,则它会被存进slab class 1,伴随着30字节的内存浪费。同理如果你的数据是90字节,则它会存进slab class 2,浪费14字节。

你可以通过设置增长因子-f来自定义chunk的分配策略,但最好根据你自己的数据的需要来调整策略。切记慎用自定义,因为容易导致意想不到的惊喜。

注:memcache 会对内存进行划分不同区域大小的块,但是会默认一个最小存放数据区域块大小 size = 80/Byte 而增长因子就是以最小区域块为基础,每次递增的倍数,但是最大递增不能超过 62 个且 sizefactor < 1M。比如分配的时候-f2.0,则slab1.chunk如果是80bytes,那么slab2.chunk即为160bytes,以此类推,slabN.chunk就是2N80bytes。
不过监控下来发现,我的slab是从6开始一直到26,slab6的chunk是304而slab7是384,slab8是480,slab9是600…
384/304=1.263,480/384=1.25,600/480=1.25
我也不清楚slab6和7为什么不是1.25,理解还不深刻,衰!!!
参考Memcache-内存模型-源码分析

额外内存的作用

Memcached的chunk内存还有额外的功能。根据散列表查找item会有部分开销,同样地,每个请求链接也会使用额外的缓存。这些加起来在-m分配的内存上限中占比应该很小,但应该记住这点开销。说不定这是压死骆驼的稻草呢。

内存回收时机

在1.5.0版本之前,过期的数据不会主动回收。如果用命令行-o modern启动老版本,或者版本高于1.5.0,会有一个爬虫定期(理解成后台线程) 去扫描缓存数据并释放过期数据的缓存。

当你获取一条数据时,memcached查找到这条数据并比较过期时间,如果过期则释放它的内存。这便给出了一种重复利用内存的解决方案。

实际上,slab在新增item的时候先查看LRU队尾,如果队尾item过期则重用缓存,否则重新申请。参考memcache内存分配和重用机制
只有当-m分配的内存已达上限时,新的数据会强制回收相应slab中LRU队尾的item。

单个item占用多少内存

一个item的内存被其key、内部数据结构和data占用。

你可以通过在本地编译memcached源码,然后运行./sizes 命令查看一条item的占用情况。32位系统在使用CAS(启动服务时使用-C命令开启,注意区别小写 -c 。后者指定最大同时连接数,默认是1024)协议时,每个item最多可用32字节;禁用CAS时最多40字节。64位系统的可用内存会高一点归功于可申请到更多的指针。显然在64位系统上操作更多的内存空间给我们带来了极大地灵活性。

$ ./sizes 
Slab Stats	56
Thread stats	176
Global stats	108
Settings	88
Item (no cas)	32
Item (cas)	40
Libevent thread	96
Connection	320
----------------------------------------
libevent thread cumulative	11472
Thread stats cumulative		11376

item被强制回收的时机

当slab中的chunk被消耗殆尽,而且没有可用的page可供申请,就需要强制回收未过期(包括过期时间到0和未来某一时刻到期)的数据来腾出位子。

LRU怎样决定谁该被回收

当添加新的数据而占用内存已达上限时就需要强制回收内存。如果相应的slab下没有空闲的chunk和page,memcached就会扫描当前slab下的LRU队尾来寻找合适的item来回收。对于已经过期的item则重新利用其内存,如果找不到过期数据,就会强制回收掉队尾的item(即使用计数最少的那条记录)。然后更新一遍item的使用计数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值