2021年最新Redis面试题汇总(3)

目录
  • 1、Redis 怎么保证高可用、有哪些集群模式
  • 2、主从复制
  • ​3、哨兵
    • 1)哨兵故障检测
    • 2)哨兵故障转移流程
  • 4、集群模式
  • ​5、集群选举
  • 6、如何保证集群在线扩容的安全性?(Redis 集群要增加分片,槽的迁移怎么保证无损)
  • 7、Redis 事务的实现
  • 8、Redis 的 Java 客户端有哪些?官方推荐哪个?
  • 9、Redis 里面有1亿个 key,其中有 10 个 key 是包含 java,如何将它们全部找出来?
  • 10、使用过 Redis 做消息队列么?
  • 11、Redis 和 Memcached 的比较
  • ​总结

1、Redis 怎么保证高可用、有哪些集群模式

主从复制、哨兵模式、集群模式。

2、主从复制

在当前最新的 Redis 6.0 中,主从复制的完整过程如下:

1)开启主从复制

通常有以下三种方式:

  • 在 slave 直接执行命令:slaveof <masterip> <masterport>
  • 在 slave 配置文件中加入:slaveof <masterip> <masterport>
  • 使用启动命令:--slaveof <masterip> <masterport>

注:在 Redis 5.0 之后,slaveof 相关命令和配置已经被替换成 replicaof,例如 replicaof <masterip> <masterport>。为了兼容旧版本,通过配置的方式仍然支持 slaveof,但是通过命令的方式则不行了。

2)建立套接字(socket)连接

slave 将根据指定的 IP 地址和端口,向 master 发起套接字(socket)连接,master 在接受(accept) slave 的套接字连接之后,为该套接字创建相应的客户端状态,此时连接建立完成。

3)发送PING命令

slave 向 master 发送一个 PING 命令,以检査套接字的读写状态是否正常、 master 能否正常处理命令请求。

4)身份验证

slave 向 master 发送 AUTH password 命令来进行身份验证。

5)发送端口信息

在身份验证通过后后, slave 将向 master 发送自己的监听端口号, master 收到后记录在 slave 所对应的客户端状态的 slave_listening_port 属性中。

6)发送IP地址

如果配置了 slave_announce_ip,则 slave 向 master 发送 slave_announce_ip 配置的 IP 地址, master 收到后记录在 slave 所对应的客户端状态的 slave_ip 属性。

该配置是用于解决服务器返回内网 IP 时,其他服务器无法访问的情况。可以通过该配置直接指定公网 IP。

7)发送CAPA

CAPA 全称是 capabilities,这边表示的是同步复制的能力。slave 会在这一阶段发送 capa 告诉 master 自己具备的(同步)复制能力, master 收到后记录在 slave 所对应的客户端状态的 slave_capa 属性。

8)数据同步

slave 将向 master 发送 PSYNC 命令, master 收到该命令后判断是进行部分重同步还是完整重同步,然后根据策略进行数据的同步。

9)命令传播

当完成了同步之后,就会进入命令传播阶段,这时 master 只要一直将自己执行的写命令发送给 slave ,而 slave 只要一直接收并执行 master 发来的写命令,就可以保证 master 和 slave 一直保持一致了。

以部分重同步为例,主从复制的核心步骤流程图如下:

​3、哨兵

哨兵(Sentinel) 是 Redis 的高可用性解决方案:由一个或多个 Sentinel 实例组成的 Sentinel 系统可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器。

Sentinel 可以在被监视的主服务器进入下线状态时,自动将下线主服务器的某个从服务器升级为新的主服务器,然后由新的主服务器代替已下线的主服务器继续处理命令请求。

1)哨兵故障检测

检查主观下线状态

在默认情况下,Sentinel 会以每秒一次的频率向所有与它创建了命令连接的实例(包括主服务器、从服务器、其他 Sentinel 在内)发送 PING 命令,并通过实例返回的 PING 命令回复来判断实例是否在线。

如果一个实例在 down-after-miliseconds 毫秒内,连续向 Sentinel 返回无效回复,那么 Sentinel 会修改这个实例所对应的实例结构,在结构的 flags 属性中设置 SRI_S_DOWN 标识,以此来表示这个实例已经进入主观下线状态。

检查客观下线状态

当 Sentinel 将一个主服务器判断为主观下线之后,为了确定这个主服务器是否真的下线了,它会向同样监视这一服务器的其他 Sentinel 进行询问,看它们是否也认为主服务器已经进入了下线状态(可以是主观下线或者客观下线)。

当 Sentinel 从其他 Sentinel 那里接收到足够数量(quorum,可配置)的已下线判断之后,Sentinel 就会将服务器置为客观下线,在 flags 上打上 SRI_O_DOWN 标识,并对主服务器执行故障转移操作。

2)哨兵故障转移流程

当哨兵监测到某个主节点客观下线之后,就会开始故障转移流程。核心流程如下:

发起一次选举,选举出领头 Sentinel领头 Sentinel 在已下线主服务器的所有从服务器里面,挑选出一个从服务器,并将其升级为新的主服务器。领头 Sentinel 将剩余的所有从服务器改为复制新的主服务器。领头 Sentinel 更新相关配置信息,当这个旧的主服务器重新上线时,将其设置为新的主服务器的从服务器。

4、集群模式

哨兵模式最大的缺点就是所有的数据都放在一台服务器上,无法较好的进行水平扩展。

为了解决哨兵模式存在的问题,集群模式应运而生。在高可用上,集群基本是直接复用的哨兵模式的逻辑,并且针对水平扩展进行了优化。

集群模式具备的特点如下:

  1. 采取去中心化的集群模式,将数据按槽存储分布在多个 Redis 节点上。集群共有 16384 个槽,每个节点负责处理部分槽。
  2. 使用 CRC16 算法来计算 key 所属的槽:crc16(key,keylen) & 16383。
  3. 所有的 Redis 节点彼此互联,通过 PING-PONG 机制来进行节点间的心跳检测。
  4. 分片内采用一主多从保证高可用,并提供复制和故障恢复功能。在实际使用中,通常会将主从分布在不同机房,避免机房出现故障导致整个分片出问题,下面的架构图就是这样设计的。
  5. 客户端与 Redis 节点直连,不需要中间代理层(proxy)。客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。

集群的架构图如下所示:

​5、集群选举

故障转移的第一步就是选举出新的主节点,以下是集群选举新的主节点的方法:

1)当从节点发现自己正在复制的主节点进入已下线状态时,会发起一次选举:将 currentEpoch(配置纪元)加1,然后向集群广播一条 CLUSTERMSG_TYPE_FAILOVER_AUTH_REQUEST 消息,要求所有收到这条消息、并且具有投票权的主节点向这个从节点投票。

2)其他节点收到消息后,会判断是否要给发送消息的节点投票,判断流程如下:

  1. 当前节点是 slave,或者当前节点是 master,但是不负责处理槽,则当前节点没有投票权,直接返回。
  2. 请求节点的 currentEpoch 小于当前节点的 currentEpoch,校验失败返回。因为发送者的状态与当前集群状态不一致,可能是长时间下线的节点刚刚上线,这种情况下,直接返回即可。
  3. 当前节点在该 currentEpoch 已经投过票,校验失败返回。
  4. 请求节点是 master,校验失败返回。
  5. 请求节点的 master 为空,校验失败返回。
  6. 请求节点的 master 没有故障,并且不是手动故障转移,校验失败返回。因为手动故障转移是可以在 master 正常的情况下直接发起的。
  7. 上一次为该master的投票时间,在cluster_node_timeout的2倍范围内,校验失败返回。这个用于使获胜从节点有时间将其成为新主节点的消息通知给其他从节点,从而避免另一个从节点发起新一轮选举又进行一次没必要的故障转移
  8. 请求节点宣称要负责的槽位,是否比之前负责这些槽位的节点,具有相等或更大的 configEpoch,如果不是,校验失败返回。

如果通过以上所有校验,那么主节点将向要求投票的从节点返回一条 CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK 消息,表示这个主节点支持从节点成为新的主节点。

3)每个参与选举的从节点都会接收 CLUSTERMSG_TYPE_FAILOVER_AUTH_ACK 消息,并根据自己收到了多少条这种消息来统计自己获得了多少个主节点的支持。

4)如果集群里有N个具有投票权的主节点,那么当一个从节点收集到大于等于N/2+1 张支持票时,这个从节点就会当选为新的主节点。因为在每一个配置纪元里面,每个具有投票权的主节点只能投一次票,所以如果有 N个主节点进行投票,那么具有大于等于 N/2+1 张支持票的从节点只会有一个,这确保了新的主节点只会有一个。

5)如果在一个配置纪元里面没有从节点能收集到足够多的支持票,那么集群进入一个新的配置纪元,并再次进行选举,直到选出新的主节点为止。

这个选举新主节点的方法和选举领头 Sentinel 的方法非常相似,因为两者都是基于 Raft 算法的领头选举(leader election)方法来实现的。

6、如何保证集群在线扩容的安全性?(Redis 集群要增加分片,槽的迁移怎么保证无损)

例如:集群已经对外提供服务,原来有3分片,准备新增2个分片,怎么在不下线的情况下,无损的从原有的3个分片指派若干个槽给这2个分片?

Redis 使用了 ASK 错误来保证在线扩容的安全性。

在槽的迁移过程中若有客户端访问,依旧先访问源节点,源节点会先在自己的数据库里面査找指定的键,如果找到的话,就直接执行客户端发送的命令。

如果没找到,说明该键可能已经被迁移到目标节点了,源节点将向客户端返回一个 ASK 错误,该错误会指引客户端转向正在导入槽的目标节点,并再次发送之前想要执行的命令,从而获取到结果。

ASK错误

在进行重新分片期间,源节点向目标节点迁移一个槽的过程中,可能会出现这样一种情况:属于被迁移槽的一部分键值对保存在源节点里面,而另一部分键值对则保存在目标节点里面。

当客户端向源节点发送一个与数据库键有关的命令,并且命令要处理的数据库键恰好就属于正在被迁移的槽时。源节点会先在自己的数据库里面査找指定的键,如果找到的话,就直接执行客户端发送的命令。

否则,这个键有可能已经被迁移到了目标节点,源节点将向客户端返回一个 ASK 错误,指引客户端转向正在导入槽的目标节点,并再次发送之前想要执行的命令,从而获取到结果。

7、Redis 事务的实现

一个事务从开始到结束通常会经历以下3个阶段:

1)事务开始:multi 命令将执行该命令的客户端从非事务状态切换至事务状态,底层通过 flags 属性标识。

2)命令入队:当客户端处于事务状态时,服务器会根据客户端发来的命令执行不同的操作:

  • exec、discard、watch、multi 命令会被立即执行
  • 其他命令不会立即执行,而是将命令放入到一个事务队列,然后向客户端返回 QUEUED 回复。

3)事务执行:当一个处于事务状态的客户端向服务器发送 exec 命令时,服务器会遍历事务队列,执行队列中的所有命令,最后将结果全部返回给客户端。

不过 redis 的事务并不推荐在实际中使用,如果要使用事务,推荐使用 Lua 脚本,redis 会保证一个 Lua 脚本里的所有命令的原子性。

8、Redis 的 Java 客户端有哪些?官方推荐哪个?

Redis 官网展示的 Java 客户端如下图所示,其中官方推荐的是标星的3个:JedisRedisson lettuce

9、Redis 里面有1亿个 key,其中有 10 个 key 是包含 java,如何将它们全部找出来?

1)keys *java* 命令,该命令性能很好,但是在数据量特别大的时候会有性能问题

2)scan 0 MATCH *java* 命令,基于游标的迭代器,更好的选择

SCAN 命令是一个基于游标的迭代器(cursor based iterator): SCAN 命令每次被调用之后, 都会向用户返回一个新的游标, 用户在下次迭代时需要使用这个新游标作为 SCAN 命令的游标参数, 以此来延续之前的迭代过程。

当 SCAN 命令的游标参数被设置为 0 时, 服务器将开始一次新的迭代, 而当服务器向用户返回值为 0 的游标时, 表示迭代已结束。

10、使用过 Redis 做消息队列么?

Redis 本身提供了一些组件来实现消息队列的功能,但是多多少少都存在一些缺点,相比于市面上成熟的消息队列,例如 Kafka、Rocket MQ 来说并没有优势,因此目前我们并没有使用 Redis 来做消息队列。

关于 Redis 做消息队列的常见方案主要有以下:

1)Redis 5.0 之前可以使用 List(blocking)、Pub/Sub 等来实现轻量级的消息发布订阅功能组件,但是这两种实现方式都有很明显的缺点,两者中相对完善的 Pub/Sub 的主要缺点就是消息无法持久化,如果出现网络断开、Redis 宕机等,消息就会被丢弃。

2)为了解决 Pub/Sub 模式等的缺点,Redis 在 5.0 引入了全新的 Stream,Stream 借鉴了很多 Kafka 的设计思想,有以下几个特点:

  • 提供了消息的持久化和主备复制功能,可以让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失。
  • 引入了消费者组的概念,不同组接收到的数据完全一样(前提是条件一样),但是组内的消费者则是竞争关系。

Redis Stream 相比于 pub/sub 已经有很明显的改善,但是相比于 Kafka,其实没有优势,同时存在:尚未经过大量验证、成本较高、不支持分区(partition)、无法支持大规模数据等问题。

11、Redis 和 Memcached 的比较

1)数据结构:memcached 支持简单的 key-value 数据结构,而 redis 支持丰富的数据结构:String、List、Set、Hash、SortedSet 等。

2)数据存储:memcached 和 redis 的数据都是全部在内存中。

网上有一种说法 “当物理内存用完时,Redis可以将一些很久没用到的 value 交换到磁盘,同时在内存中清除”,这边指的是 redis 里的虚拟内存(Virtual Memory)功能,该功能在 Redis 2.0 被引入,但是在 Redis 2.4 中被默认关闭,并标记为废弃,而在后续版中被完全移除。

3)持久化:memcached 不支持持久化,redis 支持将数据持久化到磁盘

4)灾难恢复:实例挂掉后,memcached 数据不可恢复,redis 可通过 RDB、AOF 恢复,但是还是会有数据丢失问题

5)事件库:memcached 使用 Libevent 事件库,redis 自己封装了简易事件库 AeEvent

6)过期键删除策略:memcached 使用惰性删除,redis 使用惰性删除+定期删除

7)内存驱逐(淘汰)策略:memcached 主要为 LRU 算法,redis 当前支持8种淘汰策略,见本文第16题

8)性能比较

  • 按“CPU 单核” 维度比较:由于 Redis 只使用单核,而 Memcached 可以使用多核,所以在比较上:在处理小数据时,平均每一个核上 Redis 比 Memcached 性能更高,而在 100k 左右的大数据时, Memcached 性能要高于 Redis。
  • 按“实例”维度进行比较:由于 Memcached 多线程的特性,在 Redis 6.0 之前,通常情况下 Memcached 性能是要高于 Redis 的,同时实例的 CPU 核数越多,Memcached 的性能优势越大。
  • 至于网上说的 redis 的性能比 memcached 快很多,这个说法就离谱。

​总结

本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • 硬核 Redis 高频面试题解析

    目录 1.Redis 是单线程还是多线程? 2.为什么 Redis 是单线程? 3.Redis 为什么使用单进程.单线程也很快 4.Redis 在项目中的使用场景 5.Redis 常见的数据结构 6.Redis 的字符串(SDS)和C语言的字符串区别 7.Sorted Set底层数据结构 8.Sorted Set 为什么同时使用字典和跳跃表? 9.Sorted Set 为什么使用跳跃表,而不是红黑树? 10.Hash 对象底层结构 11.Hash 对象的扩容流程 12.渐进式 rehash 的优

  • 几道常问Redis面试题,你能答对吗?

    目录 1.Redis支持的数据类型? 2.什么是Redis持久化?Redis有哪几种持久化方式?优缺点是什么? 3.Redis 有哪些架构模式?讲讲各自的特点 4.使用过Redis分布式锁么,它是怎么实现的? 5.使用过Redis做异步队列么,你是怎么用的?有什么缺点? 6.什么是缓存穿透?如何避免?什么是缓存雪崩?何如避免? 7.Redis常用命令 8.Redis单例.主从模式.sentinel以及集群的配置方式及优缺点对比 9.为什么Redis 单线程却能支撑高并发? 10.Redis常见性

  • Java面试题冲刺第二天--Redis篇

    目录 面试题1:为什么要用 Redis ?业务在哪块儿用到的? 正经回答: 深入追问: 追问1:Redis里有哪些数据类型? 追问2:Redis与Memcached有哪些区别? 追问3:那Redis怎样防止异常数据不丢失的?如何持久化? 面试题2:Redis为啥是单线程的? 正经回答: 深入追问: 追问1:单线程只使用了单核CPU,太浪费,有什么办法发挥多核CPU的性能嘛? 面试题3:聊一下对缓存穿透.缓存击穿.缓存雪崩的理解吧 正经回答: 深入追问: 追问1:那你说一下针对缓存击穿的解决方法

  • Redis分布式锁的实现方式(redis面试题)

    什么是分布式锁? 要介绍分布式锁,首先要提到与分布式锁相对应的是线程锁.进程锁. 线程锁:主要用来给方法.代码块加锁.当某个方法或代码使用锁,在同一时刻仅有一个线程执行该方法或该代码段.线程锁只在同一JVM中有效果,因为线程锁的实现在根本上是依靠线程之间共享内存实现的,比如synchronized是共享对象头,显示锁Lock是共享某个变量(state). 进程锁:为了控制同一操作系统中多个进程访问某个共享资源,因为进程具有独立性,各个进程无法访问其他进程的资源,因此无法通过synchronize

  • 2021年最新Redis面试题汇总(1)

    目录 1.Redis 是单线程还是多线程? 2.为什么 Redis 是单线程? 3.Redis 为什么使用单进程.单线程也很快 4.Redis 在项目中的使用场景 5.Redis 常见的数据结构 6.Redis 的字符串(SDS)和C语言的字符串区别 7.Sorted Set底层数据结构 8.Sorted Set 为什么同时使用字典和跳跃表? 9.Sorted Set 为什么使用跳跃表,而不是红黑树? 10.Hash 对象底层结构 11.Hash 对象的扩容流程 总结 1.Redis 是单线程还

  • 2021年最新Redis面试题汇总(3)

    目录 1.Redis 怎么保证高可用.有哪些集群模式 2.主从复制 ​3.哨兵 1)哨兵故障检测 2)哨兵故障转移流程 4.集群模式 ​5.集群选举 6.如何保证集群在线扩容的安全性?(Redis 集群要增加分片,槽的迁移怎么保证无损) 7.Redis 事务的实现 8.Redis 的 Java 客户端有哪些?官方推荐哪个? 9.Redis 里面有1亿个 key,其中有 10 个 key 是包含 java,如何将它们全部找出来? 10.使用过 Redis 做消息队列么? 11.Redis 和 Me

  • 2021年最新Redis面试题汇总(2)

    目录 1.渐进式 rehash 的优点 2.rehash 流程在数据量大的时候会有什么问题吗(Hash 对象的扩容流程在数据量大的时候会有什么问题吗) 3.Redis 的网络事件处理器(Reactor 模式) 4.Redis 删除过期键的策略(缓存失效策略.数据过期策略) 5.Redis 的内存淘汰(驱逐)策略 6.Redis 的 LRU 算法怎么实现的? 7.Redis 的持久化机制有哪几种,各自的实现原理和优缺点? 1)RDB 2)AOF 8.为什么需要 AOF 重写 9.介绍下 AOF 重

  • 2021年最新Redis面试题汇总(4)

    目录 1.Redis 实现分布式锁 2.Redis 分布式锁过期了,还没处理完怎么办 3.守护线程续命的方案有什么问题吗 4.RedLock 5.使用缓存时,先操作数据库 or 先操作缓存 6.为什么是让缓存失效,而不是更新缓存 7.如何保证数据库和缓存的数据一致性 ​8.缓存穿透 9.布隆过滤器 10.缓存击穿 11.缓存雪崩 总结 1.Redis 实现分布式锁 1)加锁 加锁通常使用 set 命令来实现,伪代码如下: set key value PX milliseconds NX 几个参数

  • 2021最新Android笔试题总结美团Android岗职能要求

    目录 Android开发面试的几部分 1.基础知识 Java部分: Android部分: 数据结构与算法: 计算机基础: 设计模式: 开源项目: 重点项目经历 技术以外的东西 自我驱动和追求 沟通和协作 我的面经总结 Android Java 计算机网络 数据结构及算法 题外话 优秀的战士需要出色的剑才能战斗.同样,在现代IT中,每个编码人员都需要最好的Android开发人员工具来提高他们的技能和效率.在Android应用程序开发这个残酷的竞争行业中,只有优秀的开发人员才能生存下去.您需要向客户

  • GO必知必会的常见面试题汇总

    目录 引言 值类型和引用类型 值类型有哪些? 引用类型有哪些? 值类型和引用类型的区别? 垃圾回收 一图胜千言 堆和栈 栈 堆 切片 比较 比较的详解 深拷贝和浅拷贝 操作对象 区别如下: new和make new 特点 举个例子: 使用技巧 make make函数的函数签名 特点 使用技巧 小结:new与make的区别 go的map实现排序 解决思路 代码实现: 运行结果 逃逸分析 最后,听我说 引言 今年互联网的就业环境真的好糟糕啊,好多朋友被优化. 我们平常在工作中除了撸好代码,跑通项目之

  • Android 面试题汇总

        Android 70道面试题汇总不再愁面试 本文为开发者奉献了70道经典Android面试题加答案--重要知识点几乎都涉及到了,你还等啥,赶紧收藏吧!! 1. 下列哪些语句关于内存回收的说明是正确的? (b) A. 程序员必须创建一个线程来释放内存 B. 内存回收程序负责释放无用内存 C. 内存回收程序允许程序员直接释放内存 D. 内存回收程序可以在指定的时间释放内存对象 2. 下面异常是属于Runtime Exception 的是(abcd)(多选) A.ArithmeticExcep

  • Java常用类String的面试题汇总(java面试题)

    1.比较两个字符串时使用"=="还是equals()方法? 当然是equals方法."=="测试的是两个对象的引用是否相同,而equals()比较的是两个字符串的值是否相等.简单来说,基本数据类型都可以使用==.而引用类型使用==比较不了. 2.如何将字符串转化成int? 使用包装类Integer.Integer.valueOf("2");其他基本数据类型都是类似 3.为什么在Java中存储密码要使用char[],而不使用String. 因为St

  • 关于vue面试题汇总

    vue的底层原理? vue组件之间的通信? JS中判断数据类型的方法有几种? 最常见的判断方法:typeof 判断已知对象类型的方法: instanceof 根据对象的constructor判断: constructor 无敌万能的方法:jquery.type() vue与angular的区别? 1.vue仅仅是mvvm中的view层,只是一个如jquery般的工具库,而不是框架,而angular而是mvvm框架. 2.vue的双向邦定是基于ES5 中的 3.getter/setter来实现的,

随机推荐