土法炼钢兴趣小组的算法知识备份

【Redis / 缓存内核】Memcached 对照:多线程 slab 与纯缓存何时胜出

文章导航

分类入口
databasestorage
标签入口
#redis#memcached#slab#multithread#scaling-memcache#cache-aside#encoding#nsdi-2013#comparison

目录

团队把 Memcached 换成 Redis「因为功能更多」,半年后 AOF rewrite 与 fork 延迟进了 on-call 台账,而业务其实只需要 get/set 旁路缓存——这类 工具升格缓存架构 的 Cache-Aside 场景里并不少见。Memcached 与 Redis 不是同一抽象层的两个实现;前者是 多线程纯缓存,后者是 单线程执行命令的数据结构服务器(可选持久化)

本文是「Redis / 缓存内核」系列第 14 篇(共 16 篇)。→ 系列目录

版本锚定:Redis OSS 7.4 / 8.x;Memcached 以经典 1.6.x 线程+slab 模型为对照(具体发行版以部署为准)。


一、问题定义:谁在优化什么

Nishtala et al. Scaling Memcache at Facebook(NSDI 2013)把 Memcached 定位为 大规模 Web 服务的 DRAM 聚合层:配合 MySQL 等权威库,用 leases 缓解击穿、用 Gutter 做集群部分失效降级、用 客户端一致性哈希 做水平扩展。论文 measured 的是 端到端 Web 工作负载 下的延迟与失效模式,不是「Memcached vs Redis 单线程 benchmark 谁 QPS 更高」——后者缺少论文级公开对照,本篇 不给出伪造吞吐排名

Redis 的设计目标(官方 Overview 与 antirez 历史设计笔记)是 丰富数据结构 + 可选 durability:List/Hash/ZSet/Stream 留在内存里直接操作,RDB/AOF 把进程内状态接到 持久化语义。这是 不同产品类 的分叉,不是「Memcached 加持久化」。


二、架构对照

flowchart TB
  subgraph MC["Memcached"]
    W1["worker thread"]
    W2["worker thread"]
    S["slab class allocator"]
    W1 --> S
    W2 --> S
  end
  subgraph RD["Redis 7.4/8.x"]
    M["main thread: command exec"]
    IO["optional IO threads: read/write"]
    E["redisObject encodings"]
    P["optional RDB/AOF"]
    IO --> M
    M --> E
    M --> P
  end
维度 Memcached Redis
执行模型 多 worker 线程处理连接 主线程执行命令;IO threads 仅卸载读写(第 2 篇
值表示 opaque blob;无类型系统 type + encoding 多态(第 3–5 篇
内存分配 slab class 预分配固定尺寸页 jemalloc/tcmalloc + 对象编码;紧凑结构可省内存
过期 LRU 于 slab 内;惰性 全局 expires + 主动采样(第 7 篇
分片 客户端一致性哈希 单机 / Sentinel / Cluster slot第 13 篇
持久化 无(重启空) RDB / AOF / 混合
典型协议 文本二进制 Memcache RESP

三、Slab 分配器:吞吐与碎片的两面

Memcached 把内存划成 slab class(按 chunk 尺寸分级),每类一批页;分配/释放主要在固定尺寸 chunk 上完成,避免通用分配器锁争用,利于 多线程水平扩展 CPU

代价:

  1. 尺寸离散:值略大于某 class 即占用更大 chunk,内部碎片 可见;stats slabs 可观察(需真实实例,本篇不粘贴伪造输出)。
  2. 无细粒度结构:无法把一个小 Hash 嵌在对象头里——一切皆是 blob。
  3. 扩容缩容:class 划分在启动参数中大致固定,调优偏运维经验。

Redis 用编码(listpack、intset 等)在 小集合 上省内存,但编码升级与 单线程执行 使 CPU 饱和点与 Memcached 多线程不同;比较二者必须声明 值大小分布、命令 mix、是否持久化,否则结论不可移植(WRITING_GUIDE 口径)。


四、Facebook 论文与 Cache-Aside 工程

architecture/17 已讲 Cache-Aside、击穿、雪崩;NSDI’13 的增量在于 工业规模下的失效语义

机制 论文要点 与 Redis 实践对照
Leases 短期租约,防止陈旧回填 Redis 无内建 lease;可用逻辑 TTL + 版本号或 Redlock 争议方案(非本篇展开)
Gutter 部分 Memcached 挂掉时短期全局降级 需应用/代理层设计;非 Redis 内建
一致性哈希 + 副本 降低热点与节点抖动 Redis Cluster 用 slot + 主从,范式不同

论文隐含假设:权威数据在 MySQL,缓存可随时丢弃重建。Redis 若启用 AOF/RDB 且被当作 半权威 store(计数、会话、队列),故障模型从「穿透回源」变成「恢复 + fsync + 复制滞后」——运维复杂度上一个数量级。


五、何时纯缓存(Memcached)更合理

下列场景 倾向 Memcached 或等价纯缓存,而非默认 Redis:

  1. 严格 Cache-Aside:值永远可回源重建;丢失缓存等于 miss,无业务副作用。
  2. 值形态单一:大 blob 或小字符串;不需要 Hash/ZSet/Stream 原子操作。
  3. 多核线性扩展读吞吐:CPU 为瓶颈、值尺寸适配 slab、无持久化硬需求
  4. 希望运维面极简:无 fork、无 AOF rewrite、无复制 backlog 规划(仍要处理哈希扩缩容)。
  5. 团队已落地 Facebook 式多层缓存:MC 作 L2,本地 Caffeine 作 L1(见 storage/66)。

六、何时 Redis 更合理

  1. 数据结构即 API:排行榜 ZINCRBY、去重 SET、队列 LPUSH/BRPOP、Stream 消费组。
  2. TTL 精细 + 内存策略maxmemory + 近似 LRU/LFU(第 8 篇)。
  3. 需可控 durability:RDB 快照、AOF everysec、混合(第 9–11 篇);接受 fork/fsync 代价。
  4. 原生复制 / Cluster:slot 事务边界清楚,替代自研一致性哈希客户端(第 12–13 篇)。
  5. 模块生态:Redis Stack / 模块(JSON、Search)——边界见 第 16 篇

七、协议与客户端栈差异

Memcached 常见文本协议与二进制协议;Redis 统一 RESP3/RESP2。对 libevent redis-lite 一类玩具实现,RESP 入门足够;生产则要分清:

话题 Memcached Redis
连接复用 多线程下连接亲和常见 单连接 pipeline 友好;注意 CLIENT PAUSE 等管理命令
CAS gets/cas 防并发写覆盖 WATCH/MULTI 或 Lua;语义更重
TTL 精度 秒级过期 秒/毫秒(依版本与命令)
集群客户端 一致性哈希库 Cluster slot 表 + MOVED 处理

NSDI’13 还强调 invalidation daemon(McRouter 等)做跨机房一致性;Redis 侧常用 发布订阅 / keyspace notification 做失效广播,复杂度和可靠性需自行论证——两种都不是「开箱即全局一致」。


八、常见误解

误解 事实
「Redis 总是比 Memcached 快」 无统一 benchmark;多线程 Memcached 在纯 get/set、合适 slab 时可能更省 CPU;Redis 优势常在 结构与命令语义
「Memcached 不能做大缓存」 Facebook 论文是反例;关键是 集群分片 + 失效策略,非单机上限
「上了 Redis 就可以不要 DB」 持久化保证的是 Redis 自身崩溃,不是业务级事务与权威建模;Cache-Aside 仍应以 DB 为源
「slab 一定比 jemalloc 省内存」 slab 内部碎片在大值分布不均时很明显;Redis 紧凑编码在小对象场景常更省
「多线程一定优于单线程」 Redis 用 IO threads 减轻网络栈负担,但 命令仍串行;高争用写仍会打满主线程

九、学术谱系、争论与开放问题

谱系:OSDI’00 前后 Web 缓存实践 → Memcached(Brad Fitzpatrick)→ NSDI’13 Facebook 工业尺度 → Redis 数据结构服务器 → 云厂商托管双轨。

争论

  1. 单一缓存 vs 多模型服务器:「只用 Memcached + DB」派强调简单与故障域;「Redis 一站式」派承担持久化与集群运维,换取产品迭代速度——无 universally 正确,取决于失效代价。
  2. 客户端哈希 vs Cluster slot(链 algorithms/11):Memcached 传统前者;Redis Cluster 用后者——迁移与多 key 语义不同,不能互换客户端。

开放问题


十、小结

三句话小结

  1. Memcached 是 多线程 + slab 的纯缓存;Redis 是 单线程执行命令 + 多态编码 + 可选持久化 的数据结构服务器——产品类不同,勿用功能数量代替场景匹配。
  2. Facebook NSDI’13 教的是 大规模 Cache-Aside 的失效与降级,不是 Redis 替代论;权威在 DB 时 Memcached 往往更轻。
  3. 需要结构操作、durability、复制/Cluster 时选 Redis;只需可重建 blob 缓存、要多核线性读时认真考虑 Memcached。

下一篇收束运维信号:生产排障


参考资料

论文(A 级)

  1. Nishtala, R. et al., Scaling Memcache at Facebook, NSDI 2013(leases、Gutter、一致性哈希与失效语义)。

文档与源码(A 级)

  1. Memcached Wiki / Documentation, Memory Allocation(slab class)。
  2. Redis Documentation, OverviewPersistenceIO threads
  3. Redis OSS 7.4 src/object.csrc/ae.c(对照执行模型)。

辅助(B 级)

  1. 缓存架构缓存工程
  2. 对象编码Cluster系列 index

返回 系列目录 | 上一篇:Cluster | 下一篇:生产排障

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。


By .