memcached是应用较广的开源分布式缓存产品之一,它本身其实不提供分布式解决方案。
在服务端,memcached集群环境实际就是一个个memcached服务器的堆积,环境搭建较为简单。
cache的分布式主要是在客户端实现,通过客户端的路由处理来达到分布式解决方案
客户端做路由的原理非常简单:
应用服务器在每次存取某key的value时,通过某种算法把key映射到某台memcached服务器nodeA上,因此这个key所有操作都在nodeA上
memcached客户端采用一致性hash算法作为路由策略
相对于一般hash算法,一致性hash除了计算key的hash值外,还会计算每个server对应的hash值,然后将这些hash值映射到一个有限的值域上(比如0~2^32)。
- 通过寻找hash值大于hash(key)的最小server作为存储该key数据的目标server
- 如果找不到,则直接把具有最小hash值的server作为目标server
同时,一定程度上,解决了扩容问题,增加或删除单个节点,对于整个集群来说,不会有大的影响
最近版本,增加了虚拟节点的设计,进一步提升了可用性。
memcached仅支持基础的key-value键值对类型数据存储
在memcached内存结构中有两个非常重要的概念:slab和chunk
slab是一个内存块,memcached一次申请内存的最小单位
在启动memcached的时候一般会使用参数-m指定其可用内存,但并非在启动的那一刻所有的内存就全部分配,只有在需要的时候才会去申请,而且每次申请一定是一个slab
slab的大小固定为1M,一个slab由若干个大小相等的chunk组成
每个chunk中都保存了一个item结构体、一对key/value
虽然在同一个slab中chunk的大小相等的,但是在不同的slab中chunk的大小并不一定相等
在memcached中按照chunk的大小不同,可以把slab分为很多种类(class),默认情况下memcached把slab分为40类(class1~class40),在class 1中,chunk的大小为80字节,由于一个slab的大小是固定的1M,因此在class1中最多可以有13107个chunk(也就是这个slab能存最多13107个小于80字节的key-value数据)
memcached内存管理采取预分配、分组管理
- 分组管理就是我们上面提到的slab class,按照chunk的大小slab被分为很多种类
- 内存预分配过程是怎样的呢?
向memcached添加一个item时候,memcached首先会根据根据item的大小,来选择最合适的slab class
计算好所要放入的chunk之后,memcached会去检查该类大小的chunk还有没有空闲
- 如果没有,将会申请1M(1个slab)的空间并划分为该种类chunk
例如我们第一次向memcached中放入一个190字节的item时,memcached会产生一个slab class 2(也叫一个page),并会用去一个chunk,剩余5241个chunk供下次有适合大小item时使用,当我们用完这所有的5242个chunk之后,下次再有一个在160~200字节之间的item添加进来时,memcached会再次产生一个class 5的slab(这样就存在了2个pages)
总结来看,memcached内存管理需要注意
chunk是在page里面划分的,page固定为1m,所以chunk最大不能超过1m
chunk实际占用内存要加48B,因为chunk数据结构本身需要占用48B
如果用户数据大于1m,则memcached会将其切割,放到多个chunk内
已分配出去的page不能回收
对于key/value信息,最好不要超过1m的大小
同时信息长度最好相对是比较均衡稳定的,这样能够保障最大限度的使用内存
同时,memcached采用的LRU清理策略,合理甚至过期时间,提高命中率
无特殊场景下,key-value能满足需求的前提下,使用memcached分布式集群是较好的选择,搭建与操作使用都比较简单
分布式集群在单点故障时,只影响小部分数据异常,目前还可以通过Magent缓存代理模式,做单点备份,提升高可用
整个缓存都是基于内存的,因此响应时间是很快,不需要额外的序列化、反序列化的程序,但同时由于基于内存,数据没有持久化,集群故障重启数据无法恢复
高版本的memcached已经支持CAS模式的原子操作,可以低成本的解决并发控制问题
缺点
无法容灾、持久化。