Redis 常见问题解答
提示
来自deepseek解释
原文链接:https://redis.io/docs/latest/develop/get-started/faq/
Redis 与其他键值存储有何不同?
- Redis 在键值数据库领域有着不同的演进路径,其值可以包含更复杂的数据类型,并且在这些数据类型上定义了原子操作。Redis 数据类型与基本数据结构密切相关,并直接向程序员暴露,没有额外的抽象层。
- Redis 是一个内存中但持久化到磁盘的数据库,因此它代表了一种不同的权衡:以数据集不能超过内存大小为限制,实现了非常高的写入和读取速度。内存数据库的另一个优点是,复杂数据结构的内存表示比磁盘上的相同数据结构更容易操作,因此 Redis 可以用很少的内部复杂性完成很多工作。同时,两种磁盘存储格式(RDB 和 AOF)不需要适合随机访问,因此它们很紧凑,并且总是以仅追加的方式生成(即使是 AOF 日志轮换也是一个仅追加操作,因为新版本是从内存中数据的副本生成的)。然而,这种设计与传统的磁盘存储相比也带来了不同的挑战。由于主要数据表示在内存中,Redis 操作必须仔细处理,以确保磁盘上始终有数据集的更新版本。
Redis 的内存占用是多少?
举几个例子(均使用 64 位实例):
- 一个空实例使用约 3MB 内存。
- 100 万个小型键 -> 字符串值对使用约 85MB 内存。
- 100 万个键 -> 哈希值,表示一个包含 5 个字段的对象,使用约 160 MB 内存。
测试您的使用场景很简单。使用 redis-benchmark 工具生成随机数据集,然后使用 INFO memory 命令检查使用的空间。
64 位系统存储相同的键将比 32 位系统使用更多的内存,特别是当键和值都很小时。这是因为在 64 位系统中指针占用 8 个字节。但当然优点是在 64 位系统中可以拥有大量内存,因此为了运行大型 Redis 服务器,64 位系统或多或少是必需的。替代方案是分片。
为什么 Redis 将整个数据集保存在内存中?
过去,Redis 开发者曾试验过虚拟内存和其他系统,以允许数据集大于 RAM,但最终我们很高兴能做好一件事:从内存提供数据,磁盘用于存储。因此,目前没有为 Redis 创建磁盘后端的计划。Redis 的大部分特性,归根结底,都是其当前设计的直接结果。
如果您真正的问题不是总 RAM 需求,而是需要将数据集拆分到多个 Redis 实例中,请参阅本文档中的分区页面以获取更多信息。
赞助 Redis 开发的 Redis Ltd. 公司开发了一种“Redis on Flash”解决方案,针对具有偏向访问模式的较大数据集使用 RAM/Flash 混合方法。您可以查看他们的产品以获取更多信息,但此功能不属于 Redis 开源代码库的一部分。
能否将 Redis 与基于磁盘的数据库一起使用?
是的,一种常见的设计模式是将写入非常频繁的小数据(以及需要 Redis 数据结构来高效建模问题的数据)放在 Redis 中,而将大的数据块放在 SQL 或最终一致性的磁盘数据库中。同样,有时 Redis 被用来在内存中保存磁盘数据库中存储的同一数据子集的另一份副本。这看起来类似于缓存,但实际上是一种更高级的模型,因为通常 Redis 数据集与磁盘数据库数据集一起更新,而不是在缓存未命中时刷新。
如何减少 Redis 的整体内存使用量?
一个好的实践是在将逻辑数据模型映射到 Redis 中的物理数据模型时考虑内存消耗。这些考虑包括使用特定的数据类型、键模式和规范化。
除了数据建模之外,内存优化页面中有更多信息。
如果 Redis 内存不足会发生什么?
Redis 有内置的保护机制,允许用户通过配置文件中的 maxmemory 选项设置内存使用的最大限制。如果达到此限制,Redis 将开始对写入命令回复错误(但将继续接受只读命令)。
您也可以配置 Redis 在达到最大内存限制时逐出键。有关更多信息,请参阅逐出策略文档。
在 Linux 上后台保存因 fork() 错误而失败?
简短回答:echo 1 > /proc/sys/vm/overcommit_memory 😃
现在来看详细解释:
Redis 后台保存方案依赖于现代操作系统中 fork 系统调用的写时复制语义:Redis fork(创建一个子进程),该子进程是父进程的精确副本。子进程将数据库转储到磁盘,然后退出。理论上,子进程作为副本应该使用与父进程一样多的内存,但实际上,由于大多数现代操作系统实现的写时复制语义,父进程和子进程将 共享 公共内存页。只有当子进程或父进程中的页面发生更改时,页面才会被复制。由于理论上在子进程保存期间所有页面都可能更改,Linux 无法提前知道子进程将使用多少内存,因此如果 overcommit_memory 设置为零,则 fork 将失败,除非有足够的空闲 RAM 来实际复制所有父内存页。如果您有 3 GB 的 Redis 数据集,但只有 2 GB 的空闲内存,它将失败。
将 overcommit_memory 设置为 1 告诉 Linux 放松限制,以更乐观的分配方式执行 fork,这确实是您对 Redis 想要的。
您可以参考 proc(5) 手册页了解可用值的解释。
Redis 的磁盘快照是原子的吗?
是的,Redis 后台保存进程总是在服务器没有执行命令时 fork,因此在 RAM 中报告为原子的每个命令,从磁盘快照的角度来看也是原子的。
Redis 如何使用多个 CPU 或核心?
CPU 成为 Redis 瓶颈的情况并不常见,因为通常 Redis 要么受内存限制,要么受网络限制。例如,在使用管道时,运行在普通 Linux 系统上的 Redis 实例每秒可以处理 100 万个请求,因此如果您的应用主要使用 O(N) 或 O(log(N)) 命令,很难用太多 CPU。
然而,为了最大化 CPU 利用率,您可以在同一台机器上启动多个 Redis 实例,并将它们视为不同的服务器。在某个时候,单台机器可能无论如何都不够用了,所以如果您想使用多个 CPU,您可以开始考虑某种分片方式。
您可以在分区页面找到更多关于使用多个 Redis 实例的信息。
从 4.0 版本开始,Redis 已经开始实现线程化操作。目前这仅限于在后台删除对象和通过 Redis 模块实现的阻塞命令。对于后续版本,计划使 Redis 越来越线程化。
单个 Redis 实例最多可以容纳多少个键?哈希、列表、集合和有序集合中最多可以包含多少个元素?
Redis 可以处理多达 2^32 个键,并在实践中测试过每个实例至少可以处理 2.5 亿个键。
每个哈希、列表、集合和有序集合都可以容纳 2^32 个元素。
换句话说,您的限制很可能是系统中的可用内存。
为什么我的副本实例与主实例的键数量不同?
如果您使用具有有限生存时间(Redis 过期)的键,这是正常行为。以下是发生的情况:
- 主节点在首次与副本同步时生成一个 RDB 文件。
- RDB 文件不会包含在主节点中已过期但仍存在于内存中的键。
- 这些键仍然存在于 Redis 主节点的内存中,即使它们在逻辑上已过期。它们被视为不存在,其内存将在稍后回收,要么以增量方式,要么在访问时显式回收。虽然这些键在逻辑上不属于数据集的一部分,但它们会计入
INFO输出和DBSIZE命令中。 - 当副本读取主节点生成的 RDB 文件时,这组键不会被加载。
因此,拥有大量过期键的用户经常会在副本中看到较少的键。然而,从逻辑上讲,主节点和副本将具有相同的内容。
“Redis”这个名字是怎么来的?
Redis 是一个缩写,代表 REmote DIctionary Server(远程字典服务器)。
Salvatore Sanfilippo 为什么启动 Redis 项目?
Salvatore 最初创建 Redis 是为了扩展 LLOOGG,一个实时日志分析工具。但在基本的 Redis 服务器工作起来后,他决定与他人分享这项工作,并将 Redis 变成一个开源项目。
Redis 怎么发音?
"Redis"(/ˈrɛd-ɪs/)的发音类似于单词 "red" 加上单词 "kiss" 去掉 "k"。