Redis分布式实现有三种模式,分别是主从模式,哨兵模式和 Cluster集群模式。
下面分别就这三种模式进行说明
Redis主从模式
在Redis的主从模式中,客户端对master主节点进行数据的更新,从节点slave读取数据。
Redis主从模式的优缺点如下:
- 优点:读写分离,减轻服务器压力。
- 缺点:存在数据同步的延迟问题;无法保证Redis集群的高可用。
Redis主从模式同步分为全量同步和增量同步。
全量同步执行流程:
- 从服务器连接主服务器,发送SYNC命令;
- 主服务器接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命令;
- 主服务器BGSAVE执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令;
- 从服务器收到快照文件后丢弃所有旧数据,载入收到的快照;
- 主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;
- 从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令;
简单而言便是:slave发送同步命令,master节点执行BGSAVE命令,生成快照文件,发送快照文件和写命令,slave节点解析快照并执行写命令同步。
增量同步执行流程:
增量复制的过程主要是主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令。
redis2.8版本之后,已经使用psync来替代sync,因为sync命令非常消耗系统资源,psync的效率更高。
Redis哨兵模式(Sentinel)
在Redis的主从模式中,当master节点出现故障后,我们需要手动重新指定一个master节点作为新的主节点,这样一来就无法达到高可用的目的。
于是,从在Redis 2.8版本开始,解决这一问题新的模式变出现了,那就是哨兵模式,它用于redis主从状态的监控,能够在master节点发生故障时,重新选取master节点,确保分布式redis的高可用。
Redis哨兵模式工作原理
- 哨兵通过向master节点发送INFO命令,获取slave节点列表信息。
- 哨兵节点之前通过订阅发布(pub/sub)的方式进行通信。
- 每个哨兵节点以每秒1次的频率向其它的哨兵节点发送ping命令,同时也向master和slave节点发送ping命令用于判断是否在线。
- 某个实例节点超时响应则会被哨兵认为主观下线,有足够数量的哨兵节点(N/2+1)确认master节点响应超时那么这个master节点将会标记为客观下线。
- 当master节点为sdown状态时,哨兵节点要重新投票选举一个master节点,并将剩余的从节点指向新的主节点。
选举机制原理
选举机制分为筛选加排序2个步骤:
- 筛选:筛选正常响应的slave节点,剔除响应异常的slave节点。
- 排序:根据slave服务器的优先级、复制偏移量、运行id进行排序,找到一个slave服务器为新的master服务器。
哨兵节点的数量需要设置为2N+1
哨兵模式的优缺点
- 优点:解决了主从模式的master节点故障自动选举的问题,可用性更高。
- 缺点:较难支持在线扩容,对于容量达到上限,扩容会变得复杂。
Redis Cluster集群模式
在前面介绍的Redis模式中,没有解决在线扩容的问题,为了解决这一问题,在Reids3.0版本后 Redis Cluster集群模式出现了,实现了对数据的分片存储。
Redis Cluster 集群模式具有 高可用、可扩展性、分布式、容错 等特性。
Cluster集群模式的原理
在Redis Cluster集群模式中被划分为16384个槽位,每个节点负责其中一部分槽位slot,客户端查找某个key是根据槽位信息表,定位到目标节点。
槽位信息算法会对key值使用CRC16算法hash得到一个整数值,然后再对16384进行取模得到具体的槽位,hash slot=CRC16(key)%16384 。
Cluster集群模式中,用户可以自定义挂载到某个特定的slot的槽位上。
Gossip协议
集群模式通过Gossip协议进行消息通信,常用的Gossip消息分为 ping消息、 pong消息、 meet消息、 fail消息等。
- meet:某个节点在内部发送了一个gossip meet 消息给新加入的节点,通知那个节点去加入我们的集群。然后新节点就会加入到集群的通信中
- ping:每个节点都会频繁给其它节点发送 ping,其中包含自己的状态还有自己维护的集群元数据,互相通过 ping 交换元数据。
- pong:ping 和 meet消息的返回响应,包含自己的状态和其它信息,也用于信息广播和更新。
- fail:某个节点判断另一个节点 fail 之后,就发送 fail 给其它节点,通知其它节点说这个节点已宕机。
Redis集群一致性hash算法
传统的取模算法存在一些问题,当需要做节点扩容的时候,会涉及到数据的大量迁移。
举例说明
假设我们有0,1,2,3,4,5,6,7,8,9 十个数据,3个slot卡槽存储这些数据,取模算法是用number对3取余(slot=number%3)。
存储结果如下:
slot A 0,3,6,9
slot B 1,4,7
slot C 2,5,8
当我们增加一个节点D的时候,取模算法是用number对4取余(slot=number%4)存储结果如下:
Slot A 0,4,8
Slot B 1,5,9
Slot C 2,6
Slot D 3,7
那么这就会存在一个问题,前面卡槽A,B,C的节点需要做迁移了。
显然这种算法传统的取模算法不适合做集群节点的扩容,我们可以用一致性hash算法解决这样的问题。
一致性hash协议的实现思路是
- 将每个节点node生成一个hash值,范围是0~2^32-1,形成一个环状的hash空间,如图,上面的hash环显示了3个节点node1,node2,node3。
- 采用相同的方法将key值放在这个hash环上,如图,上面的hash环显示了9个key值,k1~k9。
- 然后使用顺时针的方式为key值找到最近的node节点,那么这个key值变存储到该节点上,如图,上面的hash环中,k7,k8,k9,k1存储节点Node1,k2,k3,存储节点node2,k4,k5,k6 存储节点node3。
下面看一下在hash环中,新加节点和删除节点,其它key值的变动情况。
新加节点node4,假设node4位于k7和k8之间,按照顺时针的原则,那么此时需要将k7值重新映射到node4节点即可。
移除节点node2,此时,按照顺时针的原则,k2 和k3的值需要重新映射到新的节点node3即可。
显然一致性hash协议解决了数据扩容需要大量迁移的问题。
hash环数据倾斜问题
有些时候当我们的节点较少,key值可能大部分映射到某个node节点上,会造成hash环的数据分配不平衡。
在上面的例子中假设我们没有节点node3,那么之前指向node3节点的k4,k5,k6便会指向新的节点node1,如图:
这样的话,node1节点上会存放k4,K5,k6,k7,k8,k9,k1 7个key值,为了解决这个问题,引入了虚拟节点的机制。
一致性hash虚拟节点的概念是 hash环上有多个虚拟节点,每个虚拟节点对应一个真实节点。
在上面的例子中,虚拟节点3和4对应真实节点1,虚拟节点1和2对应真实节点2。
这样一来
真实节点1存放 k4,k5,k6,k7
真实节点2存放k1,k2,k3,k8,k9
解决了一致性hash数据倾斜问题。