【面试题系列】:Redis夺命12问,你能扛到第几问?

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
日志服务 SLS,月写入数据量 50GB 1个月
简介: 目录Redis是单线程还是多线程呢?为什么Redis在4.0之前会选择使用单线程?而且使用单线程还那么快?Redis是如何实现数据不丢失的呢?分别说说AOF和 RDB的实现原理AOF采用的是 “写后日志” 的方式,我们平时用的MySQL则采用的是 “写前日志”,那Redis为什么要先执行命令,再把数据写入日志呢RDB做快照时会阻塞线程吗?RDB 做快照的时候数据能修改吗?Redis是怎么解决在bgsave做快照的时候允许数据修改呢?说说Redis如何实现高可用吧?..



Redis是面试中绕不过的槛,只要在简历中写了用过Redis,肯定逃不过。今天我们就来模拟一下面试官在Redis这个话题上是如何一步一步深入,全面考察候选人对于Redis的掌握情况。

Redis是单线程还是多线程呢?

Redis不同版本之间采用的线程模型是不一样的,在Redis4.0版本之前使用的是单线程模型,在4.0版本之后增加了多线程的支持

在4.0之前虽然我们说Redis是单线程,也只是说它的网络I/O线程以及Set 和 Get操作是由一个线程完成的。但是Redis的持久化、集群同步还是使用其他线程来完成。

4.0之后添加了多线程的支持,主要是体现在大数据的异步删除功能上,例如 unlink keyflushdb asyncflushall async

为什么Redis在4.0之前会选择使用单线程?而且使用单线程还那么快?

选择单线程主要是使用简单不存在锁竞争,可以在无锁的情况下完成所有操作,不存在死锁和线程切换带来的性能和时间上的开销,但同时单线程也不能完全发挥出多核CPU的性能。

至于为什么单线程那么快我觉得主要有以下几个原因:

    1. Redis 的大部分操作都在内存中完成,内存中的执行效率本身就很快,并且采用了高效的数据结构,比如哈希表和跳表。
    2. 使用单线程避免了多线程的竞争,省去了多线程切换带来的时间和性能开销,并且不会出现死锁。
    3. 采用 I/O 多路复用机制处理大量客户端的Socket请求,因为这是基于非阻塞的 I/O 模型,这就让Redis可以高效地进行网络通信,I/O的读写流程也不再阻塞。

    Redis是如何实现数据不丢失的呢?

    Redis数据是存储在内存中的,为了保证Redis数据不丢失,那就要把数据从内存存储到磁盘上,以便在服务器重启后还能够从磁盘中恢复原有数据,这就是Redis的数据持久化。Redis数据持久化有三种方式。

      • AOF 日志(Append Only File,文件追加方式):记录所有的操作命令,并以文本的形式追加到文件中。
      • RDB 快照(Redis DataBase):将某一个时刻内存数据,以二进制的方式写入磁盘。
      • 混合持久化方式:Redis 4.0 新增了混合持久化的方式,集成了 RDB 和 AOF 的优点。

      分别说说 AOF和 RDB的实现原理

      AOF采用的是写后日志的方式,Redis先执行命令把数据写入内存,然后再记录日志到文件中。AOF日志记录的是操作命令,不是实际的数据,如果采用AOF方法做故障恢复时需要将全量日志都执行一遍。

      image.gif编辑

      RDB采用的是内存快照的方式,它记录的是某一时刻的数据,而不是操作,所以采用RDB方法做故障恢复时只需要直接把RDB文件读入内存即可,实现快速恢复。

      AOF采用的是 “写后日志” 的方式,我们平时用的MySQL则采用的是 “写前日志”,那 Redis为什么要先执行命令,再把数据写入日志呢

      这个主要是由于Redis在写入日志之前,不对命令进行语法检查,所以只记录执行成功的命令,避免出现记录错误命令的情况,而且在命令执行后再写日志不会阻塞当前的写操作。

      后写日志主要有两个风险可能会发生

        • 数据可能会丢失:如果 Redis 刚执行完命令,此时发生故障宕机,会导致这条命令存在丢失的风险。
        • 可能阻塞其他操作:AOF 日志其实也是在主线程中执行,所以当 Redis 把日志文件写入磁盘的时候,还是会阻塞后续的操作无法执行。

        RDB做快照时会阻塞线程吗?

        Redis 提供了两个命令来生成 RDB 快照文件,分别是 savebgsave

        save 命令在主线程中执行,会导致阻塞。

        bgsave 命令则会创建一个子进程,用于写入 RDB 文件的操作,避免了对主线程的阻塞,这也是 Redis RDB 的默认配置。

        RDB 做快照的时候数据能修改吗?

        save是同步的会阻塞客户端命令,bgsave的时候是可以修改的。

        Redis是怎么解决在bgsave做快照的时候允许数据修改呢?

        这里主要是利用bgsave子线程实现的,具体操作如下:

          • 如果主线程执行读操作,则主线程和 bgsave 子进程互相不影响;
          • 如果主线程执行写操作,则被修改的数据会复制一份副本,然后 bgsave子进程会把该副本数据写入 RDB 文件,在这个过程中,主线程仍然可以直接修改原来的数据。

          image.gif编辑

          要注意,Redis 对 RDB 的执行频率非常重要,因为这会影响快照数据的完整性以及 Redis 的稳定性,所以在 Redis 4.0 后,增加了 AOF 和 RDB 混合的数据持久化机制: 把数据以 RDB 的方式写入文件,再将后续的操作命令以 AOF 的格式存入文件,既保证了 Redis 重启速度,又降低数据丢失风险。

          说说Redis如何实现高可用吧?

          Redis实现高可用主要有三种方式:主从复制哨兵模式,以及 Redis 集群

          主从复制

          将从前的一台 Redis 服务器,同步数据到多台从 Redis 服务器上,即一主多从的模式,这个跟MySQL主从复制的原理一样。

          image.gif编辑

          哨兵模式

          使用 Redis 主从服务的时候,会有一个问题,就是当 Redis 的主从服务器出现故障宕机时,需要手动进行恢复,为了解决这个问题,Redis 增加了哨兵模式(因为哨兵模式做到了可以监控主从服务器,并且提供自动容灾恢复的功能)。

          image.gif编辑

          Redis Cluster(集群)

          Redis Cluster 是一种分布式去中心化的运行模式,是在 Redis 3.0 版本中推出的 Redis 集群方案,它将数据分布在不同的服务器上,以此来降低系统对单主节点的依赖,从而提高 Redis 服务的读写性能

          image.gif编辑

          使用哨兵模式在数据上有副本数据做保证,在可用性上又有哨兵监控,一旦master宕机会选举salve节点为master节点,这种已经满足了我们的生产环境需要,那为什么还需要使用集群模式呢?

          哨兵模式归根节点还是主从模式,在主从模式下我们可以通过增加salve节点来扩展读并发能力,但是没办法扩展写能力和存储能力,存储能力只能是master节点能够承载的上限。所以为了扩展写能力和存储能力,我们就需要引入集群模式

          集群中那么多Master节点,redis cluster在存储的时候如何确定选择哪个节点呢?

          Redis Cluster采用的是类一致性哈希算法实现节点选择的,至于什么是一致性哈希算法你自己回去看看。

          Redis Cluster将自己分成了16384个Slot(槽位),哈希槽类似于数据分区,每个键值对都会根据它的 key,被映射到一个哈希槽中,具体执行过程分为两大步。

            • 根据键值对的 key,按照 CRC16 算法计算一个 16 bit 的值
            • 再用 16bit 值对 16384 取模,得到 0~16383 范围内的模数,每个模数代表一个相应编号的哈希槽

            每个Redis节点负责处理一部分槽位,加入你有三个master节点 ABC,每个节点负责的槽位如下:

            image.gif编辑

            这样就实现了cluster节点的选择。

            一致性hash:

            一致性Hash算法也是使用取模的方法,只是,刚才描述的取模法是对服务器的数量进行取模,而一致性Hash算法是对2^32取模,一致性Hash算法将整个哈希值空间组织成一个虚拟的圆环,将各个服务器使用Hash进行一个哈希,具体可以选择服务器的IP主机名作为关键字进行哈希,这样每台机器就能确定其在哈希环上的位置

            一致性哈希算法能尽可能减少了服务器数量变化所导致的缓存迁移。

            这种算法解决了普通余数Hash算法伸缩性差的问题,可以保证在上线、下线服务器的情况下尽量有多的请求命中原来路由到的服务器。


            相关实践学习
            基于Redis实现在线游戏积分排行榜
            本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
            云数据库 Redis 版使用教程
            云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
            相关文章
            |
            1天前
            |
            缓存 NoSQL 关系型数据库
            大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
            本文详解缓存雪崩、缓存穿透、缓存并发及缓存预热等问题,提供高可用解决方案,帮助你在大厂面试和实际工作中应对这些常见并发场景。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
            大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
            |
            1月前
            |
            存储 NoSQL Java
            可能是最漂亮的Redis面试基础详解
            我是南哥,相信对你通关面试、拿下Offer有所帮助。敲黑板:本文总结了Redis基础最常见的面试题!包含了Redis五大基本数据类型、Redis内存回收策略、Redis持久化等。相信大部分Redis初学者都会忽略掉一个重要的知识点,Redis其实是单线程模型。我们按直觉来看应该是多线程比单线程更快、处理能力更强才对,比如单线程一次只可以做一件事情,而多线程却可以同时做十件事情。但Redis却可以做到每秒万级别的处理能力,主要是基于以下原因:(1)Redis是基于内存操作的,Redis所有的数据库状态都保存在
            可能是最漂亮的Redis面试基础详解
            |
            26天前
            |
            NoSQL Java API
            美团面试:Redis锁如何续期?Redis锁超时,任务没完怎么办?
            在40岁老架构师尼恩的读者交流群中,近期有小伙伴在面试一线互联网企业时遇到了关于Redis分布式锁过期及自动续期的问题。尼恩对此进行了系统化的梳理,介绍了两种核心解决方案:一是通过增加版本号实现乐观锁,二是利用watch dog自动续期机制。后者通过后台线程定期检查锁的状态并在必要时延长锁的过期时间,确保锁不会因超时而意外释放。尼恩还分享了详细的代码实现和原理分析,帮助读者深入理解并掌握这些技术点,以便在面试中自信应对相关问题。更多技术细节和面试准备资料可在尼恩的技术文章和《尼恩Java面试宝典》中获取。
            美团面试:Redis锁如何续期?Redis锁超时,任务没完怎么办?
            |
            1月前
            |
            NoSQL 算法 Redis
            Redis面试篇
            Redis面试篇
            35 5
            |
            1月前
            |
            缓存 NoSQL Java
            Java中redis面试题
            Java中redis面试题
            33 1
            |
            13天前
            |
            存储 NoSQL Redis
            Redis常见面试题:ZSet底层数据结构,SDS、压缩列表ZipList、跳表SkipList
            String类型底层数据结构,List类型全面解析,ZSet底层数据结构;简单动态字符串SDS、压缩列表ZipList、哈希表、跳表SkipList、整数数组IntSet
            |
            2月前
            |
            存储 缓存 NoSQL
            【Java面试题汇总】Redis篇(2023版)
            Redis的数据类型、zset底层实现、持久化策略、分布式锁、缓存穿透、击穿、雪崩的区别、双写一致性、主从同步机制、单线程架构、高可用、缓存淘汰策略、Redis事务是否满足ACID、如何排查Redis中的慢查询
            【Java面试题汇总】Redis篇(2023版)
            |
            1月前
            |
            NoSQL Redis
            redis 的 key 过期策略是怎么实现的(经典面试题)超级通俗易懂的解释!
            本文解释了Redis实现key过期策略的方式,包括定期删除和惰性删除两种机制,并提到了Redis的内存淘汰策略作为补充,以确保过期的key能够被及时删除。
            50 1
            |
            2月前
            |
            缓存 监控 NoSQL
            阿里面试让聊一聊Redis 的内存淘汰(驱逐)策略
            大家好,我是 V 哥。粉丝小 A 面试阿里时被问到 Redis 的内存淘汰策略问题,特此整理了一份详细笔记供参考。Redis 的内存淘汰策略决定了在内存达到上限时如何移除数据。希望这份笔记对你有所帮助!欢迎关注“威哥爱编程”,一起学习与成长。
            |
            1月前
            |
            缓存 NoSQL 算法
            面试题:Redis如何实现分布式锁!
            面试题:Redis如何实现分布式锁!
            下一篇
            无影云桌面