[关闭]
@boothsun 2018-03-19T08:41:43.000000Z 字数 3168 阅读 2722

Redis 常见面试题

Redis


使用Redis有哪些好处?

  1. 速度快

    • 基于内存,避免了磁盘I/O的瓶颈。
    • 单进程单线程,减少了线程上下文切换的开销
    • 利用队列技术将并行访问变为串行访问,消除了传统数据库并发访问控制锁的开销。
    • Redis全程使用hash结构,读取速度快,还有一些特殊的数据结构,对数据存储进行了优化,如压缩表,对短数据进行压缩存储,再如,跳表,使用有序的数据结构加快读取的速度。
  2. 支持丰富的数据类型:支持string、list、set、sorted set、hash。

  3. 支持事务操作,保证操作原子性。

  4. 丰富的特性:可用于缓存、消息,按key设置过期时间,过期后将会自动删除。

redis相比memcached有哪些优势? (简单了解一下memcached)

  1. memcached所有的值均是简单的字符串,而redis支持更为丰富的数据类型。
  2. redis的速度比memcached快很多。
  3. redis可以支持持久化其数据。

redis常见性能问题和解决方案:

  1. 为了主从复制的速度和连接的稳定性,Master和Slave最好在同一个局域网内。

  2. Master写内存快照,save命令调度rdbSave函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务,所以Master最好不要写内存快照。

  3. Master AOF持久化,如果不重写AOF文件,这个持久化方式对性能的影响是最小的,但是AOF文件会不断增大,AOF文件过大会影响Master重启的恢复速度。Master最好不要做任何持久化工作,包括内存快照和AOF日志文件,特别是不要启用内存快照做持久化,如果数据比较关键,某个Slave开启AOF备份数据,策略为每秒同步一次。

  4. Master调用BGREWRITEAOF重写AOF文件,AOF在重写的时候会占大量的CPU和内存资源,导致服务load过高,出现短暂服务暂停现象。

Redis 最适合的场景

分布式锁

用Redis构建分布式锁

Session缓存

参见58沈剑的干货:session一致性架构设计实践

排行榜/计数器

Redis在内存中对数字进行递增或递减的操作实现的非常好。集合(Set)和有序集合(Sorted Set)也使得我们在执行这些操作的时候变的非常简单。所以,我们要从排序集合中获取排名最靠前的10个用户 —— 我们称之为“user_scores”,我们只需要像下面一样执行就可:

  1. ZRANGE user_scores 0 10 WITHSCORES

发布/订阅

Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。Redis客户端可以订阅任意数量的频道。

下图展示了频道channel1,以及订阅这个频道的三个客户端 —— Client1、Client2和Client5之间的关系:
image.png-9kB

当有新消息通过PUBLISH命令发送给频道channel1时,这个消息就会被发送给订阅它的三个客户端:
image.png-13.1kB

image.png-45kB

MySQL里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据

redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略。redis 提供 6种数据淘汰策略:

Redis为什么这么快?

  1. 纯内存数据库,避免了磁盘I/O的瓶颈。
  2. 单进程单线程,减少了线程上下文切换的开销。
  3. 利用队列技术将并行访问变为串行访问,消除了传统数据库并发访问控制锁的开销。
  4. Redis全程使用hash结构,读取速度快,还有一些特殊的数据结构,对数据存储进行了优化,如压缩表,对短数据进行压缩存储,再如,跳表,使用有序的数据结构加快读取的速度。
  5. 使用多路I/O复用模型,非阻塞I/O。

    多路I/O复用模型:

    多路I/O复用模型是利用 select、poll、epoll 可以同时监察多个流的 I/O 事件的能力,在空闲的时候,会把当前线程阻塞掉,当有一个或多个流有 I/O 事件时,就从阻塞态中唤醒,于是程序就会轮询一遍所有的流(epoll 是只轮询那些真正发出了事件的流),并且只依次顺序的处理就绪的流,这种做法就避免了大量的无用操作。

    这里“多路”指的是多个网络连接,“复用”指的是复用同一个线程。采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络 IO 的时间消耗),且 Redis 在内存中操作数据的速度非常快,也就是说内存内的操作不会成为影响Redis性能的瓶颈,主要由以上几点造就了 Redis 具有很高的吞吐量。

Redis为什么采用单线程?

我们首先要明白,上边的种种分析,都是为了营造一个Redis很快的氛围!官方FAQ表示,因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了(毕竟采用多线程会有很多麻烦!)。

image.png-91.9kB

可以参考:https://redis.io/topics/faq

看到这里,你可能会气哭!本以为会有什么重大的技术要点才使得Redis使用单线程就可以这么快,没想到就是一句官方看似糊弄我们的回答!但是,我们已经可以很清楚的解释了为什么Redis这么快,并且正是由于在单线程模式的情况下已经很快了,就没有必要在使用多线程了!

但是,我们使用单线程的方式是无法发挥多核CPU 性能,不过我们可以通过在单机开多个Redis 实例来完善!

这小结 参考自:为什么说Redis是单线程的以及Redis为什么这么快!

Redis 虚拟内存 (适用于value比key大的情况)

首先说明下redis的虚拟内存与操作系统虚拟内存不是一码事,但是思路和目的都是相同的。就是暂时把不经常访问的数据从内存交换到磁盘中,从而腾出宝贵的内存空间。对于redis这样的内存数据库,内存总是不够用的。除了可以将数据分割到多个redis服务器以外。另外的能够提高数据库容量的办法就是使用虚拟内存技术把那些不经常访问的数据交换到磁盘上。如果我们存储的数据总是有少部分数据被经常访问,大部分数据很少被访问,对于网站来说确实总是只有少量用户经常活跃。当少量数据被经常访问时,使用虚拟内存不但能提高单台redis数据库服务器的容量,而且也不会对性能造成太多影响。redis没有使用操作系统提供的虚拟内存机制而是自己在用户态实现了自己的虚拟内存机制。

主要的理由有以下两点:

  1. 操作系统的虚拟内存是以4k/页为最小单位进行交换的。而redis的大多数对象都远小于4k,所以一个操作系统页上可能有多个redis对象。另外redis的集合对象类型如list,set可能存在于多个操作系统页上。最终可能造成只有10%的key被经常访问,但是所有操作系统页都会被操作系统认为是活跃的,这样只有内存真正耗尽时操作系统才会进行页的交换。

  2. 相比操作系统的交换方式。redis可以将被交换到磁盘的对象进行压缩,保存到磁盘的对象可以去除指针和对象元数据信息。一般压缩后的对象会比内存中的对象小10倍。这样redis的虚拟内存会比操作系统的虚拟内存少做很多IO操作。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注