目录
5.1、Redis不同节点之间是如何进行通信进行维护集群的同步状态呢?
下一篇:redis双写一致性及分布式锁
1、为啥需要Redis集群
一主N从,到读写分离,再到哨兵机制,故障转移这些架构Redis仍然是单节点模式。
某些场景下,单实例存Redis缓存会存在的几个问题:
(1)写并发:单节点可解决读操作的负载,但是写操作仍然是全部落在了master节点上面。
(2)海量数据存储压力:单节点只有一台master节点作为存储
集群读写分离:
成本高,一般扩展主节点方式提高集群性能
2、什么是集群模式
Redis3.0加入了Redis的集群模式,实现了数据的分布式存储,对数据进行分片,将不同的数据存储在不同的master节点上面,从而解决了海量数据的存储和吞吐量问题。
每个节点独立,通过Gossip协议进行通信和数据同步,自动故障转移。
至少6个节点才能正常工作,其中3个节点用于存储数据,另外3个节点用于复制数据和故障转移。
Redis集群采用去中心化的思想,没有中心节点的说法,对于客户端来说,整个集群可以看成一个整体,可以连接任意一个节点进行操作,就像操作单一Redis实例一样,不需要任何代理中间件,当客户端操作的key没有分配到该node上时,Redis会返回转向指令,指向正确的node。
默认只有master节点具有处理请求(读和写)的能力,slave节点主要是用于节点的高可用:
集群模式下的故障转移:
每个master节点都可以挂载多个slave节点,当master节点挂掉时,集群会提升它的某个slave节点作为新的master节点。
跟主从复制读写分裂区别:
redis集群的读和写都是到master上去执行的,不支持slave节点读和写。redis集群的核心的理念,主要是使用slave做数据的热备,以及master故障时的主备切换实现高可用的;Redis的读写分离,是为了横向任意扩展slave节点去支撑更大的读吞吐量。而redis集群架构下,本身master就是可以任意扩展的
3、Redis集群的数据分布算法:哈希槽算法
对于分布式存储,需要考虑的重点就是如何将数据进行拆分到不同的Redis服务器上,常见的分区算法有hash算法、一致性hash算法等。
3.1、普通hash算法
将key使用hash算法计算之后,按照节点数量来取余,即hash(key)%N。优点就是比较简单,但是扩容或者摘除节点时需要重新根据映射关系计算,会导致数据重新迁移。
3.2、一致性hash算法
为每一个节点分配一个token,构成一个哈希环;查找时先根据key计算hash值,然后顺时针找到第一个大于等于该哈希值的token节点。优点是在加入和删除节点时只影响相邻的两个节点,缺点是加减节点会造成部分数据无法命中,所以一般用于缓存,而且用于节点量大的情况下。
3.3、哈希槽分区算法
Redis集群采用的算法。Redis集群中有16384个哈希槽(槽的范围是 0 -16383),将不同的哈希槽分布在不同的Redis节点上面进行管理,每个Redis节点只负责一部分的哈希槽。在对数据进行操作的时候,集群会对使用CRC16算法对key进行计算并对16384取模(slot = CRC16(key)%16383),得到的结果就是 Key-Value 所放入的槽,通过这个值,去找到对应的槽所对应的Redis节点,然后直接到这个对应的节点上进行存取操作。
(1)优点
方便的添加或者移除节点,并且无论是添加删除或者修改某一个节点,都不会造成集群不可用的状态。当需要增加节点时,只需要把其他节点的某些哈希槽挪到新节点就可以了;当需要移除节点时,只需要把移除节点上的哈希槽挪到其他节点就行了。 简化了扩容和收缩难度
4、Redis集群请求重定向
4.1、什么是请求重定向
无论Redis 的客户端访问集群中的哪个节点都可以路由到对应的节点上,怎么通过路由实现?
(1)客户端向Redis集群的某个节点发送一个读写请求
(2)节点根据请求中的键,计算出键的哈希值,并确定该键所在的哈希槽
(3)节点判断自己释放该槽主节点,是则直接处理,不是则分情况。如果节点在做数据迁移则返回ASK重定向请求,客户端根据ASK内容向指定节点发送ASKing命令询问,收到应答后再正式请求,如果节点没在做数据迁移,则直接返回MOVE重定向请求,客户端直接请求新目标节点。
4.2、如何解决频繁重定向网络开销问题
重定向映射表缓存:Redis集群中的每个节点都会维护一个重定向缓存,用于缓存最近的重定向信息,会先查缓存
4.3、JedisCluster的工作原理
JedisCluster是Redis官方提供的Java客户端,用于连接和操作Redis集群
(1)JedisCluster初始化连接:就会随机选择一个node,初始化 重定向缓存映射表,同时为每个节点创建一个JedisPool连接池;
(2)本地计算哈希槽:执行操作时先本地计算哈希槽,然后在本地映射表找到对应的节点node;
(3)随意请求一个节点:如果刚好该节点计算出是该哈希槽直接返回;如果节点间在做同步则返回ASK重定向,客户先ASKing指定节点等待回复再请求 ;如果节点没有在同步,则返回MOVE重定向,直接重新请求指定正确节点
(4)更新缓存映射表:根据返回的MOVE则更新,返回ASK则等待正确请求后再更新
5、Redis集群中节点的通信机制:goosip协议
5.1、Redis不同节点之间是如何进行通信进行维护集群的同步状态呢?
当集群的状态发生变化时,比如新节点加入、数据迁移、节点宕机、slave提升为新Master等等,希望这些变化尽快被其他节点发现。
(1)集群中每个节点都会单独开一个TCP通道,用于节点之间通信;
(2)每个节点在固定周期内随机选择几个节点发送ping消息;
(3)接收到ping消息的节点用pong消息作为响应。很简单的一个TCP通信
(4)节点采用goosip协议(最终一致性)进行通信,底层还是TCP,该协议像病毒传播,不同节点之间不间断通信互换信息,最终整个集群信息会同步一致;
(5)redis集群每隔节点都开放2个端口,一个6379服务器端口一个16379就是用来节点之间通信的
5.2、gossip协议常见的消息类型包含
- ping:用来交换节点元数据
- pong:响应meet和ping
- meet:通知新节点加入集群
- fail:某个节点判断另一个节点fail后,广播所有节点该节点挂掉的消息,其他节点收到后会标记他已经下线
6、集群的故障检测与故障转恢复机制
6.1、集群的故障检测
基于gossip协议,集群中的每个节点都会定期地向集群中的其他节点发送PING消息,以此交换各个节点状态信息
(1)主观下线
当节点A检测到与节点B的通讯时间超时,就会更新本地缓存节点状态,把节点B更新为主观下线
(2)客观下线
下线信息也会通过 Gossip 消息传遍所有节点,当半数以上节点标记了节点B是主观下线时,便会被标记客观下线
6.2、集群故障恢复
(1)从节点过滤
slave与master断开连接时间超过指定值,直接过滤掉不能参与选举master
(2)投票选举master
如果slave得到过半票则升为master节点
(3)替换主节点
删除原来主节点负责槽数据,把这些槽数据添加到自己节点上,并广播,新的主节点诞生