一、集群架构
架构图
- Redis集群是一个由多个主从节点群组成的分布式服务器群,它具有复制、高可用和分片特性。
- Redis集群不需要sentinel哨兵也能完成节点移除和故障转移的功能。
- 需要将每个节点设置成集群模式,这种集群模式没有中心节点,可水平扩展。PS:官方推荐不超过1000个节点。
- redis集群的性能和高可用性均优于之前版本的哨兵模式,且集群配置非常简单。
构建步骤
1、创建用于演示的集群文件夹
mkdir cluster
2、给对应端口创建目录
cd cluster
mkdir 8000 8001 8002 8003 8004 8005
3、复制redis.conf文件到对应的目录下
cp redis.conf zhRedisDemo/cluster/8000
cp redis.conf zhRedisDemo/cluster/8001
cp redis.conf zhRedisDemo/cluster/8002
cp redis.conf zhRedisDemo/cluster/8003
cp redis.conf zhRedisDemo/cluster/8004
cp redis.conf zhRedisDemo/cluster/8005
4、修改配置文件的值【6台机器的都要修改】
daemonize yes #守护线程方式启动【后台运行】
port 8000 #端口
pidfile /var/run/redis_8000.pid #把pid进程号写入pidfile配置的文件
dir /usr/local/redis‐cluster/8000/ #指定数据文件存放位置,必须要指定不同的目录位置,不然会丢失数据
cluster‐enabled yes #启动集群模式
cluster‐config‐file nodes‐8000.conf #集群节点信息文件,这里800x最好和port对应上
cluster‐node‐timeout 10000 #集群连接超时时间
#bind 127.0.0.1 #bind绑定的是自己机器网卡的ip,如果有多块网卡可以配多个ip,代表允许客户端通过机器的哪些网卡ip去访问,内网一般可以不配置bind,注释掉即可
protected‐mode no #关闭保护模式
appendonly yes #打开AOF持久化
equirepass xxxxxxx #设置redis访问密码
masterauth xxxxxxx #设置集群节点间访问密码,跟上面一致
5、分别启动6台实例
6、使用redis‐cli创建整个redis集群【Redis5.0+版本】
redis-cli -a 密码 --cluster create --cluster-replicas 1 120.24.58.161:8000 120.24.58.161:8001 120.24.58.161:8002 120.24.58.161:8003 120.24.58.161:8004 120.24.58.161:8005
二、Redis集群原理的一些概念
16384slots(槽位),每个节点负责其中一部分槽位。槽位的信息存储于每个节点中。
集群的槽位配置信息并将其缓存在客户端本地。这样当客户端要查找某个key时,可以直接定位到目标节点。
PS:因为槽位的信息可能会存在客户端与服务器不一致的情况,还需要纠正机制来实现槽位信息的校验调整。
槽位定位算法
Cluster 默认会对key值使用crc16算法进行hash得到一个整数值,然后用这个整数值对16384进行取模来得到具体槽位。
HASH_SLOT = CRC16(key) mod 16384
PS:新节点加入集群中时是无法写数据的(没有slot槽位),需要从新分配槽位后才可以访问
PS:迁移槽位会把对应的数据也迁移过去
PS:新节点加入集群时都是master节点
跳转重定位
当客户端向一个错误的节点发出了指令,该节点会发现指令的key所在的槽位并不归自己管理,这时它会向客户端发送一个特殊的跳转指令携带目标操作的节点地址,告诉客户端去连这个节点去获取数据。
客户端收到指令后除了跳转到正确的节点上去操作,还会同步更新纠正本地的槽位映射表缓存,后续所有key将使用新的槽位映射表。
Redis集群节点间的通信机制
Redis cluster节点间采取gossip协议进行通信,有两种方式:
集中式
- 优点:元数据的更新和读取,时效性非常好,一旦元数据出现变更立即就会更新到集中式的存储中,其他节点读取的时候立即就可以立即感知到。
- 缺点:所有的元数据的更新压力全部集中在一个地方,可能导致元数据的存储压力。
PS:很多中间件都会借助zookeeper集中式存储元数据。
gossip
- 优点:元数据的更新比较分散,不是集中在一个地方,更新请求会陆陆续续,打到所有节点上去更新,有一定的延时,降低了压力。
- 缺点:元数据更新有延时可能导致集群的一些操作会有一些滞后。
gossip协议包含多种消息,包括ping,pong,meet,fail等等。
- meet:某个节点发送meet给新加入的节点,让新节点加入集群中,然后新节点就会开始与其他节点进行通信。
- ping:每个节点都会频繁给其他节点发送ping,其中包含自己的状态还有自己维护的集群元数据,互相通过ping交换元数据【类似自己感知到的集群节点增加和移除,hash slot信息等】。
- pong:对ping和meet消息的返回,包含自己的状态和其他信息,也可以用于信息广播和更新。
- fail:某个节点判断另一个节点fail之后,就发送fail给其他节点,通知其他节点,指定的节点宕机了。
gossip通信的10000端口
自己提供服务的端口号+10000,
举个🌰:比如8000,那么用于节点间通信的就是18000端口。
网络抖动
定义:网络通信中,有时会因为一些客观原因使得网络突然中断或者波动而变得不可访问。
cluster-node-timeout,表示当某个节点持续timeout的时间失联时,才可以认定该节点出现故障,需要进行主从切换。
PS:这个配置很重要,如果没有这个选项,网络抖动会导致主从频繁切换 【数据的重新复制】。
三、Redis集群选举原理分析【重点理解哈~】
当slave发现自己的master变为FAIL状态时,便尝试进行Failover,以期成为新的master。
由于挂掉的master可能会有多个slave,从而存在多个slave竞争成为master节点的过程,其过程如下:
- 1、slave发现自己的master变为FAIL
- 2、将自己记录的集群currentEpoch【当前分代】加1,并广播FAILOVER_AUTH_REQUEST信息
- 3、其他节点收到该信息,只有master响应,判断请求者的合法性,并发送FAILOVER_AUTH_ACK【相当于投票】。PS:对每一个epoch只发送一次ack。
- 4、尝试Failover【期待上位~】的slave收集master返回的FAILOVER_AUTH_ACK【投的票数】
- 5、slave收到超过半数master的ack后变成新Master【半数选举机制】(这里解释了集群为什么至少需要三个主节点,如果只有两个,当其中一个挂了,只剩一个主节点是不能选举成功的)
- 6、slave广播Pong消息通知其他集群节点。
四、Redis集群脑裂问题
问题的产生
无法同步数据导致了重新选举【PS:这时主节点是存活的,只是网络问题导致无法同步】而后网络恢复导致该小集群出现2个主节点对外提供服务。
规避的方法
在redis.conf配置文件下更改:【务必理解 手打不易】
min‐replicas‐to‐write 1 #这个配置的意思是主节点写数据完成后,最少需要同步的slave数量【举个🌰:比如1主2从的机制,原来的主节点因为网络波动被判定为挂了,此时新的从节点想上位,那么它必须要能给另外1个从节点进行redis写的同步,它才能成为主节点。此时对于这个从节点除了自己以外他还有一个从节点对其进行数据同步,那么1+1>2/3符合半数选举机制】
PS:这个配置在一定程度上会影响集群的可用性,比如slave要是少于1个,那么没有从节点写入数据,就满足不了这个配置,那就不能对外提供服务了。
五、Redis集群和哨兵的区别
1、哨兵只提供一个主节点,同步时也是全量同步。集群的数据是分片放的,分片意味着数据是不重叠的。
2、哨兵架构可以写主读从,但是集群架构读写都走主节点。
3、哨兵架构收到单机数据量制约【一般不超过10个G】,集群架构可以很方便的进行水平扩展【当然操作起来还需要分配slots槽等等是有些麻烦】。
4、哨兵架构中的哨兵角色只是起到监控的作用,但不对外提供服务,相当于占用了资源。集群的话每一台主机都是主/或从,就不会有哨兵角色的这种主机资源“浪费”。
六、小问答
Q:Redis集群为什么至少需要三个master节点,并且推荐节点数为奇数?
因为新master的选举需要大于半数的集群master节点同意才能选举成功,如果只有两个master节点,当其中 一个挂了,是达不到选举新master的条件的。
举个🌰:3个master,挂了1个,则挂了的master其对应的slave若是获得了另外两个master的支持【2>3/2】,则它就可以成为master。
举个反🌰:2个master,挂了1个,那么就算另外一个master选出一个slave作为新的master,此时票数也不够【1=2/2】,达不到半数效果。
举个反🌰:4个master,如果挂了1个,选举方式和3个master的方式类似,可以达到半数选举的效果。但如果挂了2个,场景和上面的类似,也一样无法选出新的master。
小结
- 为什么至少需要3个master节点:半数选举机制
- 为什么推荐节点数为奇数:从节省机器资源角度出发考虑的
Q:集群是否完整才能对外提供服务?
不一定,redis.conf可以配置:
#表示当负责一个插槽的主库下线且没有相应的从库进行故障恢复时,集群仍然可用,如果为yes则集群不可用。
cluster-require-full-coverage no
Q:为啥redis.cond文件内部要写集群信息?
因为当关闭所有机器的时候,再次重启可以通过配置文件来恢复集群信息。
PS:集群重启不要用创建集群的命令,直接启动单台机器即可。
Q:集群内部主从为啥不放在一台机器上?
为了更安全,如果放在一台机器上,一个小集群挂了就整个集群全部挂掉。