memcached 命中率问题 分析 **
Memcached, 人所皆知的remote distribute cache(不知道的可以javaeye一下下,或者google一下下,或者baidu一下下,但是鉴于baidu的排名商业味道太浓(从最近得某某事 件可以看出),所以还是建议javaeye一下下),使用起来也非常的简单,它被用在了很多网站上面,几乎很少有大型的网站不会使用 memcached。
曾经我也看过很多剖析memcached内部机制的文章,有一点收获,但是看过之后又忘记了,而且没有什么深刻的概念,但是最近我遇到一个问题,这个问题迫使我重新来认识memcache,下面我阐述一下我遇到的问题
问
题:我有几千万的数据,这些数据会经常被用到,目前来看,它必须要放到memcached中,以保证访问速度,但是我的memcached中数据经常会有
丢失,而业务需求是memcached中的数据是不能丢失的。我的数据丢失的时候,memcached
server的内存才使用到60%,也就是还有40%内存被严重的浪费掉了。但不是所有的应用都是这样,其他应用内存浪费的就比较少。为什么内存才使用到
60%的时候LRU就执行了呢(之所以确定是LRU执行是因为我发现我的数据丢失的总是前面放进去的,而且这个过程中,这些数据都没有被访问,比如第一次
访问的时候,只能访问第1000w条,而第300w条或者之前的数据都已经丢失了,从日志里看,第300w条肯定是放进去了)。
带着这
些疑问,我开始重新审视memcached这个产品,首先从它的内存模型开始:我们知道c++里分配内存有两种方式,预先分配和动态分配,显然,预先分配
内存会使程序比较快,但是它的缺点是不能有效利用内存,而动态分配可以有效利用内存,但是会使程序运行效率下降,memcached的内存分配就是基于以
上原理,显然为了获得更快的速度,有时候我们不得不以空间换时间。
也就是说memcached会预先分配内存,对了,memcached分配内存方式称之为allocator,首先,这里有3个概念:
1 slab
2 page
3 chunk
解
释一下,一般来说一个memcahced进程会预先将自己划分为若干个slab,每个slab下又有若干个page,每个page下又有多个chunk,
如果我们把这3个咚咚看作是object得话,这是两个一对多得关系。再一般来说,slab得数量是有限得,几个,十几个,或者几十个,这个跟进程配置得
内存有关。而每个slab下得page默认情况是1m,也就是说如果一个slab占用100m得内存得话,那么默认情况下这个slab所拥有得page得
个数就是100,而chunk就是我们得数据存放得最终地方。
举一个例子,我启动一个memcached进程,占用内存100m,再打开telnet,telnet localhost 11211,连接上memcache之后,输入stats slabs,回车,出现如下数据:
- STAT 1:chunk_size 80
- STAT 1:chunks_per_page 13107
- STAT 1:total_pages 1
- STAT 1:total_chunks 13107
- STAT 1:used_chunks 13107
- STAT 1:free_chunks 0
- STAT 1:free_chunks_end 13107
- STAT 2:chunk_size 100
- STAT 2:chunks_per_page 10485
- STAT 2:total_pages 1
- STAT 2:total_chunks 10485
- STAT 2:used_chunks 10485
- STAT 2:free_chunks 0
- STAT 2:free_chunks_end 10485
- STAT 3:chunk_size 128
- STAT 3:chunks_per_page 8192
- STAT 3:total_pages 1
- STAT 3:total_chunks 8192
- STAT 3:used_chunks 8192
- STAT 3:free_chunks 0
- STAT 3:free_chunks_end 8192
以上就是前3个slab得详细信息
chunk_size
表示数据存放块得大小,chunks_per_page表示一个内存页page中拥有得chunk得数量,total_pages表示每个slab下
page得个数。total_chunks表示这个slab下chunk得总数(=total_pages *
chunks_per_page),used_chunks表示该slab下已经使用得chunk得数量,free_chunks表示该slab下还可以
使用得chunks数量。
从上面得示例slab
1一共有1m得内存空间,而且现在已经被用完了,slab2也有1m得内存空间,也被用完了,slab3得情况依然如此。
而且从这3个slab中chunk得size可以看出来,第一个chunk为80b,第二个是100b,第3个是128b,基本上后一个是前一个得
1.25倍,但是这个增长情况我们是可以控制得,我们可以通过在启动时得进程参数 –f来修改这个值,比如说 –f
1.1表示这个增长因子为1.1,那么第一个slab中得chunk为80b得话,第二个slab中得chunk应该是80*1.1左右。
解
释了这么多也该可以看出来我遇到得问题得原因了,如果还看不出来,那我再补充关键的一句:memcached中新的value过来存放的地址是该
value的大小决定的,value总是会被选择存放到chunk与其最接近的一个slab中,比如上面的例子,如果我的value是80b,那么我这所
有的value总是会被存放到1号slab中,而1号slab中的free_chunks已经是0了,怎么办呢,如果你在启动memcached的时候没
有追加-M(禁止LRU,这种情况下内存不够时会out of
memory),那么memcached会把这个slab中最近最少被使用的chunk中的数据清掉,然后放上最新的数据。这就解释了为什么我的内存还有
40%的时候LRU就执行了,因为我的其他slab中的chunk_size都远大于我的value,所以我的value根本不会放到那几个slab中,
而只会放到和我的value最接近的chunk所在的slab中(而这些slab早就满了,郁闷了)。这就导致了我的数据被不停的覆盖,后者覆盖前者。
问
题找到了,解决方案还是没有找到,因为我的数据必须要求命中率时100%,我只能通过调整slab的增长因子和page的大小来尽量来使命中率接近
100%,但是并不能100%保证命中率是100%(这话怎么读起来这么别扭呢,自我检讨一下自己的语文水平),如果您说,这种方案不行啊,因为我的
memcached server不能停啊,不要紧还有另外一个方法,就是memcached-tool,执行move命令,如:move 3
1,代表把3号slab中的一个内存页移动到1号slab中,有人问了,这有什么用呢,比如说我的20号slab的利用率非常低,但是page却又很多,
比如200,那么就是200m,而2好slab经常发生LRU,明显page不够,我就可以move 20
2,把20号slab的一个内存页移动到2号slab上,这样就能更加有效的利用内存了(有人说了,一次只移动一个page,多麻烦啊?ahuaxuan
说,还是写个脚本,循环一下吧)。
有人说不行啊,我的memcache中的数据不能丢失啊,ok,试试新浪的memcachedb吧,
虽然我没有用过,但是建议大家可以试试,它也使利用memcache协议和berkeleyDB做的(写到这里,我不得不佩服danga了,我觉得它最大
的贡献不是memcache server本身,而是memcache协议),据说它被用在新浪的不少应用上,包括新浪的博客。
补充,stats slab命令可以查看memcached中slab的情况,而stats命令可以查看你的memcached的一些健康情况,比如说命中率之类的,示例如下:
- STAT pid 2232
- STAT uptime 1348
- STAT time 1218120955
- STAT version 1.2.1
- STAT pointer_size 32
- STAT curr_items 0
- STAT total_items 0
- STAT bytes 0
- STAT curr_connections 1
- STAT total_connections 3
- STAT connection_structures 2
- STAT cmd_get 0
- STAT cmd_set 0
- STAT get_hits 0
- STAT get_misses 0
- STAT bytes_read 26
- STAT bytes_written 16655
- STAT limit_maxbytes 104857600
从
上面的数据可以看到这个memcached进程的命中率很好,get_misses低达0个,怎么回事啊,因为这个进程使我刚启动的,我只用telnet
连了一下,所以curr_connections为1,而total_items为0,因为我没有放数据进去,get_hits为0,因为我没有调用
get方法,最后的结果就是misses当然为0,哇哦,换句话说命中率就是100%,又yy了。
该到总结的时候了,从这篇文章里我们可以得到以下几个结论:
结论一,memcached得LRU不是全局的,而是针对slab的,可以说是区域性的。
结论二,要提高memcached的命中率,预估我们的value大小并且适当的调整内存页大小和增长因子是必须的。
结论三,带着问题找答案理解的要比随便看看的效果好得多。
原文:http://bzyyc.happy.blog.163.com/blog/static/614306472011746618136/
memcached 命中率问题 分析 **的更多相关文章
- Memcached缓存瓶颈分析
Memcached缓存瓶颈分析 获取Memcached的统计信息 Shell: # echo "stats" | nc 127.0.0.1 11211 PHP: $mc = new ...
- Memcached源码分析之请求处理(状态机)
作者:Calix 一)上文 在上一篇线程模型的分析中,我们知道,worker线程和主线程都调用了同一个函数,conn_new进行事件监听,并返回conn结构体对象.最终有事件到达时,调用同一个函数ev ...
- Memcached源码分析之线程模型
作者:Calix 一)模型分析 memcached到底是如何处理我们的网络连接的? memcached通过epoll(使用libevent,下面具体再讲)实现异步的服务器,但仍然使用多线程,主要有两种 ...
- Memcached源码分析之从SET命令开始说起
作者:Calix 如果直接把memcached的源码从main函数开始说,恐怕会有点头大,所以这里以一句经典的“SET”命令简单地开个头,算是回忆一下memcached的作用,后面的结构篇中关于命令解 ...
- Memcached源码分析
作者:Calix,转载请注明出处:http://calixwu.com 最近研究了一下memcached的源码,在这里系统总结了一下笔记和理解,写了几 篇源码分析和大家分享,整个系列分为“结构篇”和“ ...
- Memcached源码分析之内存管理
先再说明一下,我本次分析的memcached版本是1.4.20,有些旧的版本关于内存管理的机制和数据结构与1.4.20有一定的差异(本文中会提到). 一)模型分析在开始解剖memcached关于内存管 ...
- memcached源码分析-----item过期失效处理以及LRU爬虫
memcached源码分析-----item过期失效处理以及LRU爬虫,memcached-----item 转载请注明出处:http://blog.csdn.net/luotuo44/article ...
- Memcached原理深度分析详解
Memcached是 danga.com(运营LiveJournal的技术团队)开发的一套分布式内存对象缓存系统,用于在动态系统中减少数据库负载,提升性能.关于这个东 西,相信很多人都用过,本文意在通 ...
- Memcached源码分析——process_command函数解析
以下为个人笔记 /** * process_command 在memcached中是用来处理用户发送的命令的, * 包括get set,add,delete,replace,stats,flush_a ...
随机推荐
- HUE的时区问题
转自 http://molisa.iteye.com/blog/1953390 我主要是根据这个说明调整的HUE的时区问题 在使用Cloudera Hue时遇到一问题: 1. 使用Sqoop导入功 ...
- C# PropertyGrid控件应用心得
何处使用 PropertyGrid 控件 在应用程序中的很多地方,您都可以使用户与 PropertyGrid 进行交互,从而获得更丰富的编辑体验.例如,某个应用程序包含多个用户可以设置的“设置”或选项 ...
- Java的内存模型
"让计算机并发执行若干个运算任务"与"更充分地利用计算机处理器的效能"之间的因果关系,看起来顺理成章,实际上它们之间的关系并没有想象中的那么简单,其中一个重要的 ...
- jquery优化02
缓存变量:DOM遍历是昂贵的,所以尽量将会重用的元素缓存. $element = $('#element'); h = $element.height(); //缓存 $element.css('he ...
- ember.js:使用笔记4 数组数据的分组显示
除了之前介绍的将数组数据在一个页面中输出的方法,还可以将数组数据分组,按照点击,在不同页面中分别显示,方法为: Model: 例如:Table Router: 设置一个父对象和子对象设置: this. ...
- 并查集+拓扑排序 赛码 1009 Exploration
题目传送门 /* 题意:无向图和有向图的混合图判环: 官方题解:首先对于所有的无向边,我们使用并查集将两边的点并起来,若一条边未合并之前, 两端的点已经处于同一个集合了,那么说明必定存在可行的环(因为 ...
- C#:代表(delegate)和事件(event)
代表(delegate): 它是C#语言里面的函数指针,代表可以指向某一个函数,在运行的时候调用这个函数的实现.下面来看看它的实现步骤: 声明一个delegate对象. 实现和delegate具有相同 ...
- BZOJ3919 : [Baltic2014]portals
预处理出每个点上下左右能延伸到的最远点以及到它们的距离的最小值md. 然后spfa,一个点除了可以以1的代价到达四周的点之外,还可以以md+1的代价到达四个方向能到达的最远点. #include< ...
- BZOJ3673 : 可持久化并查集
题目没有强制在线! 考虑离线做法. 把操作建立成一棵树的结构,然后按照欧拉序遍历,每次转移要么是一次合并操作,要么是一次撤销合并操作,可以看成是分离操作. 用LCT维护集合,合并就是加边,分离就是删边 ...
- JavaScript初学者应注意的七个细节
每种语言都有它特别的地方,对于JavaScript来说,使用var就可以声明任意类型的变量,这门脚本语言看起来很简单,然而想要写出优雅的代码却是需要不断积累经验的.本文利列举了JavaScript初学 ...