首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

redis集群架构的演进之路

一、redis的主从架构

一开始我们的业务量不大时,一个redis节点就能满足我们的业务需求,当我们的业务量不断上涨,单台redis节点已经不能满足我们的业务需求时,这个时候redis的主从结构就出现了。

redis主从结构解决的问题:redis可以部署为一个主节点,多个从节点,从节点提供读服务,主节点提供写服务,将我们的业务进行读写分离。

redis如何进行主从同步,其第一次进行主从同时时,其流程如下图:

首先从节点执行slaveof ip port命令,让自己成为192.168.1.1的从节点,同时发送命令psync ? -1到主节点上

第一个参数为runID:主节点的一个身份标识,第一次同步时,从节点不知道主节点的表述,所以用?代替

第二个参数为offset:偏移量值,第一次用-1表示全量同步。

主节点在接受到命令后,做出响应,返回FULLRESYNC命令,runID为自身的标识id,offset为主节点的偏移量的值。

主节点通过bgsave命令生成对应的RDB文件,并将RDB文件传送给对应的从节点(192.168.1.2)

从节点执行接受到的RDB文件,先清空本身可能存在的数据,然后根据RDB生成数据

在主从同步过程中,主节点并不会停止提供服务,所以在同步过程中,主节点接到的命令,会被放入到replication buffer的缓冲区中。

从节点执行完RDB文件后,主节点将replication buffer的修改操作,发送到从节点,从节点加载replication buffer数据,第一次主从同步完成。

网络中断时,主从结构如何保持数据一致性?在redis2.8版本之前,只要主从断开连接,再次连接时,直接就是RDB全量同步;redis2.8版本之后,主从断网重连之后,会采用增量的方式进行同步,当从节点断开连接后,主节点会将操作写入到repl_backlog_buffer这个缓存区中,其中repl_backlog_buffer是一个环形的缓存区结构。

其同步流程如下图所示:

从主节点恢复连接之后,从节点会发送psync命名给主节点,并把自己当前的 slave_repl_offset 发给主库,主节点会根据自身的master_repl_offset与slave_repl_offset进行比较,将两者之间的相差部分命令找到。

将相差的部分增量同步给从节点,主从集群保持数据一致。

存在的问题:因为主从结构中,只有一个主节点,当主节点出现故障后,无法提供写服务操作,存在单点故障问题,无法提供高可用的服务,这个时候哨兵模式的构架就出现了。

二、哨兵架构

哨兵节点就是一个特殊的redis节点,它不提供存放数据,只用来监控其他redis节点情况。

哨兵节点的主要作用分为三个方面,即监控、选主和通知功能。

监控:哨兵会周期的发送PING命令给所有主从节点,在规定的时间内收到了节点的响应,就认为节点是正常,如果没有在规定时间内给出响应,就认为节点出现了故障,为了防止对主节点的误判操作,引入哨兵集群来对主节点进行监控行为,所以对于redis节点来说,又分为主观下线和客观下线。

主观下线:单个哨兵节点发送PING命令给所监控的主、从节点,当主从节点对响应超时,哨兵节点就任务redis节点主线故障,将节点标记为主观下线。

客观下线:当哨兵集群中,超过半数(可以调整,默认半数)以上的节点,认为某个节点发生故障,那个这个节点就被判定为客观下线。

选主:当主节点发生故障了,如何从多个从节点中选出主节点?选主的步骤一般是先筛选出符合竞选条件的从节点,然后对这些从节点进行打分操作,分数最高的节点就是新的主节点。

通知:就是选举结束后,哨兵需要将新的主节点通过给客户端,让客户端可以继续进行写操作。针对客户端而言,通知可以分为主动获取和被动接受。

被动接受:哨兵会把新的主节点地址信息写入到实例的pubsub(switch-master)中,客户端需要订阅这个pubsub,来获取新的主节点信息,存在的问题就是当客户端错过了哨兵的通知的话,那么客户端将不会在拿到新的主节点信息。

主动拉取:客户端在访问主从库时,不能将配置写死在自身的配置中,而是需要从哨兵集群中获取redis节点信息(sentinel get-master-addr-by-name命令)。

当主从集群中的主节点故障后,如何将从节点选为新的主节点呢?首先会对从节点进行筛选,筛选的规则就是,主要就是检查从库的当前在线状态和之前的网络情况。对于之前的网络状态判断是通过参数down-after-milliseconds,来判断,如果主从节点超过这个时间点没有通信,就被认为是出现过一次断链,当超过10次以上断连时,哨兵认为其从节点的网络情况不是很好,会主动剔除这部分从节点。然后就对剩下的从节点进行打分操作,打分分为三个纬度,如果每一轮中会出现一个最高分,就会直接选出新的主节点,选举结束。三个层级分别是从库优先级、从库复制进度和从库ID号进行选举。

优先级最高直接得分最高:可以通过配置项slave-priority来配置,优先级越高,打的分数越高,直接被选为新的主节点。

从库同步数据最接近主库的得分最高:每个从库都有一个slave_repl_offset参数,旧的主节点会有一个master_repl_offset参数,当有从节点的slave_repl_offset最接近这个master_repl_offset这个参数时,就会被选举为新的主节点

ID号小的从库得分最高:每个redis实例,都会被设置一个编号,编号越小得分越高,就会被选举为新的主节点。

存在的问题:单个哨兵架构虽然解决了主从结构的单点故障问题,当主节点故障后,通过哨兵发起主从切换,可以保持redis的高可用性,但是此时哨兵节点还是只有一个,哨兵节点还是存在单点故障问题,所以哨兵集群架构就登场了。

三、哨兵集群结构

所谓的哨兵集群结构主要解决的问题,就是哨兵的单点故障问题,防止只有一个哨兵节点,当哨兵节点出现故障后,redis集群就不可用的情况。

多个哨兵之间如何通信呢?主要是通过redis本身提供的pub/sub机制,每个哨兵和主节点redis进行连接时,会将哨兵自身的ip和port,通过主库上有一个名为“__sentinel__:hello”的频道发送,当哨兵监控这个集群时,就会订阅这个频道的消息,所以通过这种方式,哨兵之间可以拿到其他节点的ip和port。

哨兵如何拿到redis集群的信息呢?哨兵通过与主节点进行连接后,通过info命令来获取关联主节点的从节点信息,其流程如下图:

哨兵如何和客户端进行通信?还是基于pub/sub机制,每个哨兵也是一个redis实例,所有哨兵节点也会有很多相关的频道,可以进行发布订阅。

客户端通过读取哨兵的配置文件后,读取到ip和port然后进行连接,然后可以通过在客户端执行响应的命令,即可订阅对应的消息,如:

哨兵的Leader选举机制?当我们的redis主节点出现故障后,需要由哨兵来进行主从切换,将某个从节点变成主节点,整个切换的流程是由哨兵中的某一个节点来进行操作,进行操作的节点我们称之为Leader节点。那么这个Leader节点是怎么来的呢,其选举的流程如下图:

当哨兵2对于redis主节点认为其主观下线后,它会向其它哨兵节点发送is-master-down-by-addr命令去询问其他节点是否认为redis主节点的已经主观下线。

此时哨兵1认为主节点没有问题,返回N,哨兵3也认为主节点有问题,返回Y。

哨兵配置文件中,有一个quorum 配置项,只要集群中超过或等于这个数量的节点,认为主节点进行主观下线,就会认为节点客观下线;在本例中我们将quorum设置为2,这时哨兵集群中,有两个节点主观下线,那么就会认为客观下线。

这时哨兵集群就需要进行leader选举,来选出leader节点,来执行主从切换工程。成为leader节点需要满足两个条件(拿到半数以上的赞成票;拿到的票数大于等于quorum设置的值)

sentinel-2成为leader节点,主从切换的流程会由leader节点来完成。

存在的问题:哨兵集群结构,虽然解决了哨兵的单点问题,但是此时的结构中,只有一个redis主节点,当redis的主节点数据量过大时,redis的持久化,提供写复制时,响应时间存在过长的情况,针对这种情况,redis切片集群就出现了。

四、Redis Cluster集群模式

采用redis集群模式,可以解决单点节点数据量大、写入量大产生的性能瓶颈的问题。多个节点组成一个集群,可以提高集群的性能和可靠性。redis Cluster采用哈希槽(Hash slot)方法,来处理数据和实例之间的映射关系,哈希槽最多有16384个节点。存放数据的步骤就是先将key值,通过CRC16算法获取值后,然后在和16384进行取模,看这个数据落在那个哈希槽中。

采用了redis cluster集群后,客户端访问数据时,如何知道我们的数据是落在哪个节点上呢?在我们的redis集群中,每个redis集群节点都有一个额外的TCP端口,每个节点使用TCP连接与每个其他节点连接。检测和故障转移这些步骤基本和哨兵模式类似,每个redis节点都会知道其他节点分配了哪些槽信息,当客户端使用命令来请求服务端时,如何这个命令刚好在这个节点上,直接返回数据,如何不再这个节点上,会返回对应的moved重定向命令,来告知客户端需要访问的数据所在的节点信息,如下所示:

还有一种情况就是,当我们的redis cluster集群增加或删除节点时,需要进行对应的数据迁移,此时,如何访问的数据正在迁移,就会返回ask命令。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20201028A0JDIN00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券