# Redis 常见问题

开始使用 Redis 时的常见问题

# Redis 与其他键值存储有何不同?

  • Redis 在键值数据库中具有不同的演变路径,其中值可以包含更复杂的数据类型,并在这些数据类型上定义原子操作。Redis 数据类型与基本数据结构密切相关,并且直接向程序员公开,无需额外的抽象层。
  • Redis 是一种内存中但持久存在于磁盘上的数据库,因此它代表了一种不同的权衡,即在数据集不能大于内存的限制下实现了非常高的写入和读取速度。内存数据库的另一个优点是,与磁盘上的相同数据结构相比,复杂数据结构的内存表示更易于操作,因此 Redis 可以在内部复杂性很小的情况下做很多事情。同时,两种磁盘存储格式(RDB 和 AOF)不需要适合随机访问,因此它们是紧凑的并且总是以仅附加方式生成(即使 AOF 日志轮换也是一种附加方式)唯一的操作,因为新版本是从内存中的数据副本生成的)。然而,与传统的磁盘存储相比,这种设计也涉及不同的挑战。

# Redis 的内存占用是多少?

举几个例子(都是使用 64 位实例获得的):

  • 一个空实例使用约 3MB 的内存。
  • 100 万个小键 -> 字符串值对使用约 85MB 内存。
  • 1 百万个键 -> 哈希值,表示具有 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/闪存方法来处理具有偏向访问模式的更大数据集。您可以查看他们的产品以获取更多信息,但是此功能不是开源 Redis 代码库的一部分。

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

是的,一种常见的设计模式涉及在 Redis 中获取写入量非常大的小数据(以及需要 Redis 数据结构以有效方式对问题进行建模的数据),以及将大块数据放入 SQL 或最终一致的磁盘数据库中. 同样,有时使用 Redis 是为了在内存中获取存储在磁盘数据库中的相同数据子集的另一个副本。这可能看起来类似于缓存,但实际上是一种更高级的模型,因为通常 Redis 数据集与磁盘上的 DB 数据集一起更新,并且不会在缓存未命中时刷新。

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

如果可以,请使用 Redis 32 位实例。还要充分利用小散列、列表、排序集和整数集,因为 Redis 能够以更紧凑的方式在少数元素的特殊情况下表示这些数据类型。 内存优化页面 中有更多信息。

# 如果 Redis 内存不足会怎样?

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

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

# Linux 上的 fork() 错误导致后台保存失败?

简短的回答:echo 1 > /proc/sys/vm/overcommit_memory😃

现在是长篇:

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

设置overcommit_memory为 1 告诉 Linux 放松并以更乐观的分配方式执行分叉,这确实是您想要的 Redis。

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

# Redis 磁盘快照是原子的吗?

是的,当服务器不在执行命令时,Redis 后台保存进程总是被分叉,因此从磁盘快照的角度来看,每个报告在 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 实例可以容纳的最大键数是多少?Hash、List、Set 和 Sorted Set 中的最大元素数是多少?

Redis 最多可以处理 2^32 个键,并且在实践中经过测试,每个实例至少可以处理 2.5 亿个键。

每个散列、列表、集合和有序集合都可以容纳 2^32 个元素。

换句话说,您的限制可能是系统中的可用内存。

# 为什么我的副本与主实例的密钥数量不同?

如果您使用具有有限生存时间(Redis 过期)的密钥,这是正常行为。这就是发生的事情:

  • 主数据库在第一次与副本同步时生成一个 RDB 文件。
  • RDB 文件不会包含在主数据库中已经过期但仍在内存中的键。
  • 这些键仍然在 Redis 主节点的内存中,即使在逻辑上已过期。它们将被认为不存在,并且它们的内存将在以后被回收,无论是增量还是在访问时显式。虽然这些键在逻辑上不是数据集的一部分,但它们在 INFO 输出和 DBSIZE 命令中都有说明。
  • 当replica读取primary生成的RDB文件时,不会加载这组key。

因此,拥有许多过期密钥的用户通常会在副本中看到更少的密钥。但是,从逻辑上讲,主副本和副本将具有相同的内容。

# “Redis”这个名字是怎么来的?

Redis 是一个缩写词,代表RE mote DI ctionary Server

# Salvatore Sanfilippo 为什么要启动 Redis 项目?

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

# Redis如何发音?

“Redis”(/ˈrɛd-ɪs/)的发音类似于“red”这个词加上没有“k”的“kiss”这个词。

Last Updated: 4/18/2023, 8:45:33 AM