Redis 和 Memcached 的区别

Redis 和 Memcached 都是基于内存的数据库存储系统。MemCached 是高性能分布式内存缓存服务,Redis 是开源的 key-value 系统

比较

  1. Redis 支持更多的数据结构
  2. Redis 数据可以保存在磁盘
  3. Redis 支持数据持久化
  4. Redis 可通过主从模式备份数据
  5. Redis 只使用单核,MemCached 支持多核

数据结构

Redis 支持以下数据结构:

  1. String
  2. Hash
  3. List
  4. Set
  5. Sorted Set
  6. pub/sub
  7. Transactions

MemCached 只支持 Key-value,通过数据库保存对象信息时,MemCached 通常有两种做法:

  1. Key 作为对象唯一标识,Value 记录对象序列化后的字符串
  2. Key 作为对象唯一标识 + 属性,Value 记录具体属性值信息

方法1在修改对象属性时,需要将对象取出来反序列化,修改完后再更新进去。方法2 Key 占据了更大资源,并且处理起来麻烦,总的来说都不太好。

Redis 可以使用 Hash 结构,Key 作为对象唯一标识,Value 采用哈希结构,Key 记录属性名称,Value 记录具体值,相比 MemCached 更好使。

由于支持更多的数据结构,redis 的使用场景更多


内存管理机制

Redis 并不是所有数据都保存在内存,当内存使用达到阈值时,Redis 根据最近访问时间和内存的大小,将一部分 Key 对应的 value 持久化到磁盘,同时从内存中删除这部分 value,只保存 key。因此,Redis 可以保存超过本机内存大小的数据,但必须保证所有的 Key 能保存下来,Key 不会持久化到磁盘。每次持久化 Value 时,Redis 会阻塞主服务线程, 首先通过子线程完成数据的持久化。当我们查询 Key 对应的 Value 在持久化文件中时,需要 Redis 从文件中加载相应数据,此时就涉及到 I/O 操作,I/O 操作期间阻塞,对于高并发场景,需要我们在 Redis 设置 I/O 线程池,并发的从文件读取数据,减少阻塞时间。

Memcached 在内存不足时,会直接丢弃一部分数据,不会交换到磁盘中

Redis 和 Memcached 都没有使用 malloc / free 函数来分配释放内存:

  • 不匹配的 malloc 和 free 很容易造成内存泄露
  • 频繁调用 malloc 和 free 函数很容易产生大量内存碎片,降低内存利用率
  • malloc 和 free 都是系统调用,涉及用户态到内核态的切换,效率低下

Memcached 默认使用 Slab Allocation 机制管理内存,它的主要思想是将分配的内存分割为多个特定长度的块(Chunk),并把尺寸相同的块分成组(Slab Class)。其中 Chunk 就是保存 Key-Value 的最小单位。Slab Allocation 只针对外部数据,也就是所有的 Key-Value,Memcached 的其它请求仍通过 malloc、free 实现,由于这部分体量小,不会影响到 Slab Allocation 的效率。

当 Memcached 接收到客户端发送过来的数据时,首先根据收到数据的大小选择合适的 Slab Class,然后从 Slab Class 中找到合适的 Chunk 来保存数据。当一条数据过期或者需要丢弃时,回收该 Chuck 内存即可。

这样做的好处在于不会产生内存碎片,缺点在于内存利用率低,假设一个 Chunk 128 字节,它保存了 100 字节的 Key-Value,那么剩下的 28 字节就浪费掉了。

Redis 通过包装 malloc、free 函数实现内存管理。在分配一块内存后,redis 会将这块内存的大小存入内存块的头部。如果所示,real_ptr 是调用 malloc 返回的指针,redis 将内存块的大小存入头部,size 所占据的大小是已知。当需要释放内存时,通过 ret_ptr 可以计算出 real_ptr,然后将 real_ptr 传给 free 释放内存

redis 内存管理
总得来说 redis 内存管理相比 Memcached 简单很多。但由于 redis 用到了磁盘,因此在磁盘上的查询效率肯定没有 MemCached 高


数据持久化支持

Memcached 不支持数据持久化,而 Redis 支持两种数据持久化方式:

  • RDB 快照
  • AOF 日志

Redis 借助 fork 命令的 copy on write 机制,在进程中 fork 出一个子进程,子进程循环当前数据,将数据写成 RDB 文件。其中我们可以通过 Redis save 指令配置 RDB 的生成时机。由于基于子进程实现,因此 Redis 异常不会导致 RDB 文件坏掉,不过从上次 RDB 文件生成到 Redis 停机这段时间的数据会丢失。

AOF 日志全称是 append only file,它是一个可识别的纯文本日志,记录所有导致数据发生修改的 redis 命令。随着 Redis 的运行,AOF 文件会越来越大,Redis 在此基础上提供了 rewrite 功能,其功能会重新生成新的 AOF 文件,新的 AOF 文件每条记录只会记录最新一次操作。

AOF 日志的生成和 RDB 类似,都是通过 fork 子进程,直接遍历数据,写入新的 AOF 临时文件。在写入新的 AOF 临时文件期间 redis 仍处理其它指令,这部分指令会写入老 AOF 文件以及内存缓冲区中。当新文件遍历完数据后,Redis 将内存缓冲区中所有指令写入新文件中,调用 rename 系统调用修改文件名覆盖原文件。

在 Redis 中对 AOF 调用 write 操作后,通过设置 appendfsync 属性来控制调用 fsync 将其写到磁盘上的时间:

  • no:不主动调用 fsync ,完全根据操作系统调度
  • everysec:每秒调用一次
  • always:每一次写操作调用一次

随着频率的增高,安全性更高,但相应性能更差,一般情况下建议使用 RDB 快照,如果不能忍受数据丢失,建议使用 AOF 日志,AOF 日志对性能有稍许影响。

总得来说,Redis 突然宕机可以通过持久化恢复,而 Memcached 宕机数据会直接丢失。


集群管理方式不同

Memcached 本身不支持分布式,只能在客户端通过一致性哈希算法来实现分布式。每次 set 数据时,首先根据哈希算法计算应该存储的节点,然后将数据发送到目标节点上存储。每次获取数据时,首先查询数据所在节点,然后去对应节点存储。

Redis 更偏向于在服务端实现分布式存储。Redis Cluster(集群) 是一个实现分布式且允许单点故障的 Redis 高级版本,它没有中心节点,并且可以线性扩展。节点和节点之间通过二进制协议通信,节点和客户端之间通过 ascii 协议通信。其中 Redis Cluster 将整个 key 的数据域划分为 4096 个哈希槽,每个节点存储一个或多个哈希槽。

redis分布式算法:crc16( key ) % HASH_SLOTS_NUMBER。

为了保证单个节点的数据安全性,Redis Cluster 引入 master 和 Slave 节点。每个 master 节点包含两个 Slave 节点。任何两个节点的宕机都不会导致数据的不可用,Master 节点退出后,集群会从 Slave 节点中选出一个新的 Master 节点。


2021-08-03 新增内容:之前写这篇博客参考的 redis 版本较老,部分功能实际已经废弃,后文新增较新版本的比较:

  1. 数据结构:memcached 只支持 String 类型,redis 支持更多数据类型
  2. 数据存储:redis 和 memcached 都只支持内存(redis value 转移磁盘已废弃)
  3. 持久化:redis 支持 rdb 和 aof、memcached 不支持持久化
  4. 容灾恢复:redis 可通过持久化文件恢复,memcached 无法恢复
  5. 过期键删除:redis 使用惰性 + 定期,memcached 使用惰性
  6. 内存淘汰策略:redis 支持 8 中策略,memcached 主要使用 LRU
  7. 性能:由于 redis 单线程,memcached 多线程,memcached 大多数场景下性能更好
  8. 水平扩展实现:redis cluster 集群服务端实现水平扩展,memcached 只能在客户端通过一致性 hash 算法实现水平扩展
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值