memcache 内存管理

在前面

本文不包含为什么使用memcache,以及如何使用memcache等基础知识。相关知识请查阅各类手册。 另,为便于理解,最好手头准备一份memcache的源码,本文使用的是目前最新的1.4.4版本源码,可自行到github上clone。

Item、Chunk、Page、Slab

Data Item

+---------------------------------------+
|  key-value | cas | suffix | item head |  
+---------------------------------------+

Item指实际存放到memcache中的数据对象结构,除key-value数据外,还包括memcache自身对数据对象的描述信息(Item=key+value+后缀长+32byte结构体)

Chunk

Chunk指Memcache用来存放Data Item的最小单元,同一个Slab中的chunk大小是固定的。

+------------------------------+
|   data item    | empty space |
+------------------------------+

Page

+-------------------------------------+
|  chunk1 | chunk2 | chunk3 | chunk4  |
+-------------------------------------+

每个Slab中按照Page来申请内存,Page的大小默认为1M,可以通过-l参数调整,最小1k,最大128m.

Slab

+--------------------------------+
|  Page1 | Page2 | Page3 | Page4 |
+--------------------------------+

Memcache将分配给它的内存(-m 参数指定,默认64m)按照Chunk大小不同,划分为多个slab。

他们三者的关系如下图所示:

                 Chunk
                   ^                                                         
+------------------|------------------------------------------------------------+
|   Memory         |                                                            | 
|  +---------------|---------------------------------------------------------+  |
|  |      +--------|---------------------+  +------------------------------+ |  |
|  |      |Page1 +-|---+ +-----+ +-----+ |  |Page2 +-----+ +-----+ +-----+ | |  |
|  | Slab |(1M)  | 96B | | 68B | | 72B | |  |(1M)  | 92B | | 76B | | 84B | | |  | 
|  |  1   |      +-----+ +-----+ +-----+ |  |      +-----+ +-----+ +-----+ | |  |
|  |      +------------------------------+  +------------------------------+ |  |
|  +-------------------------------------------------------------------------+  |
|                                                                               |
|  +-------------------------------------------------------------------------+  |
|  |      +------------------------------+  +------------------------------+ |  |
|  |      |Page1 +------+    +------+    |  |Page2 +------+    +-------+   | |  |
|  | Slab | (1M) | 128B |    | 120B |    |  |(1M)  | 128B |    | 97B   |   | |  |
|  |   2  |      +------+    +------+    |  |      +------+    +-------+   | |  |
|  |      +------------------------------+  +------------------------------+ |  |
|  +-------------------------------------------------------------------------+  |
+-------------------------------------------------------------------------------+

 memcache内存分配机制

memcached的内存分配没有用到c语言中自带的malloc函数,因为这个函数分配内存的时候效率很低,对于这种要求快速响应,对效率要求非常高的缓存软件来说非常不合适。
memcached用的是自己的一套内存分配方法,叫做slab allocation。
Memcache单进程最大可开的内存是2GB,如果想缓存更多的数据,建议还是开辟更多的memcache进程(不同端口)或者使用分布式memcache进行缓存,将数据缓存到不同的物理机或者虚拟机上。
当memcached启动的时候,我们会在系统中给他分配一定大小的内存,假设这里是1个G,但是刚启动的时候memcached不会一下就将这1G的内存全部吃进去,它是按需索取,一点一点增加的。

Memcache进程启动,在内存开辟了连续的区域。咱们用上面的图形来举例,这段连续的区域就好像上面的slab1+slab2+slab3+……+slab(n).分配区域相同的构成了slab(分片组)。Slab下面可不直接就是存储区域片(就是图中的chunks)了。而是page,如果一个新的缓存数据要被存放,memcached首先选择一个合适的slab,然后查看该slab是否还有空闲的chunk,如果有则直接存放进去;如果没有则要进行申请。

slab申请内存时以page为单位,所以在放入第一个数据,无论大小为多少,都会有1M大小的page被分配给该slab。申请到page后,slab会将这个page的内存按chunk的大小进行切分,这样就变成了一个chunk的数组,在从这个chunk数组中选择一个用于存储数据。在Page中才是一个个小存储单元——chunks,一个page默认1mb,那么可以放多少个88字节单位的chunks呢?1024*1024/88约等于11915个。如果放入记录是一个100字节的数据,那么在88字节的chunks和112字节的chunks中如何调配呢。答案当然是紧着大的用,不可能将请求过来的数据再做个分解、分离存储、合并读取吧。这样也就带来了一个小问题,还是有空间浪费掉了。112-100=12字节,这12字节就浪费了。

Memcache借助了操作系统的libevent工具做高效的读写。libevent是个程序库,它将Linux的epoll、BSD类操作系统的kqueue等事件处理功能封装成统一的接口。即使对服务器的连接数增加,也能发挥高性能。memcached使用这个libevent库,因此能在Linux、BSD、Solaris等操作系统上发挥其高性能。Memcache号称可以接受任意数量的连接请求。事实真的是这样吗?

**一般来说一个memcahced进程会预先将自己划分为若干个slab,slab得数量是有限得,几个,十几个,或者几十个,这个跟进程配置得内存有关。

**一个slab会有多个page,预先分配1m,不是说只能使用1m,当这 1m的数据满了之后,会重新分配一个page给这个slab。

一、Memcache内存分配机制

        关于这个机制网上有很多解释的,我个人的总结如下。

  1. Page为内存分配的最小单位。

    Memcached的内存分配以page为单位,默认情况下一个page是1M,可以通过-I参数在启动时指定。如果需要申请内存时,memcached会划分出一个新的page并分配给需要的slab区域。page一旦被分配在重启前不会被回收或者重新分配(page ressign已经从1.2.8版移除了)
    Memcached pages

  2. Slabs划分数据空间。

    Memcached并不是将所有大小的数据都放在一起的,而是预先将数据空间划分为一系列slabs,每个slab只负责一定范围内的数据存储。如下图,每个slab只存储大于其上一个slab的size并小于或者等于自己最大size的数据。例如:slab 3只存储大小介于137 到 224 bytes的数据。如果一个数据大小为230byte将被分配到slab 4中。从下图可以看出,每个slab负责的空间其实是不等的,memcached默认情况下下一个slab的最大值为前一个的1.25倍,这个可以通过修改-f参数来修改增长比例。
    Memcached slab

  3. Chunk才是存放缓存数据的单位。

    Chunk是一系列固定的内存空间,这个大小就是管理它的slab的最大存放大小。例如:slab 1的所有chunk都是104byte,而slab 4的所有chunk都是280byte。chunk是memcached实际存放缓存数据的地方,因为chunk的大小固定为slab能够存放的最大值,所以所有分配给当前slab的数据都可以被chunk存下。如果时间的数据大小小于chunk的大小,空余的空间将会被闲置,这个是为了防止内存碎片而设计的。例如下图,chunk size是224byte,而存储的数据只有200byte,剩下的24byte将被闲置。
    Memcached chunk

  4. Slab的内存分配。

    Memcached在启动时通过-m指定最大使用内存,但是这个不会一启动就占用,是随着需要逐步分配给各slab的。
             如果一个新的缓存数据要被存放,memcached首先选择一个合适的slab,然后查看该slab是否还有空闲的chunk,如果有则直接存放进去;如果没有则要进行申请。slab申请内存时以page为单位,所以在放入第一个数据,无论大小为多少,都会有1M大小的page被分配给该slab。申请到page后,slab会将这个page的内存按chunk的大小进行切分,这样就变成了一个chunk的数组,在从这个chunk数组中选择一个用于存储数据。如下图,slab 1和slab 2都分配了一个page,并按各自的大小切分成chunk数组。

  5. Memcached内存分配策略。

    综合上面的介绍,memcached的内存分配策略就是:按slab需求分配page,各slab按需使用chunk存储。
    这里有几个特点要注意,

    1. Memcached分配出去的page不会被回收或者重新分配
    2. Memcached申请的内存不会被释放
    3. slab空闲的chunk不会借给任何其他slab使用

    很多同学可能熟知Memcached的LRU淘汰算法,它是在slab内部进行的,如果所有空间都被slabs分配,即使另外一个slab里面有空位,仍然存在踢数据可能。你可以把slab理解为教室,如果你的教室满了,即使别的教室有空位你的教室也只能踢人才能进人。

  6. mc

    1. 本文介绍的却是另外一种现象。今天监控发现线上一memcached发生数据被踢现象,用stats命令看evictions>0,因为以前也出现过此问题,后来对这个参数增加了一个监控,所以这次主动就发现了。由于给memcached分配的内存远大于业务存储数据所需内存,因此初步判断是 “灵异现象”。

 

      知道了这些以后,就可以理解为什么总内存没有被全部占用的情况下,memcached却出现了丢失缓存数据的问题了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值