害!面试挂在了Redis集群上......

abinxy
发布于 2022-4-21 21:34
浏览
0收藏

作者 |莱乌
来源 | IT界农民工(ID:kejishuqian)

上篇《干货:送你一份新鲜出炉的面试题》里提到了redis集群的三种模式,私下里就这道题和几位熟悉的朋友也交流过,很多答得不是很全面。大多数人平时对redis的使用很熟悉,但是对于这种偏思想与设计的东西却只是略知一二。

那么,今天我们就来聊聊redis集群的三种模式。

画外音:事实上,这道题在小莱的面试经历中被问到的频率还是挺高的。

主从模式

1、架构图害!面试挂在了Redis集群上......-鸿蒙开发者社区

2、集群介绍

1)主从模式里使用一个redis实例作为主机(master),其余多个实例作为备份机(slave);

2)master用来支持数据的写入和读取操作,而slave支持读取及master的数据同步;

3)在整个架构里,master和slave实例里的数据完全一致;

3、主从复制原理

全量同步

1) 当从节点启动时,会向主节点发送SYNC命令;

2) 主节点接收到SYNC命令后,开始在后台执行保存快照的命令生成RDB文件,并使用缓冲区记录此后执行的所有写命令;

3) 主节点快照完成后,将快照文件和所有缓存命令发送给集群内的从节点,并在发送期间继续记录被执行的写命令;

4) 主节点快照发送完毕后开始向从节点发送缓冲区中的写命令;

5) 从节点载入快照文件后,开始接收命令请求,执行接收到的主节点缓冲区的写命令。

增量同步

主从复制中因网络等原因造成数据丢失场景,当从节点再次连上主节点。如果条件允许,主节点会补发丢失数据给从节点。因为补发的数据远远小于全量数据,可以有效避免全量复制的过高开销。

三种模式主从复制原理基本一致。

4、主节点故障处理方式

主从模式中,每个客户端连接redis实例时都指定了ip和端口号。如果所连接的redis实例因为故障下线了,则无法通知客户端连接其他客户端地址,因此只能进行手动操作。

5、不支持高可用

显而易见,主从模式很好地解决了数据备份的问题,但是主节点因为故障下线后,需要手动更改客户端配置重新连接,这种模式并不能保证服务的高可用。

于是redis集群迎来了哨兵模式......

哨兵模式

1、架构图害!面试挂在了Redis集群上......-鸿蒙开发者社区

2、集群介绍

和主从模式不一样的是,哨兵模式中增加了独立进程(即哨兵)来监控集群中的一举一动。客户端在连接集群时,首先连接哨兵,通过哨兵查询主节点的地址,然后再去连接主节点进行数据交互。

如下图所示,如果master异常,则会进行master-slave切换,将最优的一个slave切换为主节点。害!面试挂在了Redis集群上......-鸿蒙开发者社区

害!面试挂在了Redis集群上......-鸿蒙开发者社区 同时,哨兵持续监控挂掉的主节点,待其恢复后,作为新的从节点加入集群中。害!面试挂在了Redis集群上......-鸿蒙开发者社区

3、主节点故障处理方式/哨兵工作方式

1) 每个哨兵每秒向集群中的master、slave以及其他哨兵发送一个PING命令;

2) 如果某个实例距离最后一次有效回复ping命令的时间超过一定值,则会被标记为主观下线;

3) 如果master被标记为主观下线,那么其他正在监视master的哨兵以每秒的频率确认其确实进入主观下线状态,且数量达到一定值时,master会被标记为下线,然后通知其他的从服务器,修改配置文件,让它们切换主机;

4) 客户端在master节点发生故障时会重向哨兵要地址,此时会获得最新的master节点地址。

4、扩容问题

哨兵模式的出现虽然解决了主从模式中master节点宕机不能自主切换(即高可用)的问题。但是,随着业务的逐渐增长,不可避免需要对当前业务进行扩容。

常见的扩容方式有垂直和水平扩容两种方式:

垂直扩容:通过增加master内存来增加容量;

水平扩容:通过增加节点来进行扩容,即在当前基础上再增加一个master节点。

虽然垂直扩容方式很便捷,不需要添加多余的节点,但是机器的容量是有限的,最终还是需要通过水平扩容方式来解决。而水平扩容涉及到数据的迁移,且迁移过程中又要保证服务的可用性。因此,数据能不迁移就尽量不要迁移。

显然,哨兵模式无法满足这种情形。因此,redis cluster应运而生。

Redis cluster 模式

1、架构图害!面试挂在了Redis集群上......-鸿蒙开发者社区

2、集群介绍

1) redis cluster模式采用了无中心节点的方式来实现,每个主节点都会与其它主节点保持连接。节点间通过gossip协议交换彼此的信息,同时每个主节点又有一个或多个从节点;

2) 客户端连接集群时,直接与redis集群的每个主节点连接,根据hash算法取模将key存储在不同的哈希槽上;

3) 在集群中采用数据分片的方式,将redis集群分为16384个哈希槽。如下图所示,这些哈希槽分别存储于三个主节点中:

  • Master1负责0~5460号哈希槽
  • Master2负责5461~10922号哈希槽
  • Master3负责10922~16383号哈希槽

害!面试挂在了Redis集群上......-鸿蒙开发者社区

4) 每个节点会保存一份数据分布表,节点会将自己的slot信息发送给其他节点,节点间不停的传递数据分布表;

5) 客户端连接集群时,通过集群中某个节点地址进行连接。客户端尝试向这个节点执行命令时,比如获取某个key值,如果key所在的slot刚好在该节点上,则能够直接执行成功。如果slot不在该节点,则节点会返回MOVED错误,同时把该slot对应的节点告诉客户端,客户端可以去该节点执行命令。

3、主节点故障处理方式

redis cluster中主节点故障处理方式与哨兵模式较为相像,当约定时间内某节点无法与集群中的另一个节点顺利完成ping消息通信时,则将该节点标记为主观下线状态,同时将这个信息向整个集群广播。

如果一个节点收到某个节点失联的数量达到了集群的大多数时,那么将该节点标记为客观下线状态,并向集群广播下线节点的fail消息。然后立即对该故障节点进行主从切换。等到原来的主节点恢复后,会自动成为新主节点的从节点。如果主节点没有从节点,那么当它发生故障时,集群就将处于不可用状态。

4、扩容问题

在哨兵模式中我们在扩容的时候遇到了问题,那么cluster中我们如何动态上线某个节点呢。当集群中加入某个节点时,哈希槽又是如何来进行分配的? 当集群中加入新节点时,会与集群中的某个节点进行握手,该节点会把集群内的其它节点信息通过gossip协议发送给新节点,新节点与这些节点完成握手后加入到集群中。

然后集群中的节点会各取一部分哈希槽分配给新节点,如下图:

  • Master1负责1365-5460
  • Master2负责6827-10922
  • Master3负责12288-16383
  • Master4负责0-1364,5461-6826,10923-12287

害!面试挂在了Redis集群上......-鸿蒙开发者社区

当集群中要删除节点时,只需要将节点中的所有哈希槽移动到其它节点,然后再移除空白(不包含任何哈希槽)的节点就可以了。

分类
收藏
回复
举报
回复
    相关推荐