1.Redis 主从复制
1.1.用途
1、Redis 主从是构建redis集群最基础的操作
2、读写分离,扩展主节点的读能力,分担主节点读压力
1.2.redis 一主两从搭建
1、Redis 安装(3个节点都要)
yum install -y gcc-c++ autoconf automake cd /usr/local/ wget http://download.redis.io/redis-stable.tar.gz tar xvzf redis-stable.tar.gz cd redis-stable make echo "redis installed"
2、master 节点配置
# cat /usr/local/redis-stable/redis-master.conf bind * -::* port 6379 daemonize yes logfile ./master.log dir ./ dbfilename "master.rdb" requirepass "123456" appendonly yes appendfilename "master.aof" # 是指从服务器连接到主服务器时认证使用的密码 masterauth "123456"
3、slave1 节点配置
# cat redis-slave1.conf bind * -::* port 6379 daemonize yes logfile ./slave1.log dir ./ dbfilename "slave1.rdb" requirepass "123456" appendonly yes appendfilename "slave1.aof" # 设置主服务器IP和通信端口 replicaof 172.16.247.3 6379 # 与主服务器通信时密码 masterauth "123456" # 从节点只读 replica-read-only yes
4、slave2 节点配置
# cat redis-slave2.conf bind * -::* port 6379 daemonize yes logfile ./slave2.log dir ./ dbfilename "slave2.rdb" requirepass "123456" appendonly yes appendfilename "slave2.aof" # 设置主服务器IP和通信端口 replicaof 172.16.247.3 6379 # 与主服务器通信时密码 masterauth "123456" # 从节点只读 replica-read-only yes
5、分别启动一主两从三个服务
cd /usr/local/redis-stable ./src/redis-server ./redis-master.conf ./src/redis-server ./redis-slave1.conf ./src/redis-server ./redis-slave2.conf
6、登陆redis master cli客户端,使用info命令验证主从配置情况
1.3.主从原理
主从复制分两种(主从刚连接的时候,进行全量复制;全量复制结束后,进行增量复制)
1.3.1.全量复制
- master服务器会开启一个后台进程用于将redis中的数据生成一个rdb文件
- 主服务器会缓存所有接收到的来自客户端的写命令,当后台保存进程处理完毕后,会将该rdb文件传递给slave服务器
- slave服务器会将rdb文件保存在磁盘并通过读取该文件将数据加载到内存
- 在此之后master服务器会将在此期间缓存的命令通过redis传输协议发送给slave 服务器
- 然后slave服务器将这些命令依次作用于自己本地的数据集上最终达到数据的一致性
1.3.2.增量复制
Slave初始化后开始正常工作时主服务器发生的写操作同步到从服务器的过程
服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令
1.4.无盘复制
- 完全重新同步需要在磁盘上创建一个RDB文件,然后加载这个文件以便为从服务器发送数据 在比较低速的磁盘,这种操作会给主服务器带来较大的压力
- 新版支持无磁盘的复制,子进程直接将RDB通过网络发送给从服务器,不使用磁盘作为中间存储
只需要在redis配置中增加下面配置即可实现无盘复制
repl-diskless-sync no
注意:使用无盘复制会降低可靠性,生产可靠性高于性能,所以这种方式不建议生产使用。
2.Redis Sentinel
前面的redis主从集群,当主服务器宕机后,需要手动把一台从服务器切换为主服务器,人工干预费时费力,还会造成一段时间内服务不可用。这个时候redis Sentinel就该上场了
2.1.哨兵Sentinel介绍
- Redis提供了Sentinel的命令,是一个独立的进程
- Sentinel通过发送命令给多个节点,等待Redis服务器响应,从而监控运行的多个Redis实例的运行情况
- 当Sentinel监测到master宕机,会自动将slave切换成master,通过通知其他的从服务器,修改配置文件切换主机
- 配置哨兵之后,redis client连接server的地址,就需要填写哨兵的地址
2.2.Sentinel 职能
监控(Monitoring)
Sentinel 会不断地检查你的主服务器和从服务器是否运作正常
提醒(Notification)
当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应 用程序发送通知
自动故障迁移(Automatic failover)
当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改 为复制新的主服务器
当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集 群可以使用新主服务器代替失效服务器
2.3.Sentinel集群架构
一个哨兵进程对redis服务进行监控,会出现单点问题,生产都是使用多个哨兵进行监控,各个哨兵之间还会进行监控,形成多哨兵模式,涉及到选举算法的问题,哨兵节点需要以奇数节点出现
2.4.哨兵集群搭建
说明:哨兵集群搭建基于上文的主从复制基础上进行
1、增加哨兵配置文件
节点1配置:
# cat sentinel-1.conf port 26379 bind 0.0.0.0 daemonize yes logfile "./sentinel-1.log" dir "./" sentinel monitor mymaster 172.16.247.3 6379 2 sentinel down-after-milliseconds mymaster 5000 sentinel auth-pass mymaster 123456 sentinel failover-timeout mymaster 30000
节点2配置:
# cat sentinel-2.conf port 26379 bind 0.0.0.0 daemonize yes logfile "./sentinel-2.log" dir "./" sentinel monitor mymaster 172.16.247.3 6379 2 sentinel down-after-milliseconds mymaster 5000 sentinel auth-pass mymaster 123456 sentinel failover-timeout mymaster 30000
节点3配置:
# cat sentinel-3.conf port 26379 bind 0.0.0.0 daemonize yes logfile "./sentinel-3.log" dir "./" sentinel monitor mymaster 172.16.247.3 6379 2 sentinel down-after-milliseconds mymaster 5000 sentinel auth-pass mymaster 123456 sentinel failover-timeout mymaster 30000
参数说明:
- sentinel monitor:说明当有2个Sentinel节点无法访问172.16.247.3:6379 ,就客观认为该Master不可用,将master做下线处理,并进行故障转移(failover) ,额外补充下mymaster是Sentinel分组名称,同一组sentinel必须设置相同的名字mymaster
- sentinel down-after-milliseconds:说明当ping 超过5000毫秒没响应,则主观判定为下线
- sentinel failover-timeout:说明当超过30秒还没有完成故障转移,则认为故障转移失败.
- sentinel auth-pass:连接到masterauth时设置的密码
2、三个节点都启动sentinel
./src/redis-server ./sentinel-1.conf --sentinel ./src/redis-server ./sentinel-2.conf --sentinel ./src/redis-server ./sentinel-3.conf --sentinel
3、验证
查看sentinel是否正常
# cat sentinel-1.log 9461:X 17 Oct 2022 08:47:07.007 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo 9461:X 17 Oct 2022 08:47:07.008 # Redis version=7.0.5, bits=64, commit=00000000, modified=0, pid=9461, just started 9461:X 17 Oct 2022 08:47:07.008 # Configuration loaded 9461:X 17 Oct 2022 08:47:07.009 * Increased maximum number of open files to 10032 (it was originally set to 1024). 9461:X 17 Oct 2022 08:47:07.009 * monotonic clock: POSIX clock_gettime 9461:X 17 Oct 2022 08:47:07.012 * Running mode=sentinel, port=26379. 9461:X 17 Oct 2022 08:47:07.014 * Sentinel new configuration saved on disk 9461:X 17 Oct 2022 08:47:07.014 # Sentinel ID is 612c0c169d9b2a40a30b818596550a6fea96df23 9461:X 17 Oct 2022 08:47:07.014 # +monitor master mymaster 172.16.247.3 6379 quorum 2 9461:X 17 Oct 2022 08:47:07.015 * +slave slave 172.16.247.4:6379 172.16.247.4 6379 @ mymaster 172.16.247.3 6379 9461:X 17 Oct 2022 08:47:07.016 * Sentinel new configuration saved on disk 9461:X 17 Oct 2022 08:47:07.016 * +slave slave 172.16.247.5:6379 172.16.247.5 6379 @ mymaster 172.16.247.3 6379 9461:X 17 Oct 2022 08:47:07.017 * Sentinel new configuration saved on disk 9461:X 17 Oct 2022 08:47:18.320 * +sentinel sentinel 4e274d4f2e54bacfc024b9b3b083ec341a8cd916 172.16.247.4 26379 @ mymaster 172.16.247.3 6379 9461:X 17 Oct 2022 08:47:18.330 * Sentinel new configuration saved on disk 9461:X 17 Oct 2022 08:48:15.106 * +sentinel sentinel 93941c1aa669616952294557a93c8560eb6d9ef9 172.16.247.5 26379 @ mymaster 172.16.247.3 6379 9461:X 17 Oct 2022 08:48:15.116 * Sentinel new configuration saved on disk
redis 命令验证是否正常
redis-cli -p 26379 info
手动关机redis master节点,验证是否可以正常完成redis主从故障转移
可以看出redis master节点已经从172.16.247.3,切换到了172.16.247.5,并且只剩余一个从节点
172.16.247.3节点开机在启动redis和sentinel进程后会自动成为172.16.247.5的从节点
2.5.哨兵故障转移原理
2.5.1.判断实例下线
- 实例的下线状态分为主观下线和客观下线。哨兵会通过PING命令检测所有的实例,没有响应的实例就会被哨兵标记为主观下线状态。如果该实例为从库,哨兵会直接将他标记为主观下线。
- 如果实例为主库,如果是单哨兵模式的情况下,该主库会被哨兵直接标记为主观下线,然后开始新主库的选举工作。如果是哨兵集群模式,需要多个哨兵一起判断该主库是否无响应,如果超过一定值的哨兵实例判断该主库为主观下线,那么这个主库就正式被标记为客观下线,开始进行新主库的选举工作。哨兵集群模式会在下文进行分析。
2.5.2.选举新主库
2.5.2.1.筛选
选举新主库的第一步会进行筛选操作,主要是为了筛选出正常运行且运行良好的从库,目的是为了防止选举出来的新主库又由于网络故障等原因导致哨兵又得重新选举新出库的现象。所以要对这些从库当前的在线状态和之前的网络状态进行筛选。
2.5.2.2.筛选规则
配置项sentinel.conf中的downaftermilliseconds表示设置的主从库断连的最大连接超时时间,默认为30秒。 如果在30秒内,主从节点都没通过网络连接和响应并且发生的次数超过了10次,就说明该从库的网络状况不好,不适合作为新主库。
2.5.2.3.打分
接下来就需要对剩余的从库进行打分,打分的目的是通过规则来选举出分数最高的从库作为新主库。
(1)第一轮打分:配置项slavepriority最高的从库得分最高
通过从库配置的优先级来进行打分,默认都是100,如果有一个从库的优先级最高,那么该从库就是新的主库了,不需要进行第二轮打分比拼。
如果当前打分都一样,那么进行第二轮打分。
(2)第二轮打分:和原主库数据同步进度最接近的从库得分最高
上篇文章提到过主从复制之间存在增量复制缓冲区(repl_backlog_buffer),可以用于当从库出现闪断恢复后将闪断前的数据恢复到从库的操作。
repl_backlog_buffer是一个环形缓冲区,并且有2个指针表示主库写的位置和从库读的位置分别是master_repl_offset和slave_repl_offset。
判断从库和原主库同步进度就是通过这两个指针的位置来判断,只有从库的slave_repl_offset最接近master_repl_offset位置,表示同步进度最接近,得分就最高,获得最高分数的从库就可以被选举作为新主库。 如果还是存在相同打分情况的从库,那么就会进入下一轮打分选举。
(3)第三轮打分:从库id最小的得分最高
第三轮应该属于兜底的选举场景,只有第一轮和第二轮选举时的分数都完全一样时,才会进入第三轮打分。
通过从库中的id来进行比较,id最小的从库得分最高,就会被选举为新主库。
2.5.3.哨兵集群判断实例下线
上文在”判断实例下线“中提到的主观下线和客观下线。主观下线是指某个哨兵通过ping的响应超时来判断主实例下线状态,而客观下线是指超过一定数量的哨兵实例都认为主库已下线,那么该主库就是客观下线状态。而客观下线一般存在哨兵集群中。
哨兵集群如何投票判断主库下线:
(1)哨兵集群中某一个实例判断主库为主观下线后,就会给其他哨兵实例发送ismasterdownbyaddr命令
(2)其他哨兵实例接收到命令后,会根据自己和主库的连接情况作出响应,投出赞成票或反对票。
(3)判断该主库为主观下线的哨兵实例如果获得了一定数值的赞成票,就会将该主库标记为客观下线。
这里赞成票的阈值可配,可通过sentinel.conf中的quorum配置数量决定。
(4)判断主库为客观下线的哨兵会向其他哨兵发送命令,表示由他自己来执行主从切换。该哨兵想成为执行主从切换的主哨兵,得由其他哨兵赞成才行,并且赞成数量得大于一半的哨兵数量。
(5)如果赞成数量小于一半的哨兵数量,就不会操作主从切换,哨兵集群会等待一段时间再重新选举主哨兵进行主从切换。
哨兵集群判断实例下线详细工作过程:
假设有三个哨兵S1、S2、S3。并且quorun配置数量为2。
(1)S1判断主库为主观下线状态,向其他哨兵发送ismasterdownbyaddr命令,并且其他哨兵也同意主库为主观下线,S1将主库判断为客观下线开始进行主从切换。
(2)同时,S2也判断主库为主观下线状态,并且也向其他哨兵发送ismasterdownbyaddr命令,其他哨兵也同意主库为主观下线,S2也将主库判断为客观下线开始进行主从切换。
(3)判断主库为客观下线的S1,想成为主哨兵,向其他哨兵发送命令,表示想成为主哨兵。
(4)判断主库为客观下线的S2,也想成为主哨兵,向其他哨兵发送命令,表示想成为主哨兵。
(5)S3收到了S1想成为主哨兵的命令,由于S3没有投过票,所以会返回同意。S2收到了S1想成为主哨兵的命令,由于S2自己投给了自己,所以会返回不同意。此时S1已经获得了2票同意票,赞成票大于一半的哨兵数量,可成为主哨兵,进行主从切换。
(6)后续S3收到了S2想成为主哨兵的命令,由于S3已经将票投给了S1,所以会返回不同意。S1也收到了S2想成为主哨兵的命令,由于S1自己投给了自己所以也返回不同意。此时S2只获得了1票同意票,赞成票小于一半的哨兵数量,不能成为主哨兵。
(7)最后,如果S1获得的同意票小于一半的哨兵数量,会导致S1和S2的选举结果不会产生主哨兵,哨兵集群会等待一段时间再重新选举。
2.5.4.哨兵集群的通信
如上图所示,就是哨兵集群的通信机制,主要是通过redis提供的pub/sub机制,即发布/订阅机制。
哨兵如果想要在主库上发布消息,需要和主库建立连接。从上图中可以看到主库中有一个订阅频道“sentinel:hello”的频道,不同的哨兵之间就是通过这个默认频道来进行发布/订阅通讯。
比如,上图中哨兵S2和哨兵S3是如何与S1建立网络连接的,假设S1的ip和端口分别是192.168.23.01和6379
(1)哨兵S1通过+sentinel sentinel 192.168.23.01:6379命令将自己的ip和端口发布到“sentinel:hello”频道中。
(2)哨兵S2和哨兵S3由于已经订阅了该频道,因此可以获取这个订阅消息(+sentinelsentinel 192.168.23.01:6379),获取到S1的ip和端口。
(3)哨兵S2和哨兵S3和哨兵S1建立网络连接。
(4)任何一个哨兵可以通过向主库发送INFO命令获得所有主库对应的从库信息,和从库进行连接并进行监
(5)其余的哨兵也是根据相同的INFO命令和从库进行连接。
(6)至此,哨兵之间组成了集群并进行通信。哨兵也和主从库之间建立了连接并进行监控。
2.5.5.哨兵和客户端的通信
哨兵不仅需要和主从库之间进行通信,还需要和客户端进行连接通信,因为如果主库宕机后通过哨兵选举出来的新主库的信息也需要推送给客户端。
哨兵和客户端的通信实际上也是基于发布/订阅机制来进行的。
比如,当哨兵把新主库选举出来后,客户端可以收到switchmaster事件(switchmaster ),来表示主库已经切换。客户端就可以使用该事件中的新ip和新端口信息来进行与新主库的通信。
3.总结
Redis 主从是构建redis哨兵和集群最基础的操作,是数据可靠的基础保证。
哨兵模式的存在,是redis高可用的保证,基于redis主从模式实现,即在redis主库发生故障时可通过选举和主从切换来保证redis服务不间断的可用性。