性能分析

 Memcached做为一个内存key-value存储容器有很是优秀的性能,可是在上次的使用中确发现大量的数据丢失状况发生,致使cache的功能基本消失。具体的检测方式以下:检测命中率缓存

检测命中率是一个最基本的、最宏观的方式,使用telnet链接到memcached服务器,而后执行stats命令就能够看到宏观的一些信息,以下图。
服务器

 

        这个命令中比较关键的属性是get_hits和get_misses,get_hits表示读取cache命中的次数,get_misses是读取失败的次数,即尝试读取不存在的缓存数据。
         命中率=get_hits / (get_hits + get_misses)
命中率越高说明cache起到的缓存做用越大。可是在实际使用中,这个命中率不是有效数据的命中率,有些时候get操做可能只是检查一个key存在不存在,这个时候miss也是正确的,这就像用memcached做为一种定时器,将一些临时数据在memcache中存放特定时间长度,业务逻辑会根据cache是否存在而做不一样的逻辑,这种数据其实已经不是单纯的缓存了,也不该该统计到命中率中。再者,这个命中率是从memcached启动开始全部的请求的综合值,不能反映一个时间段内的状况,因此要排查memcached的性能问题,还须要更详细的数值。可是高的命中率仍是可以反映出memcached良好的使用状况,忽然下跌的命中率可以反映大量cache丢失的发生。 memcached

Stats items性能

Stats items命令能够查看每一个slab中存储的item的一些详细信息,具体能够见下图。
spa

 


关键属性有: 对象

最后被剔除的数据在cache中存放的时间,以秒为单位

stats items能够详细的观察各slab的数据对象的状况,由于memcached的内存分配策略致使一旦memcached的总内存达到了设置的最大内存,表明全部的slab可以使用的page都已经固定,这个时候若是还有数据放入,将开始致使memcached使用LRU策略剔除数据。而LRU策略不是针对全部的slabs,而是只针对新数据应该被放入的slab,例若有一个新的数据要被放入slab 3,则LRU只对slab 3进行。经过stats items就能够观察到这些剔除的状况。
具体分析以下: blog

evicted属性
若是一个slab的evicted属性不是0,则说明当前slab出现了提早剔除数据的状况,这个slab多是你须要注意的。evicted_time属性
若是evicted不为0,则evicited_time就表明最后被剔除的数据时间缓存的时间。并非发生了LRU就代码memcached负载过载了,由于有些时候在使用cache时会设置过时时间为0,这样缓存将被存放30天,若是内存慢了还持续放入数据,而这些为过时的数据好久没有被使用,则可能被剔除。须要注意的是,最后剔除的这个数据已经被缓存的时间,把evicted_time换算成标准时间看下是否已经达到了你能够接受的时间,例如:你认为数据被缓存了2天是你能够接受的,而最后被剔除的数据已经存放了3天以上,则能够认为这个slab的压力其实能够接受的;可是若是最后被剔除的数据只被缓存了20秒,不用考虑,这个slab已经负载太重了。age属性
age属性反应了当前还在缓存的数据中最久的时间,它的大小和evicted_time没有必然的大小关系,由于可能时间最久的数据确实频繁被读取的,这时候不会被LRU清理掉,可是若是它小于evicted_time的话,则说明数据在被下去读取前就被清理了,或者存放了不少长时间可是不被使用的缓存对象。Stats slabs 内存

从Stats items中若是发现有异常的slab,则能够经过stats slabs查看下该slab是否是内存分配的确有问题。
Stats slabs结果以下图
ci

 

Stats slabs的属性说明以下: get

 

   
chunk_size 当前slab每一个chunk的大小
chunk_per_page 每一个page可以存放的chunk数
total_pages 分配给当前slab的page总数
total_chunks 当前slab最多可以存放的chunk数,应该等于chunck_per_page * total_page
used_chunks 已经被占用的chunks总数
free_chunks 过时数据空出的chunk里尚未被使用的chunk数
free_chunks_end 新分配的可是尚未被使用的chunk数

 

这个命令的信息量很大,全部属性都颇有价值。下面一一解释各属性:

综合上面的数据,能够发现形成memcached的内存使用率下降的属性有:

chunk_size, chunk_per_page
这两个属性是固定的,可是它反映当前slab存储的数据大小,能够供你分析缓存数据的散列区间,经过调整增加因子能够改变slab的区间分布,从而改变数据散列到的区域。若是大量的230byte到260byte的数据,而恰好一个slab大小是250byte,则250byte到260byte的数据将被落到下一个slab,从而致使大量的空间浪费。total_pages
这个是当前slab总共分配大的page总数,若是没有修改page的默认大小的状况下,这个数值就是当前slab可以缓存的数据的总大小(单位为M)。若是这个slab的剔除很是严重,必定要注意这个slab的page数是否是太少了。
我上次处理的那个项目由于和另外的一个项目共用的memcache,并且memcache已经运行了很长时间,致使page都已经所有被分配完,而恰好两个项目的缓存数据大小差异不少,致使新项目数据最多的slab 4居然只有一个page,因此数据缓存不到22s就被替换了,彻底失去了缓存的意义。
针对我遇到的那个状况,解决方案是从新分配page,或者重启memcache服务。可是page reassign方法从1.2.8版已经彻底移除了,因此如今没有办法在线状况下从新分配page了。另一种有些时候是不能够接受的,由于一次缓存服务器的重启将致使全部缓存的数据将从新从DB取出,这个可能形成db的压力瞬间增大。并且有的缓存数据时不入库的,这个时候咱们就须要作memcache的导入和导出了。在下篇文章中我会总结下memcache的dump操做。total_chunks
这个的做用和total_pages基本相同,不过这个属性能够更准确的反应实际能够存放的缓存对象总数。used_chunks, free_chunks, free_chunks_end
这三个属性相关度比较高,从数值上来看它们知足: 
                total_chunks = used_chunks + free_chunks + free_chunks_end
used_chunks就是字面的意思,已经使用的chunk数;free_chunks却不是全部的未被使用的chunk数,而是曾经被使用过可是由于过时而被回收的chunk数;free_chunks_end是page中历来没有被使用过的chunk数。

 



      从上图能够看出,slab 1只放了一个对象,可是已经申请了一整个page,这个时候used_chunks为1,可是free_chunks却为0,由于尚未任何回收的空间,而free_chunks_end却等于10081,说明这么多的chunk历来没有被使用过。下图就是这个数据过时后的stats slabs数据,能够发现free_chunks有值了,就是过时的那个chunk,因此是1,used_chunks为0,free_chunks_end不变。

 



      为何要分两种free chunk呢?
      个人理解是这样的:若是free_chunks_end不为零,说明当前slab没有出现过容量不够的时候;而若是free_chunks始终为0,说明不少数据过时时间过长或者在过时前就被剔除了,这个要结合剔除数据和数据保留的时间(age属性)来看待。因此分开统计这两个值能够准确的判断实际空闲的chunk的状态,一旦因此的chunk被使用过一次之后,除非从新申请page,不然free_chunks_end始终为0。因此对于运行时间比较久的memcached,可能大部分这个值都是0。active_slabs, total_malloced
在stats slabs输出的最后两项是两个统计数据,一个是活动的slab总数,由于slab虽然带编号,可是这个编号不必定是连续的,由于有可能有些中间区间的slab没有值就没有初始化,这样之后该slab有值的时候就不用改变slab的编号了。因此活动的slab总数不必定等于slab的最大编号。
total_malloced这个是实际已经分配的总内存数,单位为byte,这个数值决定了memcached实际还能申请多少内存,若是这个值已经达到设定的上限,则不会有新的page被分配,之前分配的page也已经固定slab了。

 

    综合上面的数据,能够发现形成memcached的内存使用率下降的属性有:

 
page中历来没有被使用过的chunks;chunk中存放数据和chunk实际大小的差值;因为短期的数据集中在某个slab区域,致使大量page被分配,而以后被闲置的内存,这些即便有整个page的空闲也不会被分配给实际压力很大的slab区域(这个功能是否是之后memcached会考虑实现呢?)。 
相关文章
相关标签/搜索