Skip to content

Redis面试题2

1)什么是Redis?

Redis(Remote Dictionary Server) 是一个使用 C 语言编写的,开源的(BSD许可)高性能非关系型(NoSQL)的键值对数据库。 Redis 可以存储键和五种不同类型的值之间的映射。键的类型只能为字符串,值支持五种数据类型:字符串、列表、集合、散列表、有序集合。 与传统数据库不同的是 Redis 的数据是存在内存中的,所以读写速度非常快,因此 redis 被广泛应用于缓存方向,每秒可以处理超过 10万次读写操作,是已知性能最快的Key-Value DB。另外,Redis 也经常用来做分布式锁。除此之外,Redis 支持事务 、持久化、LUA脚本、LRU驱动事件、多种集群方案。


2)Redis是什么意思?

Redis代表REmote DIctionary Server。


3)Redis用哪种语言编写?

Redis是用ANSI C编写的,主要用于缓存解决方案和会话管理。


4)Redis的用途是什么?

计数器 可以对 String 进行自增自减运算,从而实现计数器功能。Redis 这种内存型数据库的读写性能非常高,很适合存储频繁读写的计数量。 缓存 将热点数据放到内存中,设置内存的最大使用量以及淘汰策略来保证缓存的命中率。 会话缓存 可以使用 Redis 来统一存储多台应用服务器的会话信息。当应用服务器不再存储用户的会话信息,也就不再具有状态,一个用户可以请求任意一个应用服务器,从而更容易实现高可用性以及可伸缩性。 全页缓存(FPC) 除基本的会话token之外,Redis还提供很简便的FPC平台。以Magento为例,Magento提供一个插件来使用Redis作为全页缓存后端。此外,对WordPress的用户来说,Pantheon有一个非常好的插件 wp-redis,这个插件能帮助你以最快速度加载你曾浏览过的页面。 查找表 例如 DNS 记录就很适合使用 Redis 进行存储。查找表和缓存类似,也是利用了 Redis 快速的查找特性。但是查找表的内容不能失效,而缓存的内容可以失效,因为缓存不作为可靠的数据来源。 消息队列(发布/订阅功能) List 是一个双向链表,可以通过 lpush 和 rpop 写入和读取消息。不过最好使用 Kafka、RabbitMQ 等消息中间件。 分布式锁实现 在分布式场景下,无法使用单机环境下的锁来对多个节点上的进程进行同步。可以使用 Redis 自带的 SETNX 命令实现分布式锁,除此之外,还可以使用官方提供的 RedLock 分布式锁实现。 其它 Set 可以实现交集、并集等操作,从而实现共同好友等功能。ZSet 可以实现有序性操作,从而实现排行榜等功能。


5)如何与Redis连接?

安装服务器后,可以运行redis安装时提供的Redis客户端,也可以打开命令提示符并使用以下命令:

redis-cli

通过使用其中任何一个,您可以与Redis交互。


6)Redis的主要特点是什么?

以下是Redis的主要功能:

  • 读写性能优异, Redis能读的速度是110000次/s,写的速度是81000次/s。
  • 支持数据持久化,支持AOF和RDB两种持久化方式。
  • 支持事务,Redis的所有操作都是原子性的,同时Redis还支持对几个操作合并后的原子性执行。
  • 数据结构丰富,除了支持string类型的value外还支持hash、set、zset、list等数据结构。
  • 支持主从复制,主机会自动将数据同步到从机,可以进行读写分离。

7)解释Redis的复制功能?

Redis可以使用主从同步,从从同步。第一次同步时,主节点做一次bgsave,并同时将后续修改操作记录到内存buffer,待完成后将rdb文件全量同步到复制节点,复制节点接受完成后将rdb镜像加载到内存。加载完成后,再通知主节点将期间修改的操作记录同步到复制节点进行重放就完成了同步过程。


8)Redis和RDBMS有什么区别?

Redis和RDBMS之间存在很多差异:

  • Redis是NoSQL数据库,而RDBMS是SQL数据库。
  • Redis遵循键值结构,而RDBMS遵循表结构。
  • Redis非常快,而RDBMS相对较慢。
  • Redis将所有数据集存储在主存储器中,而RDBMS将其数据集存储在辅助存储器中。
  • Redis通常用于存储小型和常用文件,而RDBMS用于存储大文件。
  • Redis仅为Linux,BSD,Mac OS X,Solaris提供官方支持。它目前没有为Windows提供官方支持,而RDBMS提供对两者的支持。

9) 为什么Redis不同于其他的键值存储数据库?

有两个主要原因:

  • Redis发展方向不同与其他键值数据库,它能包含很多复杂数据类型,对这些数据类型操作都是原子的。Redis数据类型与基本数据结构强相关,直接暴露给程序员,没有增加抽象层。
  • Redis是一个内存数据库,而不是持久化在硬盘数据库中,因此为了实现高速读写,数据集大小不能超过内存。内存数据库另一个优点是,内存数据库相对于硬盘数据库非常容易操作复杂数据结构,因此Redis的可以做很多事情,很少有内部的复杂性。与此同时两款磁盘存储格式(RDB和AOF)不需要支持随机访问,因此他们是紧凑的,而且总是以追加形式生成(甚至AOF日志轮换也是一个追加操作,因为新版本是由内存中的副本生成)。

10) Redis内存使用情况?

举几个例子(所有数据基于64位实例)

  • 一个空实例大约占用1M内存
  • 1百万简单字符串键值对大约占用100M内存
  • 1百万哈希表键值对,每个对象有5个属性,大约占用200M内存

为了测试你的用例,使用redis-benchmark工具生成随机数据集,使用INFO memory命令检查使用内存空间。

存储相同的键,64位系统比32位系统使用更多的内存,键值很小情况下更明显。这是因为64位系统指针占用8字节。但是64位系统优点是可以配置更多内存(校对注:32位操作系统支持的内存最多为2的32次方,就是4G),因此为了运行大型Redis服务器,64位系统或多或少都是需要的。另一种方案是使用分片。


11) Redis的高性能操作和特性,能创建一个比内存更大数据集吗?

真正问题并不是所需的总内存,而是你需要划分你的数据集到多个Redis实例上。


12) 同时使用Redis和磁盘数据库,是不是一个好想法?

是的,一个通用的设计方案是,在非常频繁读写的小的数据时采用Redis(并且你需要选择适当的数据结构),以及将大数据存储到SQL数据库或者最终一致性磁盘数据库中。


13) 有没有方法降低Redis内存使用率?

如果可以的话使用Redis 32位实例。另外,还要善于使用哈希表、列表、集合、有序集合,因为在特殊情况下Redis使用这些数据类型可以更紧凑存储一些元素。


14) Redis内存不足时会发生什么?

Redis要么被Linux内核OOM杀掉,抛出错误崩溃,要么开始变得卡顿。随着现代操作系统malloc方法通常都不返回NULL,而是服务器开始交换,因此Redis性能降低,因此你可能会观察到一些错误现象。

INFO命令返回Redis使用内存总量,因此你可以编写脚本监控Redis服务器内存临界值。

Redis内置保护措施允许用户在配置文件中使用maxmemory选项,设置Redis最大占用内存。如果达到此限制,Redis将开始返回错误给写命令(但是将继续接受只读命令),或者当最大内存限制达到时也可以配置为淘汰策略,在这种情况下Redis作为缓存使用。

全局的键空间选择性移除

  • noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。
  • allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。(这个是最常用的)
  • allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。

设置过期时间的键空间选择性移除

  • volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。
  • volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。
  • volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除

15) 在Linux系统中,即使我有很多空闲内存,后台保存失败报fork错误!

精辟答案:echo 1 > /proc/sys/vm/overcommit_memory 🙂

详细回答:

Redis后台保存模式依赖现代操作系统的写时拷贝技术。Redis fork(创建一个子进程)是父进程精确拷贝。子进程存储数据到磁盘并且最终退出。从理论上讲,子进程应该和父进程使用同样多内存,作为父进程副本,但是得益于多数现代操作系统实现的写时复制技术,父进程和子进程共享内存页。内存页在父进程或子进程改变时将被复制。当子进程保存时,理论上所有页面都可能改变,Linux无法提前告知子进程需要多少内存,因此如果overcommit_memory设置为0,fork将会失败除非有足够的空闲RAM真正复制父进程内存页.结果是,如果你有3G Redis数据集,只有2G可用内存将会失败。

overcommit_memory设置为1,意味着Linux 使用更乐观方式fork,这确实是你所期望的Redis。

理解虚拟机内存校对注:有兴趣可以翻译此文在并发网发表)”是红帽经典文章,可以了解Linux虚拟内存怎么工作,overcommit_memory和overcommit_ratio的替代品。这篇文章校正了proc(5)用户手册对overcommit_memory1和2配置正确含义。


16) Redis磁盘快照是不是原子操作?

是的,当服务器不在执行命令时,Redis后台SAVE进程开始工作,每个命令在RAM中是原子的,并且在磁盘快照过程也是原子的。


17) Redis是单线程的,我怎么利用多CPU/核?

CPU基本不可能成为的Redis的瓶颈,因为通常Redis受限于内存或网络。例如使用Pipelining,Redis运行在普通的Linux系统上,每秒可以处理50万请求,所以如果你的应用程序主要使用O(N) 或者 O(log(N))命令,几乎不会使用太多的CPU。

然而为了最大限度利用CPU,你可以在一台机器上启动多个Redis实例,并把它们设置为不同服务器。某些时候单个机器是不够的,所以如果你想使用多个CPU,你可以提前考虑使用分片。


18) 单个Redis实例最多可以存储多少键?哈希表、列表、集合和有序集合最大可以包含多少元素?

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

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

换句话说,Redis极限容量就是系统可用内存。


19) 为什么我的从实例与主实例拥有不同数量键?

如果你使用有生存周期的键,这就是正常现象。这就导致主从实例键的数量不一致原因。

  • 主实例在第一次与从实例同步时生成RDB文件。
  • RDB文件不包含已经过期的键,但是已经过期的键仍然在内存中。
  • 尽管这些键从逻辑上说已经过期失效,但是还在Redis主实例内存中,他们并不被识别为存在的,当增量或访问这些键时这些键会被回收。尽管从逻辑上说这些键不是数据集一部分,但是INFO和DBSIZE命令结果包含这些信息。
  • 当从实例读取主实例生成的RDB文件时,过期键不会被载入。

为很多键设置过期属性,通常为用户提供了在从实例上存储更少键,但是实际上实例内容没有逻辑区别。