Redis的常见问题

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

Redis在键值数据库中具有不同的演变路径,其中值可以包含更复杂的数据类型,并在这些数据类型上定义原子操作。Redis 数据类型与基本数据结构密切相关,并且直接向程序员公开,无需额外的抽象层。

Redis是一个内存数据库但同时数据也存在于磁盘数据库中,所以它代表了一种不同的折中,在数据集不大于内存的限制下实现了非常高的写入和读取速度。内存数据库的另一个优点是,与磁盘上的相同数据结构相比,复杂数据结构的内存表示更易于操作,因此Redis可以在内部复杂性很小的情况下做很多事情。同时,两种磁盘存储格式(RDB和AOF)不需要适用于随机访问,因此它们是紧凑的并且总是以append-only的方式生成(即使 AOF日志轮换也是一种append-only方式,因为新版本是从内存中的数据副本生成的)。然而,与传统的磁盘存储相比,这种设计也涉及不同的挑战。作为内存中的主要数据表示,必须小心处理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的大部分功能都是其当前设计的直接结果。

如果你真正的问题不是所需的总内存,而是你需要将你的数据集分成多个Redis实例,请阅读本文档中的分区页面,以获得更多信息。

Redis的赞助商Redis Ltd.公司开发了一个名为“Redis on Flash”的解决方案,该解决方案使用混合RAM/flash的方法来处理具有偏向访问模式的大型数据集。您可以查看他们的产品以了解更多信息,但此功能并不属于Redis开源代码库的部分。

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

答案是肯定的,一种常见的设计模式是在Redis中获取写入量很大的小数据(以及您需要Redis数据结构以有效的方式为您的问题建模的那些数据),以及将大块数据放入SQL或最终一致的磁盘数据库中。同样,有时Redis被用来在内存中获取存储在磁盘数据库中的相同数据子集的另一个副本。这看起来类似于缓存,但实际上是一个更高级的模型,因为通常Redis数据集与磁盘数据库的数据集一起更新。

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

如果可以的话,请使用Redis 32位实例。还要充分利用小哈希、列表、排序集和整数集,因为Redis能够在包含少数元素的特殊情况下以更紧凑的方式表示这些数据类型。另外,你也可以在内存优化页面上获取更多相关的信息。

如果Redis内存不足怎么办?

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

你也可以配置Redis在达到最大内存限制时的逐出密钥。

在Linux上后台保存失败,出现fork()错误?

Redis后台的保存模式依赖于现代操作系统中fork调用的copy-on-write语义:Redis forks(创建子进程)是父进程的精确副本。子进程将DB转储到磁盘上,然后退出。理论上,子进程应该使用与父进程一样多的内存,但实际上,由于大多数现代操作系统实现了copy-on-write语义,父进程和子进程将共享公共内存页。只有当一个页面在子进程或父进程中发生变化时,它才会被复制。由于理论上所有的页面都可能在子进程保存时发生变化,Linux无法提前知道子进程将占用多少内存,所以如果将overcommit_memory设置为0,分叉将会失败,除非你有足够可用的RAM来真正复制所有父内存页面。也就是说,如果您有一个3 GB的Redis数据集,而只有2 GB的可用内存,那么将会导致分叉失败。

将overmit\u memory设置为1会让Linux以更乐观的分配方式执行fork,这也确实才是您想要的Redis。

要了解Linux虚拟内存的工作原理以及overcommit_memory和overcommit_ratio的其他替代方案,您可以参考Red Hat Magazine的经典文章《理解虚拟内存》。您也可以参考手册页,了解可用值的解释。

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

Redis通常受内存或网络限制,CPU成为其瓶颈的情况倒并不常见。例如,当使用管道时,一个运行在普通Linux系统上的Redis实例每秒可以发送100万个请求,所以如果你的应用程序主要使用O(N)或O(log(N))命令,它几乎不会使用太多的CPU。

不过,为了最大限度地提高CPU利用率,您可以在单盒(single box)中启动多个Redis实例,并将它们视为不同的服务器。在某些情况下,单盒(single box)可能是不够的,因此如果您想使用多个CPU,可以开始考虑更早地进行切分。

从4.0版本开始,Redis已经开始实现线程操作。但目前这仅限于在后台删除对象和阻止通过Redis模块实现的命令。对于后续版本,计划是使Redis越来越多的线程化。

单个Redis实例最多可以容纳多少个键?哈希、列表、集合和排序集合中元素的最大数量是多少?

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

每个哈希、列表、集和排序集可以容纳2^32个元素。

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

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

如果您使用有效期有限的键(Redis过期),这是正常现象。这是因为:

  • The primary在第一次与副本同步时生成一个 RDB 文件。
  • RDB文件不会包含在The primary中已经过期但仍存在于内存中的键。
  • 即使在逻辑上过期,这些键仍在Redis主数据库the Redis primary的内存中。稍后将以增量或显式方式在访问时回收它们的内存。虽然这些键在逻辑上不是数据集的一部分,但它们在INFO输出和DBSIZE命令中被计算在内。
  • 当副本读取主数据库The primary生成的RDB文件时,这组键将不会被加载。

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