# MemCache

https://memcached.org

# 简介

MemCache 是一个自由、源码开放、高性能、分布式的分布式内存对象缓存系统。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高了网站访问的速度。

MemCaChe 是一个存储键值对的 HashMap,在内存中对任意的数据使用的 key-value 存储。

# 访问流程

1、应用程序输入需要写缓存的数据
2、API 将 Key 输入路由算法模块,路由算法根据 Key 和 MemCache 集群服务器列表得到一台服务器编号
3、由服务器编号得到 MemCache 及其的 ip 地址和端口号
4、API 调用通信模块和指定编号的服务器通信,将数据写入该服务器,完成一次分布式缓存的写操作

MemCache 虽然被称为 "分布式缓存",但是 MemCache 本身完全不具备分布式的功能,MemCache 集群之间不会相互通信,所谓的 "分布式",完全依赖于客户端程序的实现。

# 路由算法

和负载均衡算法一样,路由算法决定着究竟该访问集群中的哪台服务器。

1、余数 Hash
把 key 的 hash 对服务器集群数量取余。
服务器数量改变的时候会发生缓存无法命中

解决方案:在访问低谷的时候扩容,模拟请求预热数据。

2、一致性 Hash 算法
先建立一个一致性 hash 环,环的大小是 [0,2^32-1]
给服务器一个 hash 值,根据值在排在 hash 环上,排完了之后。
如果要查询一个 key,拿到 key 的 hash 值,在这个环上顺时针找服务器,最近的服务器就是目标服务器。
如果服务器增加,对缓存服务器影响没那么大,集群中的服务器节点越多,增加节点带来的影响越少。

2^32 的一致性环通常使用二叉查找树实现

# 实现原理

内存结构

MemCache 采用的内存分配方式是固定空间分配。
涉及了 slab_class、slab、page、chunk 四个概念。

1.slab_class 里,存放的是一组组 chunk 大小相同的 slab
2. 每个 slab 里面包含若干个 page,page 的默认大小是 1M,如果 slab 大小 100M,就包含 100 个 page
3. 每个 page 里面包含若干个 chunk,chunk 是数据的实际存放单位,每个 slab 里面的 chunk 大小相同

内存分配方式

Memcached 利用 slab allocation 机制来分配和管理内存,它按照预先规定的大小,将分配的内存分割成特定长度的内存块,再把尺寸相同的内存块分成组,数据在存放时,根据键值大小去匹配 slab 大小,找就近的 slab 存放。

存放数据时,首先 slab 要申请内存,申请内存是以 page 为单位的。所以在放入第一个数据的时候,无论大小为多少,都会有 1M 大小的 page 被分配给该 slab。申请到 page 后,slab 会将这个 page 的内存按 chunk 的大小进行切分,这样就变成了一个 chunk 数组,最后从这个 chunk 数组中选择一个用于存储数据。

就是说,value 最大是 1M

如果没地方存了,就进行内存回收。

内存回收方式

当数据容量用完 MemCached 分配的内存后,就会基于 LRU (Least Recently Used) 算法清理失效的缓存数据(放入数据时可设置失效时间),或者清理最近最少使用的缓存数据,然后放入新的数据。

在 LRU 中,MemCached 使用的是一种 Lazy Expiration (惰性失效) 策略,自己不会监控存入的 key/vlue 对是否过期,而是在获取 key 值时查看记录的时间戳,检查 key/value 对空间是否过期,这样可减轻服务器的负载。

如果如果 MemCache 启动没有追加 - M 命令,则表示禁止 LRU,这种情况下内存不够会报 Out Of Memory 错误。

MemCache 的 LRU 算法不是针对全局的,是针对 slab 的

# 特性和限制

MemCache 单进程在 32 位机中最大使用内存为 2G,64 位机则没有限制。
Key 最大为 250 个字节,超过该长度无法存储
MemCache 设置添加某一个 Key 值的时候,传入 expiry 为 0 表示这个 Key 值永久有效,这个 Key 值也会在 30 天之后失效

memcache 无法备份和持久化,崩溃或重启之后数据将全部丢失。

更新于
-->