目录
- 1.安装部署(基于Docker)
- 1.编排Redis主从节点
- 2.编排Redis-Sentinel节点
- 2.重新选举
- 1.redis-master宕机之后
- 2.redis-master重启之后
- 3.总结
- 3.选举原理
- 4.总结
1.安装部署(基于Docker)
1.编排Redis主从节点
- 编写
docker-compose.yml
- 创建
/root/redis/docker-compose.yml
,同时cd
到yml
所在⽬录中 - 说明:docker中可以通过容器名字作为ip地址,进⾏相互之间的访问
version: '3.7' services: master: image: 'redis:5.0.9' container_name: redis-master restart: always command: redis-server --appendonly yes ports: - 6379:6379 slave1: image: 'redis:5.0.9' container_name: redis-slave1 restart: always command: redis-server --appendonly yes --slaveof redis-master 6379 ports: - 6380:6379 slave2: image: 'redis:5.0.9' container_name: redis-slave2 restart: always command: redis-server --appendonly yes --slaveof redis-master 6379 ports: - 6381:6379
- 创建
- 启动所有容器:
docker-compose up -d
- 查看运行日志:
docker-compose logs
2.编排Redis-Sentinel节点
- 说明:可以把
redis-sentinel
放到和上⾯的Redis的同⼀个yml
中进⾏容器编排,但此处分成两组,主要是为了两⽅⾯:- 观察⽇志⽅便
- 确保Redis主从节点启动之后才启动
redis-sentinel
- 如果先启动
redis-sentinel
的话,可能触发额外的选举过程,混淆视听 - 不是说先启动哨兵不⾏,⽽是观察的结果可能存在⼀定随机性
- 如果先启动
- 编写
docker-compose.yml
- 创建
/root/redis-sentinel/docker-compose.yml
,同时cd
到yml
所在⽬录中
version: '3.7' services: sentinel1: image: 'redis:5.0.9' container_name: redis-sentinel-1 restart: always command: redis-sentinel /etc/redis/sentinel.conf volumes: - ./sentinel1.conf:/etc/redis/sentinel.conf ports: - 26379:26379 sentinel2: image: 'redis:5.0.9' container_name: redis-sentinel-2 restart: always command: redis-sentinel /etc/redis/sentinel.conf volumes: - ./sentinel2.conf:/etc/redis/sentinel.conf ports: - 26380:26379 sentinel3: image: 'redis:5.0.9' container_name: redis-sentinel-3 restart: always command: redis-sentinel /etc/redis/sentinel.conf volumes: - ./sentinel3.conf:/etc/redis/sentinel.conf ports: - 26381:26379 networks: default: external: name: redis-data_default
- 创建
- 创建配置文件:创建
sentinel1.conf
、sentinel2.conf
、sentinel3.conf
,三分文件的内容是完全相同的,都放在/root/redis-sentinel/
⽬录中bind 0.0.0.0 port 26379 sentinel monitor redis-master redis-master 6379 2 sentinel down-after-milliseconds redis-master 1000
- 理解
sentinel monitor
:- 主节点名:这个是哨兵内部⾃⼰起的名字
- 主节点ip:部署
redis-master
的设备ip- 此处由于是使⽤docker,可以直接写docker的容器名,会被⾃动DNS成对应的容器ip
- 法定票数:哨兵需要判定主节点是否挂了,但是有的时候可能因为特殊情况
- ⽐如主节点仍然⼯作正常,但是哨兵节点⾃⼰⽹络出问题了,⽆法访问到主节点了
- 此时就可能会使该哨兵节点认为主节点下线,出现误判
- 使⽤投票的⽅式来确定主节点是否真的挂了是更稳妥的做法
- 需要多个哨兵都认为主节点挂了,票数 >= 法定票数之后,才会真的认为主节点是挂了
sentinel monitor 主节点名 主节点 ip 主节点端⼝ 法定票数
- 理解
sentinel down-after-milliseconds
:- 主节点和哨兵之间通过⼼跳包来进⾏沟通
- 如果⼼跳包在指定的时间内还没回来,就视为是节点出现故障
- 既然内容相同,为啥要创建多份配置⽂件?
redis-sentinel
在运⾏中可能会对配置进⾏rewrite
,修改⽂件内容- 如果⽤⼀份⽂件,就可能出现修改混乱的情况
- 理解
- 启动所有容器:
docker-compose up -d
- 查看运行日志:
docker-compose logs
2.重新选举
1.redis-master宕机之后
-
哨兵发现了主节点
sdown
,进⼀步的由于主节点宕机得票达到 2 / 3 2/3 2/3,达到法定得票,于是master
被判定为odown
- 主观下线(Subjectively Down,SDown):哨兵感知到主节点没⼼跳了,判定为主观下线
- 客观下线(Objectively Down,ODown):多个哨兵达成⼀致意⻅,才能认为
master
确实下线了
-
接下来,哨兵们挑选出了⼀个新的
master
,上图中,是172.22.04:6379
这个节点
-
此时,对于Redis来说仍然是可以继续使用的
2.redis-master重启之后
- 哨兵日志:刚才新启动的
redis-master
被当成了slave
3.总结
- Redis主节点如果宕机,哨兵会把其中的⼀个从节点,提拔成主节点
- 当之前的Redis主节点重启之后,这个主节点被加⼊到哨兵的监控中,但是只会被作为从节点使⽤
3.选举原理
- 假定生产环境如下
- 主观下线:
- 当
redis-master
宕机,此时redis-master
和三个哨兵之间的⼼跳包就没有了 - 此时,站在三个哨兵的⻆度来看,
redis-master
出现严重故障,因此三个哨兵均会把redis-master
判定为主观下线(SDown
)
- 当
- 客观下线:
- 此时,哨兵
sentenal1, sentenal2, sentenal3
均会对主节点故障这件事情进⾏投票 - 当故障得票数 >= 配置的法定票数之后,意味着
redid-master
故障这个事情被坐实,此时触发客观下线(ODown
)sentinel monitor redis-master 172.22.0.4 6379 2
- 此时,哨兵
- 选举出哨兵的
leader
- 接下来需要哨兵把剩余的
slave
中挑选出⼀个新的master
,这个⼯作不需要所有的哨兵都参与,只需要选出个代表(称为leader),由leader负责进⾏slave升级到master的提拔过程 - 这个选举过程涉及到
Raft
算法,假定一共三个哨兵节点S1,S2,S3- 每个哨兵节点都给其他所有哨兵节点,发起⼀个"拉票请求"
- S1 -> S2, S1 -> S3, S2 -> S1, S2 -> S3,S3 -> S1, S3 -> S2
- 收到拉票请求的节点,会回复⼀个 “投票响应”,响应的结果有两种可能, 投or不投
- 例如:S1给S2发了个投票请求,S2就会给S1返回投票相应
- S2是否要投S1,取决于S2是否给别人投过票了(每个哨兵只有一票)
- 如果没投过(S1是第一个向S2拉票的),S2就会投给S1,否则则不投
- 一轮投票完成之后,发现得票超过半数的节点,自动成为
leader
- 如果出现平票,则重新再投一次即可
- 这也是为啥建议哨兵节点设置成奇数个的原因,如果为偶数个,则增大了平票的概率,带来了不必要的开销
leader
节点负责挑选⼀个slave
成为新的master
,当其他的sentenal
发现新的master
出现了,就说明选举结束了
- 每个哨兵节点都给其他所有哨兵节点,发起⼀个"拉票请求"
- 综上,
Raft
算法的核心就是”先下手为强”,谁率先发出了拉票请求,谁就有更大的概率成为leader
- 决定因素:网络延时,其本身就带有一定的随机性
- 具体选出的哪个节点是
leader
不重要,重要的是能选出一个节点
- 接下来需要哨兵把剩余的
leader
挑选出合适的slave
成为新的master
- 挑选规则:
- 比较优先级,优先级高(数值小的)的上位
- 优先级是配置文件中的配置项
slave-priority
或者replica-priority
- 优先级是配置文件中的配置项
- 比较
replication offset
,谁复制的数据多,高的上位 - **比较
run id**,谁的
id`小,谁上位- 即:大小全凭缘分,选谁都可以,随便挑一个
- 比较优先级,优先级高(数值小的)的上位
- 当某个
slave
节点被指定为master
之后leader
指定该节点执行slave no one,成为
master`leader
指定剩余的slave
节点,都依附于这个新master
- 挑选规则:
4.总结
- 上述过程,都是"⽆⼈值守",Redis ⾃动完成的,这样做就解决了主节点宕机之后需要⼈⼯⼲预的问题,提⾼了系统的稳定性和可⽤性
- 注意事项:
- 哨兵节点不能只有一个,否则哨兵节点挂了也会影响系统可用性
- 分布式系统中,应该避免使用“单点”,应该有冗余
- 哨兵节点最好是奇数个,方便选举
leader
,得票更容易超过半数- 大部分情况下,3个就足够了
- 哨兵节点不负责存储数据,仍然是Redis主从节点负责存储
- 哨兵节点可以使用一些配置不高的机器来部署
- 哨兵 + 主从复制解决的问题是”提高可用性”,不能解决”数据极端情况下写丢失”的问题
- 哨兵 + 主从复制不能提高数据的存储容量,当需要存的数据接近或者超过机器的物理内存,这样的结构就不能胜任了
- 为了能存储更多的数据,就引入了集群
- 哨兵节点不能只有一个,否则哨兵节点挂了也会影响系统可用性