Redis 和 Memcached 的区别?
结论:两者都是内存 KV,但定位已经分叉。Memcached 是纯粹的「多线程 + 内存对象缓存」,只做字符串缓存;Redis 是「单线程命令模型 + 丰富数据结构 + 可持久化 + 原生集群」的数据结构服务器。今天选 Memcached 的唯一理由是:价值极低、可随意丢失、纯字符串、需要吃满多核的极致读缓存,其余场景一律 Redis。
一、核心维度对照
| 维度 | Redis | Memcached |
|---|---|---|
| 数据模型 | String/List/Hash/Set/ZSet/Stream 等 | 仅 key → bytes |
| 线程模型 | 命令执行单线程,6.0 起 IO 多线程 | 多线程 worker,天然吃多核 |
| 持久化 | RDB、AOF、混合持久化 | 不支持,重启即空 |
| 高可用 | 主从、哨兵、Cluster | 无原生方案,靠客户端一致性哈希 |
| 集群分片 | 16384 槽,服务端负责路由 | 客户端分片,服务端互不通信 |
| 淘汰策略 | 8 种(LRU/LFU/random/ttl/noeviction) | 近似 LRU(分段 LRU) |
| 单 value 上限 | 512 MB | 1 MB(默认,可调但影响 slab) |
| 事务/脚本 | MULTI/EXEC、Lua、函数 | CAS(gets/cas)、incr/decr |
| 过期 | 惰性 + 定期删除,支持毫秒级 | 惰性删除,到期不主动回收内存 |
| 内存管理 | jemalloc + 主动整理 | slab allocator,按 chunk 定长分配 |
| 协议 | RESP | 文本协议 + 二进制协议 |
二、线程模型差异决定了什么
Redis(6.0 之前) Memcached
┌──────────────────┐ ┌───────────────────────────┐
│ 主线程 │ │ 主线程 accept │
│ ├─ epoll 就绪 │ │ ├─ worker-1(epoll) │
│ ├─ 解析/执行命令 │ │ ├─ worker-2(epoll) │
│ └─ 回写响应 │ │ └─ worker-N(epoll) │
└──────────────────┘ └───────────────────────────┘
一条命令串行执行 多连接并行执行,共享哈希表加锁
Redis 单线程命令执行换来的是无锁、无竞态、可原子组合(Lua、MULTI),代价是单实例只能压满一个核,需要靠多实例或 Cluster 横向扩展。Memcached 多线程能直接吃满多核,但跨 key 的原子操作只能靠 CAS 重试,做不到"读-改-写"一次原子完成。
三、内存分配与过期行为的差别
Memcached 的 slab allocator 把内存切成固定大小的 chunk,写入时按 value 大小落到对应 slab class。好处是无碎片、分配极快;坏处是不同 slab class 之间不能借内存,出现"总量没满但某类 chunk 用尽"的 OOM。过期 key 只是标记,不主动腾内存,只有新写入复用该位置时才回收。
Redis 用 jemalloc,key 到期后由惰性删除 + 定期删除回收,配合 maxmemory 触发淘汰,能做到"内存到顶就按策略挤掉旧数据"。
# Memcached 常用启动参数
memcached -m 4096 -c 8192 -t 8 -I 2m
# -m 内存 MB,-c 最大连接数,-t worker 线程数,-I 单 item 上限
# Redis 对应能力靠配置 + 命令
redis-cli CONFIG SET maxmemory 4gb
redis-cli CONFIG SET maxmemory-policy allkeys-lru
redis-cli INFO memory | grep used_memory_human
# redis.conf 关键片段
maxmemory 4gb
maxmemory-policy allkeys-lru
appendonly yes
appendfsync everysec
四、什么情况下真的会选 Memcached
| 场景特征 | 建议 | 原因 |
|---|---|---|
| 纯 HTML 片段 / 小对象缓存,命中即返回 | 可以 Memcached | 多线程吃满多核,逻辑极简 |
| 需要计数器、排行榜、去重集合 | Redis | Memcached 只有 incr,复杂结构要应用层拼 |
| 缓存需要高可用、扩容不丢数据 | Redis | Memcached 客户端分片扩容要搬 key |
| 一次请求要读写多个 key 且需原子 | Redis | Lua / MULTI 一次往返完成 |
| 数据允许全丢、只要最快吞吐 | 两者都可,看压测 | 同机同连接下差异通常在 10% 量级 |
五、常见追问
- 问:既然 Redis 单线程,为什么吞吐还比 Memcached 高?答:通常不是单机极限更高,而是 Redis 省掉了网络往返次数——一次 Lua 或一个 ZSet 命令能做到 Memcached 要多次 get/set 才能完成的事。
- 问:Memcached 支持集群吗?答:服务端不支持互相通信,分片由客户端(如 spymemcached 的一致性哈希)完成,扩缩容时需处理数据倾斜。
- 问:多线程一定更快吗?答:在纯 GET/SET 的短连接压测中 Memcached 有优势;但业务一旦需要原子计数、有序集合、分布式锁,Redis 少一次网络交互就赢回来了。
- 问:Memcached 的 CAS 和 Redis 的 WATCH 有何不同?答:CAS 是单 key 版本号比较后写入,WATCH 是监视多个 key、EXEC 时整体失败,后者不能回滚已执行的命令。
- 问:能否只用 Redis 做纯缓存,关掉持久化?答:可以,
save ""+appendonly no,此时它就是个功能更多的 Memcached。 - 问:Memcached 的 1 MB 上限怎么绕过?答:调
-I提高单 item 上限,但会新增更大的 slab class,挤压其他类的内存;更常见的做法是把大对象压缩或拆成多个 key。
小结
- 差异的根在三点:数据模型(字节 vs 结构)、线程模型(串行 vs 并行)、集群与持久化能力。
- Memcached 的 slab 与多线程在小 value 纯缓存上仍有价值,但没有持久化、没有原生分片是硬伤。
- 现代架构默认选 Redis;只有明确"缓存可全丢、只要字符串、要压满多核"时,才值得把 Memcached 拿出来比较。