redis主从架构及哨兵模式
redis主从原理分析
主从出现原因
-
高并发 -
官方数据表示redis的读数据在11万/s左右,写速度在8万/s左右 -
redis尽量少写多读,符合缓存的适用要求 -
通过主从架构来进行读写分离 -
HA -
具备有一个以上的从库就会对节点进行备份
主从同步过程中一定要开启持久化
-
如果master出现宕机内存丢失,从库也会删除数据 -
如果master进行功能性重启,内存数据就是,也会同步给slave节点
主从复制原理
-
当slave第一次连接时,会触发全量同步,如果已经连接过,只会同步新增数据 -
全量备份分为落盘和不落盘两种形式,默认是落盘
# 不落盘复制配置 yes不落盘,no落盘
repl-diskless-sync no
# 等待其他slave连接的一个时间周期,单位是秒
repl-diskless-sync-delay 5
-
支持断点续传 -
如果从库过多会导致占用带宽过大,所以从库不易过多
主从结构除了一对多,还可以是树形结构,只不过树形结构用的比较少
主从设置
# 可以通过命令看一下主从信息,v5.x版本前从是用slave表示,之后换成replication
# master和slave节点都可以查看
info replication
# 修改slave的redis.conf
replicaof 192.168.1.100 6379 #master的ip,master的端口
# 在slave配置上添加
masterauth icoding #主机的访问密码
# yes 主从复制中,从服务器可以响应客户端请求
# no 主从复制中,从服务器将阻塞所有请求,有客户端请求时返回“SYNC with master in progress”;
# 默认开启yes,在slave上配置
replica-serve-stale-data yes
# slave节点只允许read 默认就是 yes
# 这个配置只对slave节点才生效,对master节点没作用
# 默认开启并配置为yes,在slave上配置
replica-read-only yes
# slave根据指定的时间间隔向master发送ping请求
# 时间间隔可以通过 repl-ping-replica-period 来设置,默认10秒
# 默认没有开启,在slave的配置上打开
repl-ping-replica-period 10
# 复制连接超时时间。
# master和slave都有超时时间的设置。
# master检测到slave上次发送的时间超过repl-timeout,即认为slave离线,清除该slave信息。
# slave检测到上次和master交互的时间超过repl-timeout,则认为master离线。
# 需要注意的是repl-timeout需要设置一个比repl-ping-slave-period更大的值,不然会经常检测到超时。
# 默认没有开启,在slave的配置上打开
repl-timeout 60
# 是否禁止复制tcp链接的tcp nodelay参数,可传递yes或者no。
# 默认是no,即使用tcp nodelay,允许小包的发送。对于延时敏感型,同时数据传输量比较小的应用,开启TCP_NODELAY选项无疑是一个正确的选择
# 如果master设置了yes来禁止tcp nodelay设置,在把数据复制给slave的时候,会减少包的数量和更小的网络带宽。
# 但是这也可能带来数据的延迟。
# 默认我们推荐更小的延迟,但是在数据量传输很大的场景下,建议选择yes。
# 默认开启并配置为no,在master上添加
repl-disable-tcp-nodelay no
# 复制缓冲区大小,这是一个环形复制缓冲区,用来保存最新复制的命令。
# 这样在slave离线的时候,不需要完全复制master的数据,如果可以执行部分同步,只需要把缓冲区的部分数据复制给slave,就能恢复正常复制状态。
# 缓冲区的大小越大,slave离线的时间可以更长,复制缓冲区只有在有slave连接的时候才分配内存。
# 没有slave的一段时间,内存会被释放出来,默认1m。
# 默认没有开启,在master上配置
repl-backlog-size 5mb
# master没有slave一段时间会释放复制缓冲区的内存,repl-backlog-ttl用来设置该时间长度。
# 单位为秒。
# 默认没有开启,在master上配置
repl-backlog-ttl 3600
# 当master不可用,Sentinel会根据slave的优先级选举一个master。
# 最低的优先级的slave,当选master。
# 而配置成0,永远不会被选举。
# 注意:要实现Sentinel自动选举,至少需要2台slave。
# 默认开启,在slave上配置
replica-priority 100
# redis提供了可以让master停止写入的方式,如果配置了min-slaves-to-write,健康的slave的个数小于N,mater就禁止写入。
# master最少得有多少个健康的slave存活才能执行写命令。
# 这个配置虽然不能保证N个slave都一定能接收到master的写操作,但是能避免没有足够健康的slave的时候,master不能写入来避免数据丢失。
# 设置为0是关闭该功能,默认也是0。
# 默认没有开启,在master上配置
min-replicas-to-write 2
# 延迟小于min-replicas-max-lag秒的slave才认为是健康的slave。
# 默认没有开启,在master上配置
min-replicas-max-lag 10
哨兵机制及实现原理
redis的提供的sentinel哨兵机制,是为了应对master节点挂掉之后,保证redis的可用性及实现继续写的操作,哨兵可以自动将slave升级成master节点。
什么是哨兵?
redis的sentinel机制是用于管理多个redis服务器的,sentinel会执行以下四个任务
-
服务监控:负责监控redis master和slave进程是否正常工作 -
消息通知:master如果挂掉了,哨兵可以根据配置的脚本来调用发送通知 -
故障转移:master几点挂掉,sentinel会从slave中选举一个节点为master,会让剩下的slave节点 follow到新的master节点上,并从新master节点复制数据 -
配置中心:如果故障发生转移,sentinel可以通知客户端,新的master地址端口
哨兵配置
# redis的安装根目录下,有个sentinel.conf
# 部署三个哨兵节点,同时监控一组redis服务(只有一个节点其实也可以,但风险)
# bind 127.0.0.1 192.168.1.1
# 测试的时候放开访问保护
protected-mode no
port 26379 #默认是26379
daemonize yes
pidfile /var/run/redis-sentinel-26379.pid #pid 集群要区分开
logfile /usr/local/redis-6379/sentinel/redis-sentinel.log #日志,非常重要
dir /usr/local/redis-6379/sentinel #工作空间
# sentinel监控的核心配置
# 最后一个2,quorum,>=2个哨兵主观认为master下线了,master才会被客观下线,才会选一个slave成为master
sentinel monitor icoding-master 127.0.0.1 6379 2
# master访问密码
sentinel auth-pass icoding-master icoding
# sentinel主观认为master挂几秒以上才会触发切换
sentinel down-after-milliseconds icoding-master 3000
# 所有slave同步新master的并行同步数量,如果是1就一个一个同步,在同步过程中slave节点是阻塞的,同步完了才会放开
sentinel parallel-syncs icoding-master 1
# 同一个master节点failover之间的时间间隔
sentinel failover-timeout icoding-master 180000
启动哨兵
redis-sentinel sentinel.conf
# 如果要搭建集群,只需要将刚刚配置的sentinel.conf复制到其他节点即可
哨兵部署的约定
-
哨兵集群至少3个节点 -
最好三个节点在不同的物理机器上 -
一组哨兵最好只监控一组主从
查看哨兵信息
redis-cli -p 26379 #通过哨兵的端口进入
sentinel master cqp-master
sentinel slaves cqp-master
sentinel sentinels cqp-master #查看哨兵信息
主观宕机和客观宕机
-
S_DOWN(subjectively down)主观宕机
-
一个哨兵根据配置的主观宕机秒数,认为一个master宕机了就是主观宕机 -
sentinel down-after-milliseconds icoding-master 3000 就是这个配置 -
哨兵ping主机,然后返回超过上面设置的时间就会认为是主观宕机 -
O_DOWN(objectively down)客观宕机
-
如果quorum数量的哨兵认为一个master宕机了,就是客观宕机
哨兵集群是如何自动发现
创建哨兵集群的时候并没有手动设置之间的关联
通过pub/sub机制来实现的,每个哨兵都会pub一个__sentinel__:hello并通过sub来获取和感知有多少个同组redis监控的哨兵
并且信息里会携带host ip runid,并让其他哨兵感知到
选举算法
会考虑的slave选举的信息
-
和master断开的时长 -
slave的优先级:replica-priority 100 -
复制的offset位移程度 -
run_id
如果slave和master连接断开超过:down-after-milliseconds icoding-master这个配置的10倍以上绝对不考虑
slave的选举排序顺序
1、按照slave优先级进行排序,replica priority越低,优先级越高
2、如果replica priority级别相同,看offset越靠后(复制的内容多少),优先级越高
3、如果上面两个条件都一样,这个时候看run_id ,run_id字符排序越靠前越优先
先选一个执行主从的sentinel,这个sentinel在根据主从选举算法进行选举
quorum和majority
每次哨兵要做主从切换,首先需要quorum数据的哨兵认为O_DOWN,然后选举一个哨兵来做主从切换,这个哨兵要得到majority数量哨兵的授权,才能正式切换
如果quorum<majority,如果5个哨兵,maj就是3个,qu就是2个
如果quorum>=majority,必须quorum数量的哨兵都授权
configuration epoch
监控的版本号,这个时候所有的哨兵都会记录一套当前的主从关系,这个关系的变更,切换版本号
一个执行哨兵完成了主从切换后,就会通过pub/sub机制来传播给其他哨兵
哨兵故障转移实现
关闭master节点服务
实现方式:依赖于config命令,我们会改成imconfig
# 可以通过这个命令来修改成无redis修改后的config命令
# SENTINEL rename-command mymaster CONFIG IMCONFIG
实现切换机制
1. 通过config命令修改redis.conf的主从关系
修改自己的sentinel.conf的主机监控命令
2. 在sentinel.conf配置的最下端写入当前主从的版本,供所有哨兵进行使用
sentinel leader-epoch icoding-master 1
sentinel known-replica icoding-master 127.0.0.1 7002
sentinel known-replica icoding-master 127.0.0.1 6379
sentinel known-sentinel icoding-master 127.0.0.1 26379 ce3608694909e996b280e8672750b2bd5522945f
sentinel known-sentinel icoding-master 127.0.0.1 26382 a2f203e003ce891a08580104dc2b49a4f6ae187e
sentinel current-epoch 1
哨兵故障通知机制
# sentinel notification-script <master-name> <script-path>
# 当我们master出现sdown和odown都会触发
sentinel notification-script icoding-master /usr/local/redis/nofity.sh
# sentinel client-reconfig-script mymaster /var/redis/reconfig.sh
# 会带有一些参数:主从切换新旧地址的参数
# <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>
sentinel client-reconfig-script icoding-master /usr/local/redis/configer.sh
哨兵转移中问题
-
异步复制的时候,master的数据还没有复制给slave,这个时候哨兵切换slave成为master后就会丢失这些数据(新master会把他的数据同步到其他slave:清空其他slave进行同步)
-
脑裂:哨兵的网络和master断开了,但我们master还在运行,这个时候客户端写入旧master的时候就会丢失
old-master<-->client 是连接的,这个时候old-master就没有slave,可以通过以下两个配置来缓解
new-master---slave1/slave2
-
min-replicas-to-write 2 -
min-replicas-max-lag 10
程序如何确保访问有效
需要我们在springboot配置中连接哨兵port
spring:
redis:
host: 127.0.0.1
password: icoding
sentinel:
master: icoding-master
nodes: 39.99.199.5:26379,39.99.199.5:26381,39.99.199.5:26382