键值数据库(如 Redis、Memcached)的工作原理
你的前端应用体验流畅。用户点击,数据立即显示,页面瞬间加载。在这种体验背后,通常有一个键值数据库在做繁重的工作——在请求到达主数据库之前就将其拦截。理解这些系统的工作原理有助于你在缓存、会话和后端架构方面做出更明智的决策。
核心要点
- 键值数据库使用唯一键与值配对来存储和检索数据,以牺牲查询灵活性换取卓越的速度。
- 内存存储(RAM)通过哈希表实现常数时间查找,通常比基于磁盘的读取快 100-1000 倍。
- Redis 提供丰富的数据结构、可选的持久化和内置集群功能,而 Memcached 则作为简单、多线程、专用缓存表现出色。
- 常见用例包括会话管理、API 响应缓存和速率限制——这些场景中低延迟最为重要。
- 键值存储是关系数据库的补充而非替代品。将它们用作性能层,而不是主数据存储。
什么是键值数据库?
键值数据库是一种 NoSQL 数据存储,使用简单的两部分结构来保存和检索数据:唯一键及其关联的值。
可以把它想象成 JavaScript 对象或哈希映射:
"session:user:4821" → { userId: 4821, role: "admin", expires: 1720000000 }
"product:sku:9001" → { name: "Wireless Keyboard", price: 49.99 }
你通过键查找数据。就这么简单。没有查询语言,没有 JOIN,没有模式。正是这种约束使键值存储如此快速。
内存存储如何实现快速查找
大多数键值数据库——包括 Redis 和 Memcached——将数据存储在 RAM(内存)中,而不是磁盘上。磁盘读取以毫秒为单位。内存读取发生在微秒级别,通常快 100-1000 倍。
在内部,这些系统使用哈希表:键被哈希到内存地址,值被直接检索。没有扫描,没有索引,没有查询规划。查找时间实际上是 O(1)——无论数据集大小如何都保持恒定。
这就是为什么键值存储是缓存层、会话存储以及任何响应时间直接影响用户体验的后端服务的默认选择。
核心操作:SET、GET 和过期
基本操作在设计上是最小化的:
- SET
key value— 存储值 - GET
key— 检索值 - DEL
key— 删除值 - EXPIRE
key seconds— 在生存时间(TTL)后自动删除
TTL 对缓存特别有用。你可以存储一个 API 响应或渲染的 HTML 片段,设置 60 秒过期时间。你的应用首先从缓存读取。如果键缺失或过期,则回退到数据库并重新填充缓存。这种模式——旁路缓存(cache-aside)——是 Web 架构中最常见的模式之一。
Discover how at OpenReplay.com.
Redis vs. Memcached:关键架构差异
两者都是内存键值存储。两者都提供亚毫秒级性能。但它们做出了不同的权衡。
| 特性 | Redis | Memcached |
|---|---|---|
| 数据类型 | 字符串、列表、集合、哈希、有序集合、流等 | 仅字符串 |
| 值大小限制 | 最大 512 MB | 最大 1 MB |
| 持久化 | 可选(RDB 快照或仅追加文件) | 无——纯易失性 |
| 多线程 | 单线程事件循环(6.0+ 版本添加了 I/O 线程) | 完全多线程 |
| 内存回收 | 将释放的内存返回给操作系统 | 通过 slab 分配器保留已分配内存直到重启 |
| 内置集群 | 是(Redis Cluster、Sentinel) | 需要客户端分片 |
Memcached 是专用缓存。它简单、快速且可预测。其基于 slab 的内存分配器保持低碎片化,使内存使用高度一致——当你需要硬性内存上限时非常有用。当你缓存纯字符串且不需要更多功能时,它是很好的选择。
Redis 是更广泛的内存数据结构存储。除了缓存,它还支持用于排行榜的有序集合、发布/订阅消息传递、原子计数器和可选持久化。现代 Redis 被用作缓存、会话存储、消息代理和轻量级数据库——有时同时充当所有这些角色。值得注意的是:Redis 从 2024 年开始更改了许可证,这导致一些团队评估 Valkey,这是一个由 Linux 基金会在宽松许可证下维护的兼容开源分支。
键值数据库在面向前端的系统中的位置
从前端开发者的角度来看,键值存储通常出现在三个地方:
- 会话管理——在服务器端存储认证令牌、用户状态和偏好设置
- API 响应缓存——减少数据库负载并加速重复请求
- 速率限制——使用原子递增操作跟踪每个用户或 IP 的请求计数
这些场景都直接受益于键值数据库最擅长的功能:快速读取、快速写入和简单的过期逻辑。
何时不使用键值存储
键值数据库不是关系数据库的替代品。它们有真实的局限性:
- 大多数查询基于键,与关系数据库相比,过滤或排序支持有限
- 记录之间没有内置关系
- 不适合复杂报告或分析
- 数据建模需要预先仔细设计键
如果你的数据有关系或需要灵活查询,请选择 PostgreSQL 或文档数据库。将键值存储用作主数据存储之上的性能层,而不是替代品。
结论
键值数据库之所以有效,是因为它们以复杂性换取速度。它们只做一件事——主要在内存中通过键存储和检索值——并且做得非常出色。无论你选择 Redis 的灵活性还是 Memcached 的简单性,理解底层模型都能帮助你在真正适合的地方使用这些工具:作为保持应用响应速度的快速、专注的层。
常见问题
Redis 支持两种可选的持久化机制:RDB 快照,在配置的时间间隔保存数据集;以及仅追加文件(AOF),记录每个写操作。你可以使用其中一种或两者都使用。如果未启用持久化,数据在重启时会丢失,就像 Memcached 一样。对于纯缓存,持久化通常不是必需的。
当你需要一个简单的多线程缓存来处理简单的字符串值,并希望以最少的配置获得可预测的内存使用时,Memcached 是一个不错的选择。如果你不需要丰富的数据结构、持久化或内置集群,Memcached 的简单性和高效的基于 slab 的内存分配器使其成为可靠的轻量级选项。
Redis 和 Memcached 都使用驱逐策略来处理内存限制。Memcached 默认使用 LRU(最近最少使用)驱逐。Redis 提供多种可配置策略,包括 LRU、LFU(最不经常使用)、随机驱逐和无驱逐模式,后者在内存满时对写入返回错误。
Redis 可以作为特定用例的主数据存储,如会话管理、计数器或实时排行榜,特别是在启用持久化的情况下。然而,它缺乏关系查询、强制模式和成熟的事务支持。对于大多数应用,它最适合作为关系数据库或文档数据库的补充性能层。
Gain control over your UX
See how users are using your site as if you were sitting next to them, learn and iterate faster with OpenReplay. — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.