Redis 常见问题解答

开始使用 Redis 时常见的疑问

Redis 与其他键值存储有什么不同?

  • Redis 在键值数据库中具有不同的演化路径,其中值可以包含更复杂的数据类型,并针对这些数据类型定义原子操作。Redis 数据类型与基本数据结构密切相关,并以这种方式暴露给程序员,无需额外的抽象层。
  • Redis 是一个内存数据库,但会持久存储在磁盘上,因此它代表了一种不同的权衡,在该权衡中,可以通过将数据集限制为不能大于内存的范围来实现非常高的写入和读取速度。内存数据库的另一个优点是,与磁盘上的相同数据结构相比,复杂数据结构的内存表示更容易操作,因此 Redis 可以用很少的内部复杂性完成很多事情。同时,两种磁盘存储格式 (RDB 和 AOF) 不需要适合随机访问,因此它们很紧凑,并且始终以追加方式生成(即使 AOF 日志轮换也是追加操作,因为新版本是从内存中数据副本生成的)。但是,与传统的磁盘存储相比,这种设计也涉及不同的挑战。由于内存是主要数据表示,因此必须仔细处理 Redis 操作,以确保磁盘上始终存在更新后的数据集版本。

Redis 的内存占用量是多少?

举几个例子(全部使用 64 位实例获得)

  • 一个空的实例使用约 3MB 的内存。
  • 100 万个小型键 -> 字符串值对使用约 85MB 的内存。
  • 100 万个键 -> 哈希值,表示包含 5 个字段的对象,使用约 160MB 的内存。

测试您的用例很简单。使用 `redis-benchmark` 实用程序生成随机数据集,然后使用 `INFO memory` 命令检查使用的空间。

64 位系统在存储相同键时,将比 32 位系统占用更多内存,尤其是在键和值都较小的情况下。这是因为指针在 64 位系统中占用 8 个字节。但当然,64 位系统的优势在于可以拥有大量内存,因此为了运行大型 Redis 服务器,几乎需要 64 位系统。另一种方法是分片。

为什么 Redis 将整个数据集保存在内存中?

过去,Redis 开发人员尝试过虚拟内存和其他系统,以便允许比 RAM 大的更大的数据集,但最后我们很高兴能做好一件事:从内存中提供数据,磁盘用于存储。因此,目前还没有计划为 Redis 创建一个磁盘后端。毕竟,Redis 的大部分功能都是其当前设计的直接结果。

如果您的实际问题不是所需的总 RAM 量,而是需要将数据集拆分为多个 Redis 实例,请阅读此文档中的 分区页面 以获取更多信息。

Redis Ltd. 是赞助 Redis 开发的公司,该公司开发了“Redis on Flash”解决方案,该解决方案使用混合 RAM/闪存方法,适用于具有偏差访问模式的更大数据集。您可以查看他们的产品以获取更多信息,但是此功能不是 Redis 社区版代码库的一部分。

您可以将 Redis 与基于磁盘的数据库一起使用吗?

是的,常见的模式涉及将写入量很大的小数据保存在 Redis 中(以及您需要 Redis 数据结构以有效的方式对您的问题进行建模的数据),并将大量数据保存在 SQL 或最终一致的基于磁盘的数据库中。同样,有时使用 Redis 来存储一个磁盘数据库中一部分数据的内存副本。这可能看起来类似于缓存,但实际上这是一个更高级的模型,因为通常 Redis 数据集会与磁盘数据库数据集一起更新,而不是在缓存未命中时刷新。

如何减少 Redis 的总体内存使用量?

一个好习惯是在将逻辑数据模型映射到 Redis 内部的物理数据模型时考虑内存消耗。这些考虑因素包括使用特定的数据类型、键模式和规范化。

除了数据建模之外,内存优化页面 中提供了更多信息。

如果 Redis 内存不足会发生什么?

Redis 具有内置保护机制,允许用户设置内存使用量的最大限制,在配置文件中使用 `maxmemory` 选项可以限制 Redis 可使用的内存。如果达到此限制,Redis 将开始对写入命令回复错误(但会继续接受只读命令)。

您还可以配置 Redis 在达到最大内存限制时逐出键。有关这方面的更多信息,请参阅 逐出策略文档

在 Linux 上,后台保存因 `fork()` 错误而失败?

简短回答:`echo 1 > /proc/sys/vm/overcommit_memory` :)

现在是长一点的答案

Redis 后台保存模式依赖于现代操作系统中 `fork` 系统调用的写时复制语义:Redis fork(创建子进程),该进程是父进程的精确副本。子进程将 DB 存储到磁盘,最后退出。理论上,子进程应该使用与父进程一样多的内存,因为它是父进程的副本,但实际上,由于大多数现代操作系统实现的写时复制语义,父进程和子进程将 *共享* 公共内存页面。只有当子进程或父进程中页面发生更改时,页面才会被复制。由于理论上所有页面都可能在子进程保存期间发生更改,因此 Linux 无法提前知道子进程将占用多少内存,因此,如果 `overcommit_memory` 设置为零,那么 fork 将失败,除非有足够多的可用 RAM 来真正复制所有父进程内存页面。如果您有一个 3 GB 的 Redis 数据集,只有 2 GB 的可用内存,它将失败。

将 `overcommit_memory` 设置为 1 会告诉 Linux 放松并以更乐观的方式执行 fork,这确实是 Redis 所需要的。

您可以参考 proc(5) 手册页了解可用值的解释。

Redis 磁盘快照是原子的吗?

是的,Redis 后台保存进程始终在服务器处于命令执行之外时 fork,因此每个报告为 RAM 中原子的命令从磁盘快照的角度来看也是原子的。

Redis 如何使用多个 CPU 或内核?

Redis 的 CPU 很少成为瓶颈,因为它通常受到内存或网络的限制。例如,当使用管道时,在平均 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" 是一个首字母缩略词,代表 **RE**mote **DI**ctionary **S**erver。

Salvatore Sanfilippo 为什么启动 Redis 项目?

Salvatore 最初创建 Redis 是为了扩展 LLOOGG,这是一个实时日志分析工具。但是,在 Redis 服务器基本工作后,他决定与其他人分享这项工作,并将 Redis 变成一个开源项目。

Redis 如何发音?

"Redis" (/ˈrɛd-ɪs/) 的发音类似于 "red" 这个词加上 "kiss" 这个词,去掉 "k" 音。

RATE THIS PAGE
Back to top ↑