Redis 与 Memcached 的比较相当多,首先我们比较一下他们的介绍。

Memcached:一款完全开源、高性能的、分布式的内存系统;

Redis:一个开源的、Key-Value 型、基于内存运行并支持持久化的 NoSQL 数据库;

可以发现,Memcached 更侧重于高性能内存 / 缓存系统,而 Redis 则支持持久化,主打数据库功能,兼可作缓存系统(性能也很高)。

下面有一个更加详细的比较表

对比参数 Redis Memcached
类型 1. 支持内存
2. 非关系型数据库
1. 支持内存
2. key-value 形式 < br />3. 缓存系统
数据存储类型 String、List、Set、Hash、Sort Set 文本型、二进制型
查询操作 1. 批量操作 < br />2. 支持事务 < br />3. 每个类型 CRUD 不同 CRUD 和少量其他命令
附加功能 1. 发布 / 订阅模式 < br />2. 主从分区 < br />3. 序列化支持 < br />4. 脚本支持 多线程服务支持
网络模型 单进程 IO 复用模型 多进程非阻塞 IO 模型
事件库 AeEvent LibEvent
持久化支持 RDB、AOF 不支持

网络模型

Memcached 是多线程非阻塞 IO 复用的网络模型 ,它由负责监听的主线程和子线程 worker 组成。主线程监听网络连接,每当接受到网络请求,将连接描述字传递给 worker 线程进行读写 IO 操作。Memcached 的网络层使用 libevent 封装的事件库。但多线程不可避免地会有缓存一致性和锁等问题,这里面带来了性能损耗。

Redis 是单线程 IO 复用模型 ,自己封装了一个简单的 AeEvent 事件处理框架,主要实现了 epoll, kqueue 和 select,对于单纯只有 IO 操作的业务场景来说,单线程可以将速度优势发挥到最大,但对于一些消耗 CPU 资源的计算性的操作例如 redis 提供的排序和聚合等,单线程模型施加会严重影响整体吞吐量,CPU 计算过程中,整个 IO 调度都是被阻塞的。

我们可以粗略得出结论, 在高并发场景的压力下,多线程非阻塞式 IO 的 Memcached 表现会更加优异。

内存管理机制

Memcached 和 Redis 都是由 C 语言开发,他们都是自主实现内存模型。

Memcached 的内存模式是 Slab Allocation。它有以下几个特点:

  1. Memcached 存储数据的最小单位是 chunk,这种设计是为了避免内存碎片的问题。chunk 的大小可以通过 Factor 来管理。
  2. Slab 和 Page 用于承装不同尺寸的 chunk。

  3. 不同尺寸 chunk 最终进入一个 slab_class 进行管理,便于访问。

数据访问流程,用户在 slab_class 找到合适尺寸的 slab,再通过某种方式找到 chunk,保证数据进入一个合适大小的 chunk 中存储,防止内存浪费。

相对于 Memecached,Redis 的内存管理要相对简单。

Redis 每一个数据块都是根据数据类型和大小来分配,每一块数据的元数据存入内存块头部。分配内存时,redis 调用 malloc 后返回首地址指针 real_ptr。redis 将内存块的大小 size 存入头部,size 本身所占据的内存大小是固定为 sizeof (typeof (size))。根据这个可以推算存储的数据的内存指针 ret_ptr。释放内存时,通过 ret_ptr 来推算 real_ptr 再调用 free 函数释放内存。

结论

Memcacehd 预分配内存池,用不同大小的内存单元来管理内存,数据选择合适的内存单元来存储。这样节省了申请 / 释放内存的开销,减少了内存碎片产生,但依然会带来内存空间浪费。Memcached 通过这种方式来最大化内存管理性能,是时间优先策略。

Redis 按需申请内存,Redis 会把带过期时间的数据单独存放在一起,这些数据是临时数据,临时数据会根据缓存过期策略来进行剔除。非临时数据则永远不会剔除。Redis 更好地利用了内存空间,是空间优先策略。

数据一致性

Redis 提供了事务,这种事务并非真正的事务实现。而且这种事务性操作容易造成线程阻塞。Memcached 会返回操作的结果,不会影响其他数据。

集群

Memcached 本身不支持集群,但它可以通过客户端来实现集群操作。它通过客户端上的程序库来封装了对集群服务器访问的接口,使得用户看起来似乎是在操作一个节点。客户端的程序通过 hash 算法来选择 memcached 节点,然后去访问对应的节点。

Redis 支持集群。各个节点之间通过二进制协议进行通信,节点与客户端之间通过 ascii 协议进行通信。

总结

  1. 如果业务更加侧重性能的高效性,对持久化要求不高,那么应该优先选择 Memcached。

    具体到业务有服务器的实时配置、存储 json 字符串等等。

  2. 对持久化有高需求,追求多类型数据支持,选择 Redis。

    具体到业务有排行榜类应用、社交关系存储、数据排重等等。