Redis常见问题解答
在开始使用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 Ltd.,赞助Redis开发的公司,已经开发了一个"Redis on Flash"的解决方案,使用混合RAM/flash的方法来处理较大的数据集的偏向访问模式。你可以查看他们提供的更多信息,然而这个功能不是开源Redis代码库的一部分。
你能将Redis与基于磁盘的数据库一起使用吗?
是的,一个常见的设计模式涉及到在Redis中采取非常重写的小数据(以及你需要Redis数据结构来有效地模拟你的问题的数据),和大块的数据到一个SQL或最终一致的磁盘数据库。同样,有时Redis被用来在内存中获取存储在磁盘数据库中的相同数据子集的另一个副本。这看起来类似于缓存,但实际上是一个更高级的模型,因为通常Redis数据集与磁盘数据库数据集一起更新,而不是在缓存错过时刷新。
怎样才能减少Redis的整体内存使用量?
如果可以的话,使用Redis的32位实例。也要好好利用小的哈希值、列表、排序集和整数集,因为Redis能够在少数元素的特殊情况下以更紧凑的方式表示这些数据类型。在内存优化页面有更多信息。
如果Redis的内存用完了,会发生什么?
Redis有内置的保护措施,允许用户设置内存使用的最大限制,使用配置文件中的maxmemory
选项,对Redis可以使用的内存进行限制。如果达到这个限制,Redis将开始对写入命令作出错误的回答(但将继续接受只读命令)。
你也可以配置Redis在达到最大内存限制时驱逐钥匙。有关这方面的更多信息,请参见eviction policy docs。
在Linux上,后台保存失败,出现fork()错误?
简短的回答:echo 1 > /proc/sys/vm/overcommit_memory
:)
现在是长篇大论了:
Redis的后台保存模式依赖于现代操作系统中fork
系统调用的写时复制语义:Redis分叉(创建一个子进程),是父进程的精确拷贝。子进程将数据库转储到磁盘上,最后退出。理论上,子进程使用的内存应该和作为副本的父进程一样多,但实际上由于大多数现代操作系统实施的写时复制语义,父进程和子进程将share共同的内存页。只有当一个页面在子进程或父进程中发生变化时,它才会被复制。由于理论上所有的页面都可能在子进程保存时发生变化,Linux无法提前知道子进程将占用多少内存,所以如果overcommit_memory
设置为0,分叉将失败,除非有尽可能多的空闲内存来真正复制所有的父内存页面。 如果你有一个3GB的Redis数据集,而只有2GB的空闲内存,它将失败。
将overcommit_memory
设置为1告诉Linux放松,并以更乐观的分配方式执行分叉,这确实是你对Redis所希望的。
你可以参考proc(5) man页,以获得对可用值的解释。
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
命令中,它们被计算在内。 - 当副本读取由主文件生成的RDB文件时,这组键将不会被加载。
因此,拥有许多过期密钥的用户通常会在副本中看到更少的密钥。但是,从逻辑上讲,主副本将具有相同的内容。
Redis这个名字是怎么来的呢?
Redis是一个缩写,代表着REmote DIctionary Server。
为什么Salvatore Sanfilippo要启动Redis项目?
Salvatore最初创建Redis是为了扩展LLOOGG,一个实时日志分析工具。但在让基本的Redis服务器工作后,他决定与其他人分享这项工作,并将Redis变成一个开源项目。
Redis是如何发音的?
"Redis"(/ˈrɛd-ɪs/)的发音类似于单词"red"加上单词"k",没有"k"的发音。