memcached 是一套分布式的快取系统,当初是Danga Interactive为了LiveJournal所发展的,但被许多软件(如MediaWiki)所使用。这是一套开放源代码软件,以BSD license授权协议发布。[1]
memcached 仅支持一些非常简单的命令 比如get(获取某个键值) set(用来设定或保存一个缓存);
其本身是缓存服务器,但本身无法决定缓存任何数据,其缓存机制依赖于服务端和客户端两者必不可少(存储是由服务端进行存储,但存储什么是由客户端进行决定的)
因此客户端要自己提供缓存的键名以及时长、标志位、整个数据大小等等
例如:只存储hello 但只存储60秒
set key 5 60 hello
并告知服务器端,这样存储过了60秒后,由服务端进行清除数据
但是其工作机制非常独特,其缓存功能是基于Lazy模型的:
只要空间未满则不清理
那么问题来了:如果空间过小,而需缓存的内容过大的话,那么导致缓存抖动非常严重,存完即清理其次再去缓存这样会导致命中率下降,而毫无意义
有些时候,有些数据管理不善有可能导致缓存崩溃等
如果memcached崩溃仅导致业务层的影响,最多是速度降低 而不会导致数据层
memcached 如何实现缓存的
memcached 通过内存进行缓存数据,但并不实现持久缓存
存数数据的下限:
最小为48字节
最大不能超过1MB
但存储的数据大小有可能不一致,比如:
index.html10k
test.jpg34k
那memcached如何在内存中管理缓存数据
假如我们分别存储不同大小的数据以上为例
很显然只要分配一个足够大的空间就可以了,但是在内存中去找对应的数据我们必须要有对应的缓存对象的边界(起始存储位地址和结束存储位地址)将其当做独立的单位来管理
等其缓存失效了,空间会被腾出,时间久了可能会带来碎片,因为存储的都是非常小的数据单元,按理说如果再想高速利用则会困难,所以在这种机制下memcached的存储数据 查询数据等操作都是非常缓慢的
由此,不停快速基于内存的申请、释放反复操作,这种释放本身也消耗大量的资源和时间
因此我们需要一种高效的机制来解决内存的创建和释放的问题
对于memcached来讲首要必须解决这类内存碎片问题,不然由于内存的碎片导致进程运行的非常缓慢
在linux内核中引入了两种机制避免内存碎片
1.buddy system 伙伴系统
为了实现整个内存中以页面方式管理内存的时候有足够大的连续内存空间可用的,在物理内存中,事实上内存的管理和分配在内核级别通常以页面方式分配和使用的
通常是4k大小一个页面,buddy就是为了将这些零碎的、空闲的合并成一个连续的大的内存空间,这样就避免了页面之间产生碎片的,因此,其主要目的是为了避免内存外碎片
2.slab allocator slab 分配器
实现将存储小于页面单位的非常小的数据内存结构的时候之前事先分配并随时等待有需求的进程或要存储的对象使用,当我们使用之后它也不会自动消毁结构而是随时重复使用
避免内存内部碎片
最新版本的memcached使用的是增长因子(growth factor)来明确定义起始点开始依次增长
比如:
我们定义增长因子为其2倍
我们存储一个单位为48bytes,那么会分配其48*2 = 96bytes
如果增长因子为1.1倍
那么48+48*1.1
一旦存储空间满了,则会清理,没有存满则不会清理数据