Redis Cluster 集群
Redis-cluster架构图
架构细节
-
所有的redis节点彼此互联( PING-PONG机制 ),内部使用二进制协议优化传输速度和带宽
-
节点的fail是通过集群中超过半数的节点检测失效时才生效
-
客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
-
redis-cluster把所有的物理节点映射到[0-16383] slot 上,cluster 负责维护
Redis 集群中内置了 16384个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点
Redis-cluster投票:容错
-
节点失效判断 :集群中所有master参与投票,如果 半数以上master节点 与其中一个master节点通信超过(cluster-node-timeout) ,认为该master节点挂掉
-
集群失效判断 :什么时候整个集群不可用(cluster_state:fail)
-
如果集群任意master挂掉,且当前master没有slave,则集群进入fail状态。也可以理解成集群的[0-16383]slot映射不完全时进入fail状态
-
如果集群超过半数以上master挂掉,无论是否有slave,集群进入fail状态
-
RedisCluster 集群创建
需要开启防火墙,或者直接关闭防火墙
service iptables stop
-
创建节点
Redis集群最少需要三台主服务器,三台从服务器
端口号分别为:8001~8006
-
第一步:创建8001实例,并编辑redis.conf文件,修改port为8001
注意:创建实例,即拷贝单机版安装时,生成的bin目录,为8001目录
-
第二步:修改redis.conf配置文件,打开cluster-enable yes
-
第三步:复制8001,创建8002~8006实例, 注意端口修改
cp 8001/ 8002 -r -
第四步:启动所有的实例
-
第五步:创建Redis集群
./redis-cli --cluster create 127.0.0.1:8001 127.0.0.1:8002 127.0.0.1:8003 127.0.0.1:8004 127.0.0.1:8005 127.0.0.1:8006 ƕcluster-replicas 1
-
-
创建集群
./redis-cli –h 127.0.0.1 –p 8001 –c -
查看集群状态
-
查看集群状态
cluster info -
查看集群中的节点
cluster nodes
-
cluster 从节点 默认不可写不可读 仅仅是备份
工作原理
-
客户端与Redis节点直连,不需要中间Proxy层,直接连接任意一个Master节点
-
根据公式HASH_SLOT=CRC16(key) mod 16384,计算出映射到哪个分片上,然后Redis会去相应的节点进行操作
优点
-
无需Sentinel哨兵监控,如果Master挂了,Redis Cluster内部自动将Slave切换Master
-
可以进行水平扩容
-
支持自动化迁移,当出现某个Slave宕机了,那么就只有Master了,这时候的高可用性就无法很好的保证了,万一Master也宕机了,咋办呢? 针对这种情况,如果说其他Master有多余的Slave ,集群自动把多余的Slave迁移到没有Slave的Master 中
缺点
-
批量操作是个坑
-
资源隔离性较差,容易出现相互影响的情况
-
主从切换
当集群中节点通过错误检测机制发现某个节点处于fail状态时,会执行主从切换,Redis 还提供了手动切换的方法,即通过执行 cluster failover 命令
-
自动切换
切换流程如下(假设被切换的主节点为M,执行切换的从节点为S)
-
S先更新自己的状态,将声明自己为主节点。并且将S从M中移除
-
由于S需要切换为主节点,所以将S的同步数据相关信息清除(即不再从M同步锁数据)
-
将M提供服务的slot都声明到S中
-
发送一个PONG包,通知集群中其他节点更新状态
-
-
手动切换
当一个节点接受到 cluster failover 命令之后,执行手动切换,流程如下
-
该从节点首先向主节点发送一个mfstart包。通知主节点从节点开始进行手动切换
-
主节点会阻塞所有客户端指令的执行。之后主节点在周期函数clusterCron中发送ping 包时会在包头部分做特殊标记
-
当从节点收到主节点的ping包并且检测到特殊标记之后,会从包头中获取主节点的复制偏移量
-
从节点在周期函数clusterCron中检测当前处理的复制偏移量与主节点复制偏移量是否相等,当相等时开始执行切换流程
-
切换完成后,主节点会将阻塞的所有客户端命令通过发送+MOVED 指令重定向到新的主节点
通过流程可以看到,手动执行主从切换流程时不会丢失任何数据,也不会丢失任何执行命令,只在切换过程中会有暂时的停顿
-
副本漂移
假设A发生故障,主A的A1会执行切换,切换完成后A1变为主A1,此时主A1会出现单点问题
在周期性调度函数 clusterCron中会定期检查如下条件
- 是否存在单点的主节点,即主节点没有任何一台可用的从节点
- 是否存在有两台及以上可用从节点的主节点
如果以上两个条件都满足,从有最多可用从节点中选择一台从节点执行副本漂移。选择标准为按节点名称从小到大,选择最靠前的一台从节点执行漂移
具体漂移过程
- 从C的记录中将C1移除
- 将C1所记录的主节点更改为A1
- 在A1中添加C1从节点
- 将C1的数据同步源设置为A1
漂移过程只是更改一些节点所记录的信息,之后会通过心跳包将该信息同步到所有的集群节点
添加节点
当集群需要扩容时需要向集群中添加新的节点
我们首先创建一个新的redis实例,端口为8007。其他配置同上
启动7007节点,然后使用redis-cli将新的节点添加到集群中
./redis-cli --cluster add-node 新节点的ip:端口 现有集群ip:端口
./redis-cli --cluster add-node 192.168.133.22:8007 192.168.133.22:8001
分配slot
我们可以看到新的节点已经添加到集群中了,但是新的节点中并没有任何槽在其上,也就意味着,不可能有数据放到这个节点上。那么我们需要将一部分槽移动到新的节点上
./redis-cli --cluster reshard 192.168.133.22:8001 --cluster-from f3ab5f5c53b82b8a9df24bfd4a8191224cf63597,faa53cbb6bae288d7f3a19fa55f18d7e77c9 7f6d,d33eab99055e05440a6ba1dd314efb0a25274fb1 --cluster-to 90dcd8e79fd753d24c35ef6ec63e65d79f56600a 3000
-
cluster-from:表示slot目前所在的节点的node ID,多个ID用逗号分隔
-
cluster-to:表示需要新分配节点的node ID(貌似每次只能分配一个)
-
cluster-slots:分配的slot数量
添加从节点
我们向集群中添加了一个新的节点7007,如果只有一个主节点的情况下,高可用性会下降。那么我们就应该给这个节点增加一个备份节点提高可用性。我们再添加一个节点7008,按照之前的配置方法配置,然后启动
./redis-cli --cluster add-node 192.168.133.22:8008 192.168.133.22:8007 -- cluster-slave --cluster-master-id 90dcd8e79fd753d24c35ef6ec63e65d79f56600a
-
add-node: 后面的分别跟着新加入的slave和slave对应的master
-
cluster-slave:表示加入的是slave节点
-
cluster-master-id:表示slave对应的master的node ID
收缩集群
-
首先删除master对应的slave
./redis-cli --cluster del-node 192.168.133.22:8008 5e8924bef3cfb0a07838d45da77e9a2e0e61d7b9del-node后面跟着集群中的任意节点的ip及端口号(主要目的是连接到集群,ip:port) 和node ID
-
清空master的slot
./redis-cli --cluster reshard 192.168.133.22:8007 --cluster-from 90dcd8e79fd753d24c35ef6ec63e65d79f56600a --cluster-to f3ab5f5c53b82b8a9df24bfd4a8191224cf63597 ƕcluster-slots 3000 ƕcluster-yes由于我们的集群一共有四个主节点,而每次reshard只能写一个目的节点,因此以上命令需要执行三次( ƕcluster-to对应不同的目的节点)
--cluster-yes:不回显需要迁移的slot,直接迁移
-
下线(删除)节点
./redis-cli --cluster del-node 192.168.133.22:8007 90dcd8e79fd753d24c35ef6ec63e65d79f56600