缓存服务 Redis 集群
五、Redis 主从复制
1、Redis 复制特性
-
使用异步复制。
-
一个主服务器可以有多个从服务器。
-
从服务器也可以有自己的从服务器。
-
复制功能不会阻塞主服务器。
-
可以通过复制功能来让主服务器免于执行持久化操作,由从服务器去执行持久化操作即可。

-
关闭主服务器持久化时,复制功能的数据安全
-
当配置Redis复制功能时,强烈建议打开主服务器的持久化功能。 否则的话,由于延迟等问题,部署的服务应该要避免自动拉起。
为了帮助理解主服务器关闭持久化时自动拉起的危险性,参考一下以下会导致主从服务器数据全部丢失的例子:
-
假设节点A为主服务器,并且关闭了持久化。 并且节点B和节点C从节点A复制数据
-
节点A崩溃,然后由自动拉起服务重启了节点A. 由于节点A的持久化被关闭了,所以重启之后没有任何数据
-
节点B和节点C将从节点A复制数据,但是A的数据是空的, 于是就把自身保存的数据副本删除。
在关闭主服务器上的持久化,并同时开启自动拉起进程的情况下,即便使用 Sentinel 来实现 Redis 的高可用性,也是非常危险的。 因为主服务器可能拉起得非常快,以至于Sentinel 在配置的心跳时间间隔内没有检测到主服务器已被重启,然后还是会执行上面的数据丢失的流程。
无论何时,数据安全都是极其重要的,所以应该禁止主服务器关闭持久化的同时自动拉起。
2、Redis 主从复制原理
1、Redis 主从同步方式
redis 主从同步有两种方式(或者所两个阶段):全同步和部分同步。
主从刚刚连接的时候,进行全同步;全同步结束后,进行部分同步。当然,如果有需要,slave 在任何时候都可以发起全同步。
redis 策略是,无论如何,首先会尝试进行部分同步,如不成功,要求从机进行全同步,并启动 BGSAVE......BGSAVE 结束后,传输 RDB 文件;如果成功,允许从机进行部分同步,并传输积压空间中的数据。
下面这幅图,总结了主从同步的机制:

2、Redis 主从复制原理
-
从服务器向主服务器发送 SYNC 命令。
-
接到 SYNC 命令的主服务器会调用BGSAVE 命令,创建一个 RDB 文件,并使用缓冲区记录接下来执行的所有写命令。
-
当主服务器执行完 BGSAVE 命令时,它会向从服务器发送 RDB 文件,而从服务器则会接收并载入这个文件。
-
主服务器将缓冲区储存的所有写命令发送给从服务器执行。
3、Redis 命令的传播
在主从服务器完成同步之后,主服务器每执行一个写命令,它都会将被执行的写命令发送给从服务器执行,这个操作被称为"命令传播"(command propagate)。

命令传播是一个持续的过程:只要复制仍在继续,命令传播就会一直进行,使得主从服务器的状态可以一直保持一致。
3、Redis 复制中的 SYNC 与 PSYNC
在 Redis 2.8 版本之前, 断线之后重连的从服务器总要执行一次完整重同步(full resynchronization)操作。
从 Redis 2.8 开始,Redis 使用 PSYNC 命令代替 SYNC 命令。PSYNC 比起 SYNC 的最大改进在于 PSYNC 实现了部分重同步(partial resync)特性:在主从服务器断线并且重新连接的时候,只要条件允许,PSYNC 可以让主服务器只向从服务器同步断线期间缺失的数据,而不用重新向从服务器同步整个数据库。
4、Redis 复制的一致性问题

在读写分离环境下,客户端向主服务器发送写命令 SET n 10086,主服务器在执行这个写命令之后,向客户端返回回复,并将这个写命令传播给从服务器。
接到回复的客户端继续向从服务器发送读命令 GET n ,并且因为网络状态的原因,客户端的 GET命令比主服务器传播的SET 命令更快到达了从服务器。
因为从服务器键 n 的值还未被更新,所以客户端在从服务器读取到的将是一个错误(过期)的 n值。
5、Redis 复制安全性提升
主服务器只在有至少 N 个从服务器的情况下,才执行写操作从 Redis 2.8 开始, 为了保证数据的安全性, 可以通过配置, 让主服务器只在有至少 N 个当前已连接从服务器的情况下, 才执行写命令。
不过, 因为 Redis 使用异步复制, 所以主服务器发送的写数据并不一定会被从服务器接收到, 因此, 数据丢失的可能性仍然是存在的。
通过以下两个参数保证数据的安全:
min-slaves-to-write <number of slaves>
min-slaves-max-lag <number of seconds>
6、Redis 主从复制实践
1、Redis 多实例的配置
准备两个或两个以上redis实例
[root@xulei.com redis]# tree
.
├── 6380
│ ├── redis.conf
│ └── redis-server
├── 6381
│ ├── redis.conf
│ └── redis-server
├── 6382
│ ├── redis.conf
│ └── redis-server
├── install-redis.sh
└── start-redis.sh
2、Redis 配置文件示例
[root@xulei.com redis]# vim 6380/redis.conf
bind 127.0.0.1 10.0.0.186
port 6380
daemonize yes
pidfile /var/run/redis_6380.pid
loglevel notice
logfile "/var/log/redis_6380.log"
dbfilename dump.rdb
dir /application/redis/6380/
appendonly no
appendfilename "appendonly.aof"
appendfsync everysec
slowlog-log-slower-than 10000
slowlog-max-len 128
protected-mode no
3、启动 Redis 实例
[root@xulei.com redis]# ./6380/redis-server ./6380/redis.conf
[root@xulei.com redis]# ./6381/redis-server ./6381/redis.conf
[root@xulei.com redis]# ./6382/redis-server ./6382/redis.conf
4、Redis 复制环境说明
主节点:6380
从节点:6381、6382
5、Redis 开启主从(在6381 6382实例中执行)
[root@localhost redis]# redis-cli -h 192.168.152.161 -p 6380
192.168.152.161:6380> slaveof 192.168.152.161 6381
OK
6、Redis 主从复制完成
7、Redis 主从复制管理
-
主从复制状态监控:info replication
-
主从切换: slaveof no one
六、Redis HA 实践(Redis Sentinel)
官方文档:https://redis.io/topics/sentinel
Redis-Sentinel 是 Redis 官方推荐的高可用性(HA)解决方案,当用Redis做Master-slave的高可用方案时,假如master宕机了,Redis本身(包括它的很多客户端)都没有实现自动进行主备切换,而Redis-sentinel本身也是一个独立运行的进程,它能监控多个master-slave集群,发现master宕机后能进行自动切换。

Sentinel 是一个监视器,它可以根据被监视实例的身份和状态来判断应该执行何种动作。
1、Redis Sentinel 功能
1、监控(Monitoring)
Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。
2、提醒(Notification)
当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
3、自动故障迁移(Automatic failover)
当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。
2、Redis Sentinel 服务器连接
1、发现并连接主服务器
Sentinel 通过用户给定的配置文件来发现主服务器。

Sentinel 会与被监视的主服务器创建
两个网络连接:
-
命令连接用于向主服务器发送命令。
-
订阅连接用于订阅指定的频道,从而发现
-
监视同一主服务器的其他 Sentinel。
2、发现并连接从服务器
Sentinel 通过向主服务器发送 INFO 命令来自动获得所有从服务器的地址。
跟主服务器一样,Sentinel 会与每个被发现的从服务器创建命令连接和订阅连接。

3、发现其他 Sentinel
Sentinel 会通过命令连接向被监视的主从服务器发送 "HELLO" 信息,该消息包含Sentinel 的 IP、端口号、ID 等内容,以此来向其他 Sentinel 宣告自己的存在。与此同时Sentinel 会通过订阅连接接收其他 Sentinel 的"HELLO" 信息,以此来发现监视同一个主服务器的其他 Sentinel 。

sentinel1 通过发送HELLO 信息来让sentinel2 和 sentinel3发现自己,其他两个sentinel 也会进行类似的操作。
4、多个 Sentienl 之间的链接
Sentinel 之间只会互相创建命令连接,用于进行通信。因为已经有主从服务器作为发送和接收 HELLO 信息的中介,所以 Sentinel 之间不会创建订阅连接。

3、Redis Sentinel 检测实例的状态
Sentinel 使用 PING 命令来检测实例的状态:如果实例在指定的时间内没有返回回复,或者返回错误的回复,那么该实例会被 Sentinel 判断为下线。

Redis 的 Sentinel 中关于下线(down)有两个不同的概念:
-
主观下线(Subjectively Down, 简称 SDOWN)指的是单个Sentinel 实例对服务器做出的下线判断。
-
客观下线(Objectively Down, 简称 ODOWN)指的是多个Sentinel 实例在对同一个服务器做出 SDOWN 判断, 并且通过SENTINEL is-master-down-by-addr 命令互相交流之后, 得出的服务器下线判断。 (一个 Sentinel 可以通过向另一个Sentinel 发送 SENTINEL is-master-down-by-addr 命令来询问对方是否认为给定的服务器已下线。)
如果一个服务器没有在 master-down-after-milliseconds 选项所指定的时间内, 对向它发送 PING 命令的 Sentinel 返回一个有效回复(valid reply), 那么 Sentinel 就会将这个服务器标记为主观下线。
4、Redis Sentinel 故障转移 FAILOVER
一次故障转移操作由以下步骤组成:
-
发现主服务器已经进入客观下线状态。
-
基于Raft leader election 协议 , 进行投票选举
-
如果当选失败,那么在设定的故障迁移超时时间的两倍之后,重新尝试当选。 如果当选成功, 那么执行以下步骤。
-
选出一个从服务器,并将它升级为主服务器。
-
向被选中的从服务器发送 SLAVEOF NO ONE 命令,让它转变为主服务器。
-
通过发布与订阅功能, 将更新后的配置传播给所有其他 Sentinel ,其他 Sentinel 对它们自己的配置进行更新。
-
向已下线主服务器的从服务器发送 SLAVEOF 命令,让它们去复制新的主服务器。
-
当所有从服务器都已经开始复制新的主服务器时, leader Sentinel 终止这次故障迁移操作。
5、Redis Sentinel 配置
1、创建程序目录
[root@xulei.com ~]# cd /application
[root@xulei.com application]# mkdir 26380
[root@xulei.com application]# cp /usr/local/redis-5.0.5/src/redis-sentinel ./26380/
[root@xulei.com application]# cd 26380
2、编辑配置文件
[root@xulei.com 26380]# vim sentinel.conf
port 26380
dir "/tmp"
daemonize yes
sentinel monitor mymaster 127.0.0.1 6380 2
sentinel down-after-milliseconds mymaster 60000
sentinel config-epoch mymaster 0
3、启动 sentinel
[root@xulei.com 26380]# ./redis-sentinel ./sentinel.conf
4、配置文件说明
# 指定监控master
sentinel monitor mymaster 127.0.0.1 6370 2
# {2表示多少个 sentinel 同意}
# 安全信息
sentinel auth-pass mymaster root
# 超过15000毫秒后认为主机宕机
sentinel down-after-milliseconds mymaster 15000
# 当主从切换多久后认为主从切换失败
sentinel failover-timeout mymaster 900000
# 这两个配置后面的数量主从机需要一样,epoch为master的版本
sentinel leader-epoch mymaster 1
sentinel config-epoch mymaster 1
6、Redis Sentinel 命令操作
| 命令 | 描述 |
|---|---|
| PING | 返回 PONG |
| SENTINEL masters | 列出所有被监视的主服务器 |
| SENTINEL slaves | |
| SENTINEL get-master-addr-by-name | 返回给定名字的主服务器的 IP 地址和端口号。 |
| SENTINEL reset | 重置所有名字和给定模式 pattern 相匹配的主服务器 |
| SENTINEL failover | 当主服务器失效时, 在不询问其他 Sentinel 意见的情况下,强制开始一次自动故障迁移。 |
7、Redis Sentinel 发布与订阅信息
客户端可以将 Sentinel 看作是一个只提供了订阅功能的 Redis 服务器: 你不可以使用 PUBLISH 命令向这个服务器发送信息, 但你可以用 SUBSCRIBE 命令或者 PSUBSCRIBE 命令, 通过订阅给定的频道来获取相应的事件提醒。
一个频道能够接收和这个频道的名字相同的事件。 比如说, 名为 +sdown 的频道就可以接收所有实例进入主观下线(SDOWN)状态的事件。
通过执行 PSUBSCRIBE * 命令可以接收所有事件信息。
以下列出的是客户端可以通过订阅来获得的频道和信息的格式:
第一个英文单词是频道/事件的名字,其余的是数据的格式。
注意, 当格式中包含 instance details 字样时, 表示频道所返回的信息中包
含了以下用于识别目标实例的内容:
<instance-type> <name> <ip> <port> @ <master-name> <master-ip> <master-port>
@ 字符之后的内容用于指定主服务器, 这些内容是可选的, 它们仅在 @ 字符之前的内容指定的实例不是主服务器时使用。
8、Redis Sentinel(哨兵)实现 Redis 的高可用性
1、环境准备
| 机器名称 | IP配置 | 服务角色 | 备注 |
|---|---|---|---|
| redis-master | 192.168.30.107 | redis主 | 开启 sentinel |
| redis-slave1 | 192.168.30.7 | redis从 | 开启 sentinel |
| redis-slave2 | 192.168.30.2 | redis从 | 开启 sentinel |
2、按照上实验实现主从
(1)打开所有机器上的redis 服务
[root@redis-master ~]# systemctl start redis
(2)在主上登录查询主从关系,确实主从已经实现
[root@redis-master ~]# redis-cli -h 192.168.30.107 -p 6379
192.168.30.107:6379> info Replication
3、所有节点配置 Redis Sentinel 哨兵
1、Redis Sentinel 配置
[root@redis-master ~]# vim /etc/redis-sentinel.conf
port 26379 #默认监听端口26379
#sentinel announce-ip 1.2.3.4 #监听地址,注释默认是0.0.0.0
sentinel monitor mymaster 192.168.30.107 6379 1 #指定主redis和投票裁决的机器数,即至少有1个sentinel节点同时判定主节点故障时,才认为其真的故障
下面保存默认就行,根据自己的需求修改
sentinel down-after-milliseconds mymaster 5000 #如果联系不到节点5000毫秒,我们就认为此节点下线。
sentinel failover-timeout mymaster 60000 #设定转移主节点的目标节点的超时时长。
sentinel auth-pass <master-name> <password> #如果redis节点启用了auth,此处也要设置password。
sentinel parallel-syncs <master-name> <numslaves> #指在failover过程中,能够被sentinel并行配置的从节点的数量;
注意:只需指定主机器的IP,等sentinel 服务开启,它能自己查询到主上的从redis;并能完成自己的操作
2、指定 master 选举优先级
-
vim /etc/redis.conf 根据自己的需求设置优先级
-
slave-priority 100 复制集群中,主节点故障时,sentinel应用场景中的主节点选举时使用的优先级;数字越小优先级越高 ,但0表示不参与选举;当优先级一样时,随机选举。
3、开启 Redis Sentienl 服务
1、开启 Redis Sentienl 服务
shell
[root@redis-master ~]# systemctl start redis-sentinel # 在主上开启服务,打开了26379端口
2、开启服务后,/etc/redis-sentinel.conf 配置文件会生成从redis 的信息
未完待续