简介
- 官网: http://memcached.org/
- Github:https://github.com/memcached/memcached
一款高性能,分布式内存对象缓存系统。
使用目的
缓存数据查询结果,减少数据库访问次数,以提高Web应用的响应速度、提高可扩展性。
特点
- 互不通信的分布式方式,服务端自身不提供实现,由客户端实现
- 内置内存存储机制,不支持数据持久、数据同步
- 仅支持Key-Value数据结构
- 支持多线程,基于LibEvent事件处理(参考:https://www.jianshu.com/p/98a02d771b2d)
内存分配机制(Slab Allocation)
- Chunk:Memcached中存放数据的最小单元(Key、Value)。
- Page:由多个相同大小的Chunk组成。固定大小,默认值为1M,可以通过启动参数
-I
设定。 - Slab :由多个相同大小的Page组成。
原理
- 启动Memcached时,立即分配
-m
参数设定大小的内存,并按Page的大小分割成多个Page。 - 当Slab申请内存时,将分配一个可用的Page,并按照Slab的Chunk大小分割成多个Chunk。
- 当数据被存储时,会分配到内存浪费最少的Slab中。
优点
- 不会产生系统内存碎片
缺点
- 内存浪费
- Slab中的每个Chunk大小是固定的,当存储的数据小于Chunk大小,则产生少量不可使用的内存
- Page的大小也是固定的,当分割成固定大小的Chunk时,可能剩余不足以分割的内存
- 按照Growth Factor因子生成指定大小的Slab,而某Slab的Id根本未被使用时,会出现内存浪费
调优
- Memcached 在启动时指定 Growth Factor 因子(
-f
),就可以在某种程度上控制 Slab 之间的
差异。默认值为 1.25。最佳值应该通过分析数据的平均长度而定
- Memcached 在启动时指定 Growth Factor 因子(
-f
),就可以在某种程度上控制 Slab 之间的
差异。默认值为 1.25。最佳值应该通过分析数据的平均长度而定
内存回收机制(LRU)
- 数据不会过期删除:Memcached 不会释放已分配的内存,存储空间利用LRU机制重复使用
- 缓存延迟失效机制:Memcached 不会主动监控缓存失效,而是使用Get时查看记录的时间戳,是否已过期。
- LRU缓存删除
- 优先使用已经超时的内存空间
- 当没有可使用的空间时,将查找最近未被使用的记录,并将空间直接分配给新的记录
分布式机制
-
余数计算分散算法
- 根据服务器台数的余数进行分散。虽然分散性优秀,但是新增或删除服务器时,缓存不可避免会重组,缓存命中率骤降,严重时会将数据压力集中到数据库服务器,导致无法正常提供服务。
-
一致性哈希算法(Consistent Hashing)
- 首先求出Memcached服务器节点的哈希值,并将其分配到0~2^32 的圆上,这个圆我们可以把它叫做值域,然后用同样的方法求出存储数据键的哈希值,并映射到圆上。然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器上,如果超过0~2^32仍找不到,就会保存在第一台memcached服务器上:
- 再抛出上面的问题,如果新添加或移除一台机器,在consistent Hashing算法下会有什么影响。上图中假设有四个节点,我们再添加一个节点叫node5:
- node5被放在了node4与node2之间,本来映射到node2和node4之间的区域都会找到node4,当有node5的时候,node5和node4之间的还是找到node4,而node5和node2之间的此时会找到node5,因此当添加一台服务器的时候受影响的仅仅是node5和node2区间。
缓存命中率
命中率 = get成功次数 / get总次数
命中率越高意味着访问数据库的次数越少,带来的性能提升也是最大的。
注意事项
- 使用缓存一定是读多写少,实时性较高的数据不适用缓存
- Page默认值为1MB,所以数据大小受限于Page大小,处理方案:
- 数据分片存储,降低单个Chunk大小
- 利用客户端实现gzip压缩数据
- Page默认值调高,但可能导致内存浪费率增高,需具体分析后处理,建议作为最终办法
参考文献
- 《Memcached全面解析》
- https://my.oschina.net/andylucc/blog/671447
- http://breezylee.iteye.com/blog/2101605
- https://www.cnblogs.com/dinglang/p/6133501.html