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

【Redis / 缓存内核】缓存服务器全景:HashMap · Memcached · Redis · 嵌入 KV

文章导航

分类入口
databasestorage
标签入口
#redis#memcached#cache#hashmap#rocksdb#embedded-kv#data-structure-server#resp#redis-kernel

目录

读完 缓存架构 的 Cache-Aside 与击穿治理,或 缓存工程 的多级缓存之后,工程师往往已经会「在应用旁挂一层 Redis」。但若被追问 进程内 HashMap 与网络缓存的边界在哪、Memcached 与 Redis 差的是线程还是数据结构、嵌入 RocksDB 何时该替代 Redis,答案容易滑向「看场景」而缺少可核对的机制地图。

本文是「Redis / 缓存内核」系列第 1 篇。目标不是重复五种读写模式全文,而是回答三个定位问题:

  1. 进程内 HashMap、Memcached、Redis、RocksDB 嵌入 KV 在同一问题轴上各占哪一段?
  2. 本系列与 architecture/17storage/66linux/redis-source(Redis 4.0 Org 情景)、libevent redis-lite 如何分工?
  3. 后续 16 篇按什么依赖顺序读,才能把「一条命令落到内存对象」串起来?

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

篇目 核心内容
第 1 篇 · 缓存服务器全景 四类 KV 生态位、相邻系列分工、16 篇地图
第 2 篇 · 事件循环与 I/O aeEventLoop、客户端缓冲、IO threads 边界
第 3 篇 · 对象模型与 SDS redisObject、type/encoding、SDS

版本锚定:Redis OSS 7.4 / 8.x(本系列源码路径与官方文档);Memcached 作第 14 篇对照;linux/redis-source 锚定 4.0 历史路径。

环境说明:本篇以架构定位与文献谱系为主,不粘贴未执行的 redis-benchmarkINFO 数字;机制边界来自 Redis 官方文档与 7.4.x 源码结构。


一、四类内存 KV 生态位

把「缓存 / KV」按 部署边界值语义 粗分四格,便于后续选型与读源码时不混层。

flowchart LR
  subgraph process["In-Process"]
    HM["HashMap / ConcurrentMap"]
    RK["RocksDB / LevelDB embed"]
  end
  subgraph network["Network Service"]
    MC["Memcached<br/>opaque blob + slab"]
    RD["Redis<br/>typed objects + optional persistence"]
  end
  HM -->|"miss / capacity"| MC
  HM -->|"local durable state"| RK
  MC -.->|"richer types / persistence"| RD
形态 典型 API 值模型 持久化 多进程共享 主要代价
进程内 HashMap map.put(k,v) 语言原生对象 无(随进程消失) 堆内存、GC/STW、无跨实例一致性
Memcached get/set + slab opaque blob 默认无 是(分片在客户端) 功能单一;多线程与 slab 碎片(第 14 篇)
Redis RESP 命令 string/list/hash/zset/stream… RDB/AOF 可选 是(单机/Cluster) 单主线程执行命令 + 编码/持久化复杂度
RocksDB 嵌入 KV Put/Get/Iterator 字节序列 + CF WAL + SST 默认有 否(库嵌入进程) Compaction、写 stall、运维在宿主进程内

1.1 进程内 HashMap:零跳数,零共享

应用内 ConcurrentHashMap、Guava CacheCaffeine 等落在 同一 JVM/进程地址空间。优势是延迟最低、无序列化 hop;代价是 无法跨实例共享、容量受单进程堆约束、淘汰策略与观测性由语言运行时决定。 architecture/17 中的 L1 本地缓存多在这一格; storage/66 讨论它与 Page Cache、远程缓存的叠加顺序。

边界:HashMap 解决「本进程重复读」;一旦需要 多副本一致视图独立扩缩容,必须上网络层(Memcached/Redis)或带复制/分片的存储服务。

1.2 Memcached:纯分布式缓存

Memcached 把值当作 不透明的字节块,分配器以 slab class 切分内存(源码 slabs.c;设计讨论见 Nishtala et al., NSDI 2013,B 级)。多 worker 线程处理连接;无内置持久化、无复杂数据结构。Facebook 大规模部署经验(同论文)强调 客户端分片、UDP 聚合 get、invalidation 与 MySQL 的配合——这与 Redis Cluster 的服务端 slot 模型不同(第 13 篇对照)。

1.3 Redis:内存数据结构服务器

Redis 官方文档与源码把产品定位为 in-memory data structure store:除 string 外还有 list、hash、sorted set、stream 等 带语义的操作(如 ZADDXREADGROUP),并可选 RDB/AOF(第 9–11 篇)。执行模型上,命令仍在主线程上突变共享数据集;7.x 起的 IO threads 只卸载读写与解析,不改变这一不变量(第 2 篇)。

1.4 RocksDB 嵌入 KV:磁盘 LSM,不是网络缓存

RocksDB 内核系列 拆解的是 写优化 LSM:WAL 顺序写、MemTable、后台 compaction。它嵌入 TiKV、Flink state backend 等进程,提供 可持久、可迭代 的本地 KV,而不是替代 Memcached 的纯 RAM 网络缓存。

需求信号 更可能的一格
微秒级、可丢、跨实例共享 Memcached 或 Redis(volatile)
复杂结构 + 可选持久化 + 复制 Redis
单进程大量写、需磁盘耐久、范围扫描 RocksDB 嵌入
仅本进程、无网络 HashMap / 嵌入库

二、与相邻系列的分工

本系列刻意 不重写 应用层缓存模式与 LSM 公式全文,而是引相邻篇目,把读者送到已写透的层。

话题 相邻系列 本系列承接点
Cache-Aside、击穿/雪崩、热点 architecture/17 第 1、14、16 篇:模式 ↔︎ 服务器能力边界
Page Cache → 应用缓存栈 storage/66 第 1、8 篇:远程缓存与 OS 页缓存分工
哈希表 / 跳表 / LRU 理论 algorithms/071852 第 4、6、8 篇:Redis 工程编码与近似淘汰
Redis 4.0 Org 情景漫游 linux/redis-source 第 1 篇历史入口;机制以 7.4/8.x 为准
RESP + libevent 玩具服务器 libevent redis-lite 第 1–2 篇:协议入门 vs 生产 ae 路径
磁盘 LSM、WAL、compaction rocksdblsm-tree 第 1 篇对照;不把 Redis 当 LSM 引擎讲
fsync / 持久化语义 fsyncgatestorage/12 第 11 篇落地配置

linux/redis-source 基于 Redis 4.0 的 Org 笔记,适合建立「事件循环 + dict + object」的第一遍直觉;但 listpack 替代 ziplist、IO threads、客户端内存限制 等已在 7.x 演进。本系列正文以 Redis Ltd. 7.4 / 8.x tag 源码为准,4.0 仅作谱系参照。

libevent redis-litebufferevent + unordered_map 实现最小 RESP,帮助理解 协议解析与单线程 Reactor;它没有 redisObject 多态编码、也没有 RDB fork——那是本系列第 3 篇起的对象层。


三、学术谱系与争论:cache 还是 data structure server?

3.1 奠基:Web 缓存与大规模 Memcache

工作 出处 本文引用点
Nishtala et al., Scaling Memcache at Facebook NSDI 2013(B 级) 纯缓存、客户端分片、与 DB 的一致性实践;假设服务端 rich type
Ousterhout et al., The Case for RAMCloud HotOS 2009 / 后续 RAMCloud 论文 「内存作 primary store」愿景;与「Redis 作 cache」对照阅读

NSDI’13 的叙事是:Memcached 是 MySQL 前的加速层,失效与回填由应用与运维流程保证;论文 Figure 与 workload 针对 简单 get/set、高扇出,不是 general-purpose data structure server。

3.2 Redis 分叉:数据结构服务器

Salvatore Sanfilippo(antirez)在 Redis 早期公开说明中把项目定位为 data structure server(官方站点与源码 README,A/B 级):在内存里提供 语义化命令(列表、集合、有序集合),而不是仅缓存序列化 blob。持久化(RDB/AOF)与复制随后加入,使 Redis 在工程上 模糊「缓存 vs 小型 primary store」边界——这正是长期争论来源。

3.3 可核对的争论轴

立场 代表依据 主张
A:Redis 应 primarily 作 cache NSDI’13 实践;architecture/17 旁路模式 数据源在 DB;Redis 丢数据可重建;应用负责 invalidation
B:Redis 可作 durable in-memory store Redis Persistence / Replication 官方文档;AOF everysec 等配置 部分团队把 Redis 当 主存储或会话层;需接受复制滞后与 fsync 窗口(第 11 篇)

工程间隙:论文与官方文档讨论的是 机制语义(例如异步复制下丢什么),不是「能不能当唯一数据源」的 universal 答案。把 Redis 当 primary store 时,必须显式承担 failover、备份、跨 key 事务边界(Cluster 多 key 限制见第 13 篇)——这与 Memcached 论文假设的「MySQL 为真源」不同。

3.4 开放问题(系列收束于第 16 篇)

  1. 多线程执行命令是否应成为 Redis 主线? IO threads 已卸载读写;命令仍单线程。社区 fork(如 KeyDB、Valkey)与模块生态对 并行突变 有不同取舍(第 2、16 篇)。
  2. 嵌入 LSM vs 网络 Redis:本地 RocksDB 与远程 Redis 在 延迟、运维、跨服务共享 上如何划界?见 rocksdb/16 嵌入生产 与本系列第 16 篇选型树。

四、本系列 16 篇地图

flowchart TD
  A["01 全景"] --> B["02 事件循环"]
  B --> C["03 对象/SDS"]
  C --> D["04 Dict rehash"]
  D --> E["05 紧凑编码"]
  E --> F["06 ZSet/Stream"]
  F --> G["07 TTL"]
  G --> H["08 maxmemory"]
  H --> I["09 RDB"]
  I --> J["10 AOF"]
  J --> K["11 混合持久化"]
  K --> L["12 复制"]
  L --> M["13 Cluster"]
  M --> N["14 Memcached"]
  N --> O["15 排障"]
  O --> P["16 选型"]
部分 篇目 一句话价值
模型与执行 01–02 生态位 + ae / IO threads 精确边界
内存结构 03–06 redisObject、dict、listpack、skiplist/stream
过期与内存 07–08 TTL 采样、近似 LRU/LFU vs 真 LRU
持久化 09–11 RDB fork、AOF fsync、混合与崩溃语义
分布式与收束 12–16 PSYNC、16384 slot、Memcached 对照、排障、选型

推荐阅读路径(详见 系列 index):


五、常见误解

  1. 「Redis = 更快的 Memcached」。差的不只是实现语言:Redis 有 类型系统、持久化、复制、Cluster slot;Memcached 是 多线程 + slab + opaque value。吞吐数字随 workload 变化,不能脱离 item 大小、pipeline、持久化是否开启(本篇不列未实测排名)。
  2. 「用 HashMap 就不用 Redis」。HashMap 不能解决 跨进程/跨主机共享独立扩缩容;architecture/17 的多级缓存里 L1 与 L2 是互补关系。
  3. 「Redis 和 RocksDB 都是 KV,可互换」。Redis 是 网络内存结构服务;RocksDB 是 进程内磁盘 LSM。Flink state 用 RocksDB 不是因为「Redis 不够快」,而是因为 本地耐久 + iterator + compaction 模型不同。
  4. 「读完 linux/redis-source 就等于掌握生产 Redis」。4.0 Org 笔记 valuable,但 7.4/8.x 在编码(listpack)、IO threads、客户端内存 eviction 等处已演进;应以本系列 + 当前 tag 源码为准。
  5. 「缓存服务器 = 淘汰算法」。TTL(第 7 篇)与 maxmemory 淘汰(第 8 篇)是 不同路径;NSDI’13 的 Memcached 甚至以 LRU 类策略 + 手动失效 为主,不能套用 Redis 的 LFU 语义。

六、小结

三句话小结

  1. 进程内 HashMap、网络 Memcached/Redis、嵌入 RocksDB 解决的是不同边界上的 KV 问题:共享范围、值语义、持久化与扩缩容不可混谈。
  2. 本系列补的是 Redis 7.4/8.x 内核路径(事件循环 → 对象编码 → 淘汰 → RDB/AOF → 复制/Cluster),与 architecture/17、storage/66、4.0 redis-source 分工阅读
  3. 「cache vs data structure server」 在文献与工程上并存:NSDI’13 代表纯缓存栈;Redis 官方定位与持久化能力代表另一分叉——选型需显式写出 真源在哪、丢数据是否可接受

下一篇进入执行路径:事件循环与 I/O,用 ae.c / networking.c / server.c 钉住「单线程」的精确含义。


参考资料

核心论文 / 系统文献

  1. Nishtala, Rajesh et al., Scaling Memcache at Facebook, NSDI 2013(大规模纯缓存实践;B 级,对读 architecture/17)。
  2. O’Neil, Patrick E. et al., The Log-Structured Merge-Tree (LSM-Tree), Acta Informatica, 1996(嵌入 KV 谱系;见 rocksdb/01)。
  3. Pugh, William, Skip Lists: A Probabilistic Alternative to Balanced Trees, CACM 1990(第 6 篇 ZSet 对照)。

规范 / 源码 / 官方文档

  1. Redis Documentation, Introduction / Persistence / Replication(redis.io,Redis OSS 7.4 / 8.x)。
  2. Redis OSS 源码:src/server.csrc/object.csrc/dict.c(版本 tag 与正文一致)。
  3. Memcached 源码与 Wiki(slabs.c、协议章节)。

站内

  1. 本系列 indexarchitecture/17storage/66
  2. linux/redis-source(4.0)libevent redis-literocksdb 索引

返回 系列目录 | 下一篇:事件循环与 I/O

同主题继续阅读

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


By .