Memcached 内存管理详解

news/2024/7/20 13:50:32 标签: memcached, 内存管理, c/c++

Memcached是一个高效的分布式内存cache,了解memcached内存管理机制,便于我们理解memcached,让我们可以针对我们数据特点进行调优,让其更好的为我所用。

首先需要我们先了解两个概念:Slab和chunk

Slab和chunk在Memcached的内部结构中是非常两个重要的概念,先上一张图来感性认识下:

Slab是一个内存块,是Memcached一次申请内存的最小单位。在启动Memcached的时候一般会使用参数-m来指定其可用内存,但并不是在启动哪一刻时所有内存全被分配出去了,而是只有在需要的时候才去申请,每次申请的就是一个Slab。Slab的大小是固定为1M(1048576 Byte)的,而一个Slab是由若干个大小相等的chunk组成,每个chunk中都保存了一个item结构体。

虽然在同一个Slab中的chunk大小相等,但在不同的Slab中chunk的大小不一定相等。因此在Memcached中按照chunk的大小不同,把Slab分成了很多种类(class)。在启动Memcached的时候可以通过-vv来查看Slab的种类:

从上图可以看到,默认情况下memcached把slab分为40类(class1~class40):

  • 一列数据(slab class),为slab的编号;
  • 第二列数据是chunk的大小,跟slab class是一一对应的关系,可以通俗的理解为slab就是存放一组相同大小chunk的集合,只不过这个集合是固定的(1M),
  • 第三列数据,表示每种不同slab中的page可以存放的chunk个数,实际上等于1MB/ (chunk size),例如在class 1中,chunk的大小为80字节,因此在class1中最多可以有13107个chunk:

    13107×80 + 16 = 1048576

    很显然,slab的chunk size越大,其中的每个page包含的chunk数量就越少。

在class1中,剩余的16字节因为不够一个chunk的大小(80byte),因此会被浪费掉。每类chunk的大小有一定的计算公式的,假定i代表分类,class i的计算公式如下:

chunk size(class i) :  (default_size+item_size)*f^(i-1)+ CHUNK_ALIGN_BYTES
  • default_size: 默认大小为48字节,也就是memcached默认的key+value的大小为48字节,可以通过-n参数来调节其大小;
  • item_size: item结构体的长度,固定为32字节。default_size大小为48字节,item_size为32,因此class1的chunk大小为48+32=80字节;
  • f为factor,是chunk变化大小的因素,默认值为1.25,调节f可以影响chunk的步进大小,在启动时可以使用-f来指定;
  • CHUNK_ALIGN_BYTES是一个修正值,用来保证chunk的大小是某个值的整数倍(在32位机器上要求chunk的大小是4的整数倍)。

从上面的分析可以看到,我们实际可以调节的参数有-f、-n,在memcached的实际运行中,我们还需要观察我们的数据特征,合理的调节f,n的值,使我们的内存得到充分的利用减少浪费。


内存申请分配

Memcached默认情况下采用了名为Slab Allocator的机制分配、管理内存,Slab Allocator的基本原理是按照预先规定的大小,将分配的内存分割成特定长度的块,以完全解决内存碎片问题。

Memcached在重复利用分配的内存时,不会主动删除过期的,而是通过两种策略来实现的:

  • Lazy Expiration:就是Memcached不会去监视服务器上的数据是否过期,而是等待get的时候检查时间戳是否过期,如果过期将不返回值,来减少Memcached在监控数据上所用到的时间。
  • Least Recently Used(LRU):Memcached 不会去释放已经使用的内存空间,但是如果分配的内存空间已经满了,当此处内存空间数据最长时间没有使用,而且使用次数很少,在存储新的数据的同时就会覆盖此处内存块。
    而LRU是针对Slab做的操作,而非全局哦。

下面解释一下memcached的内存预分配过程:

  1. memcached添加一个item时候,memcached首先会根据 item的大小,来选择最合适的slab class:例如item的大小为190字节,默认情况下class 4的chunk大小为160字节显然不合适,class 5的chunk大小为200字节,大于190字节,因此该item将放在class 5中(显然这里会有10字节的浪费是不可避免的)。
  2. 计算好所要放入的chunk之后,如果这个item对应的slab未出现过,则申请1个page(注意,这1M空间不论是否达到memcached使用内存都可以申请成功)并加该item存入slab中的chunk。
  3. 如果item对应的slab出现过,则在该slab中优先选择expired(free_chunks)和delete的chunk进行存储,其次将选择未使用过的chunk(free_chunks_end)进行存储。
  4. 如果item对应的slab出现过,但是对应的slab已经存储满了,那么会申请一个新的page,这个page被分为对应大小的chunk,继续存储。例如我们第一次向memcached中放入一个190字节的item 时,memcached会产生一个slab class 5(也叫一个page),并会用去一个chunk,剩余5241个chunk供下次有适合大小item时使用,当我们用完这所有的5242个chunk之后,下次再有一个在160~200字节之间的item添加进来时,memcached会再次产生一个class 5的slab(这样就存在了2个pages)。
  5. 如果item对应的slab出现过,但是对应的slab已经存储满了并且memcache也达到了最大内存使用。将使用lru算法,清除item(可能将未过期的item清除)此时会有eviction++。

Page其实就是分配给Slab的内存空间,默认是1MB,Slab是逻辑概念。

转载于:https://www.cnblogs.com/zhaiqianfeng/p/4619134.html


http://www.niftyadmin.cn/n/1063940.html

相关文章

实时监听移动端输入框的变化

一个常见需求,实时监听textarea的输入变化,并在页面上显示还能够输入多少字符。 开发过程中翻了两个形式错误: 1、仅仅使用onkeyup事件 2、使用zepto绑定事件的时候,经验主义错误 第三方输入法在输入拼音的时候,并没有…

JavaScript中的异步梳理(1)——使用消息驱动

先举一个例子,如果希望ABCDE这5个函数依次执行,我们可以写出如下代码。 A(); B(); C(); D(); E(); 在同步的情况下,这样的代码没有任何问题。但如果ABCDE都是异步的,还需要按次序执行,这样写就不行了。通常我们会为异步…

jQuery、prototype、mootools、YUI Extjs 框架比较

框架涉及对浏览器的支 持、文档、扩展行、性能、编码风格。 1.prototype入门级框架,对ie浏览器的版本判断很粗糙,糟糕的文档和扩展性 2.jquery 简洁, 内部结构好开源,侧重逻辑 ,对DOM选择强大(其实&#xf…

嵌入式实验linux驱动编程,实验八 嵌入式Linu备驱动编程实验八 嵌入式Linux设备驱动编程.pdf...

实验八 嵌入式Linu备驱动编程实验八 嵌入式Linux设备驱动编程.pdf实验八 嵌入式 Linux 设备驱动编程【实验目的】? 学习中断的相关知识? 学习驱动程序的编写,驱动程序的加载和使用? 掌握 GPIO 驱动和中断驱动的编写方法【实验学时】建议 4 学时【实验内容】? 掌…

转载 C#中静态类和非静态类比较

转载原地址: http://www.cnblogs.com/NothingIsImpossible/archive/2010/07/28/1786706.html C#静态方法与非静态方法的区别不仅仅是概念上的,那么他们有什么具体的区别呢?让我们通过本文向你做一下解析。 C#的类中可以包含两种方法&#xff…

一步步学习SPD2010--第四章节--创建和修改网页

本章节内容:1. 插入文本、屏幕贴士、超链接和图片2. 处理Web部件3. 改变网站的首页4. 修改和创建列表视图及列表表单页面5. 创建ASP.NET页面并插入Web部件区域6. 附上母版页7. 管理网页 使用SPD2010,你可以创建许多不同文件格式,一些你可能认…

学习MVC之租房网站(一)-项目概况

这儿的MVC是ASP.NET MVC,只用过C#一种语言,后面就直接称呼为MVC了。 一年多没接触MVC后,现在想用MVC做个网站,觉得特别吃力,以前学的仅仅是皮毛,所以闲置了一年后,MVC知识就重新归零了。 这几周…

[LeetCode] Search Insert Position

Given a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order. You may assume no duplicates in the array. Here are few examples.[1,3,5,6], 5 → 2[1,3,5,6], 2 → 1[1…