Redis学习总结(四)--Redis主从配置

在分布式系统架构设计中高可用是必须考虑的因素之一。高可用通常是指,通过设计减少系统不能提供服务的时间。而单点是系统高可用的最大的败笔,如果单点出现问题的话,那么整个服务就不能使用了,所以应该尽量在系统设计的过程中避免单点。对于 redis 服务也是这样,今天我们就来实现 Redis 的高可用的基础 --> 主从配置。

主从概念

有多台 Redis 服务器(至少两台或以上),其中一台是主服务器(master) 负责写指令的操作,其他都是从服务器(slave)负责读指令的操作。

主从服务器之间会进行数据的同步(即:主服务器会将数据同步到从服务器去),保证数据是一致的。从服务器将读指令操作分流减少服务器压力,而且其中一台从服务器出现错误,不影响其他从服务器的使用。

如果是主服务器出现问题,那么就需要实现故障转移(手动/自动)将其中一台从服务器提升为主服务器,其他从服务器都从这个新的主服务器同步数据。

从上面这段话中我们可以知道 Redis 实现高可用的两个功能点:

  • 主从复制
  • 故障转移

主从复制

主从复制流程

1)从服务器连接主服务器,发送SYNC命令;
2)主服务器接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命令;
3)主服务器BGSAVE执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令;
4)从服务器收到快照文件后丢弃所有旧数据(如果有的话),载入收到的快照;
5)主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;
6)从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令;
7) 主服务器接收到的每一个写指令都向从服务器发送,从服务器接收并执行收到的写命令。

注:主从服务器刚连接的时候,会进行全量同步;全同步结束后,进行增量同步。当然,如果有需要,slave 在任何时候都可以发起全量同步。redis 策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。

主从复制实现方式

  • slaveof 命令
  • 配置文件

主从复制实践

前期准备

1)复制两份 redis-6379.conf 配置文件,分别命名为 redis-7000.confredis-7001.conf
2) 编辑 redis-7000.confredis-7001.conf 文件将端口分别修改为 7000 和7001并将日志文件格式以端口命名,以 redis-6379.conf 为例:

# 允许远程访问
## bind 127.0.0.1
protected-mode no
# 服务端口号
port 6379
# 以守护进程启动
daemonize yes
# 日志文件名称
logfile "redis-6379.log"
# 启用日志文件
syslog-enabled yes

3)分别启动 6379,7000 和 7001 Redis 服务

主从复制实践之 slaveof 命令

我们将会让 6379 成为主服务器,70007001 为从服务器。

1)进入 7000 并将其设置为 6379 的从服务器

[root@VM_0_15_centos redis4]# ./redis-cli -p 7000
127.0.0.1:7000> SLAVEOF 127.0.0.1 6379
OK
127.0.0.1:7000> exit

2)查看 6379 信息

[root@VM_0_15_centos redis4]# ./redis-cli -p 6379 info replication

输出如下:

# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=7000,state=online,offset=210,lag=0
master_replid:9fe7d7ca84fe33cf8e916be1ee3a1b0423675ef8
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:210
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:210

2)查看 7000 信息

[root@VM_0_15_centos redis4]# ./redis-cli -p 7000 info replication

输出如下:

# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:2
master_sync_in_progress:0
slave_repl_offset:336
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:9fe7d7ca84fe33cf8e916be1ee3a1b0423675ef8
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:336
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:336

可以看到 6379rolemaster 表示为主服务器,而 7000roleslave
表示为从服务器,证明我们刚刚的配置成功了。

3)我们尝试在 6379 设置一些值

[root@VM_0_15_centos redis4]# ./redis-cli -p 6379 
127.0.0.1:6379> set name MarkLogZhu
OK
127.0.0.1:6379> set age 18
OK

然后进 7000 看看是不是会将数据同步过来(执行此操作前,先将两边的数据都清空)

[root@VM_0_15_centos redis4]# ./redis-cli -p 7000
127.0.0.1:7000> get name
"MarkLogZhu"
127.0.0.1:7000> get age
"18"

可以看到数据同步过来了,我们试试在 7000 上写入下数据

127.0.0.1:7000> set name1 123
(error) READONLY You can't write against a read only slave.

可以看到从服务器上不能执行写指令操作的。

  1. 启动 7001 并将其也设置为 6379的从服务器,看看是否也会同步数据过来
127.0.0.1:7001> SLAVEOF 127.0.0.1 6379
OK
127.0.0.1:7001> get name
"MarkLogZhu"
127.0.0.1:7001> get age
"18"

可以看到会将 6379 之前的数据也同步过来。

  1. 7000 上将主从绑定取消
[root@VM_0_15_centos redis4]# ./redis-cli -p 7000 
127.0.0.1:7000> slaveof no one
OK

6)查看主服务器信息

[root@VM_0_15_centos redis4]# ./redis-cli -p 6379 info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=7001,state=online,offset=70,lag=0
master_replid:b3a6488a9667dd3f80c9549146ed012a4ec1d465
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:70
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:70
[root@VM_0_15_centos redis4]# 

可以看到就一个从服务器,端口号为 7001,要注意的是 7000 上的数据还是存在的不会主动清空。

主从复制实践之配置文件

1)将 Redis 服务都关闭

[root@VM_0_15_centos redis4]# ps -ef |grep redis
root      4220     1  0 15:10 ?        00:00:00 ./redis-server *:6379
root      4238     1  0 15:11 ?        00:00:00 ./redis-server *:7000
root      4325     1  0 15:13 ?        00:00:00 ./redis-server *:7001
root      4830  1579  0 15:18 pts/0    00:00:00 grep --color=auto redis
[root@VM_0_15_centos redis4]# ./redis-cli -p 6379 shutdown
[root@VM_0_15_centos redis4]# ./redis-cli -p 7000 shutdown
[root@VM_0_15_centos redis4]# ./redis-cli -p 7001 shutdown
  1. 编辑 redis-7000.conf 增加如下内容:
slaveof 127.0.0.1 6379
  1. 编辑 redis-7001.conf 增加如下内容:
slaveof 127.0.0.1 6379
  1. 依次启动服务
[root@VM_0_15_centos redis4]# ./redis-server redis-6379.conf 
[root@VM_0_15_centos redis4]# ./redis-server redis-7000.conf 
[root@VM_0_15_centos redis4]# ./redis-server redis-7001.conf 
  1. 查看主从状态
[root@VM_0_15_centos redis4]# ./redis-cli -p 6379 info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=7000,state=online,offset=84,lag=1
slave1:ip=127.0.0.1,port=7001,state=online,offset=84,lag=0
master_replid:645cc6d0869b23998c1265af1d556e671330d2f0
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:84
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:84

可以看到服务一启动就已经自动配置为一主二从了,在实际项目中通过配置文件的形式更常见。

主从故障

什么是主从故障

主从故障就是主服务器出现问题,导致无法执行写命令。我们来演示下主服务器故障看看

  1. 启动三个服务
[root@VM_0_15_centos redis4]# ./redis-server redis-6379.conf 
[root@VM_0_15_centos redis4]# ./redis-server redis-7000.conf 
[root@VM_0_15_centos redis4]# ./redis-server redis-7001.conf 
  1. 将主服务器进程关闭(模拟突然出现问题)
[root@VM_0_15_centos redis4]# ps -ef |grep redis
root      5538     1  0 15:25 ?        00:00:00 ./redis-server *:6379
root      5545     1  0 15:25 ?        00:00:00 ./redis-server *:7000
root      5551     1  0 15:25 ?        00:00:00 ./redis-server *:7001
root      6179  1579  0 15:34 pts/0    00:00:00 grep --color=auto redis
[root@VM_0_15_centos redis4]# kill -9 5538 

3)查看主从状态

[root@VM_0_15_centos redis4]# ./redis-cli -p 7000 info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:down
master_last_io_seconds_ago:-1
master_sync_in_progress:0
slave_repl_offset:891
master_link_down_since_seconds:216
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:645cc6d0869b23998c1265af1d556e671330d2f0
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:891
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:891

可以看到 Redis 是无法自动切换的,只能通过人为执行命令解除主从配置,并将其中一个从服务器提升为主服务器。除了人为来操作之外 Redis 提供了一个 sentinel(哨兵)来实现故障自动转移。

Sentinel(哨兵)

什么是 sentinel

sentinel 就相当于是一个哨兵,当 Redis 主服务器出现故障的时候,代替我们人为的将其中一个服务器提升为主服务器,当主服务器修复故障后自动降格为从服务器加入进来。

多个哨兵节点(至少三个,并且是奇数)会使用 Raft算法(选举算法)实现选举机制,选出一个哨兵节点当作领导者来完成转移和通知。

Sentinel 是如何实现故障转移的?

Sentinel 做到故障转移是基于三个定时任务的执行:

  1. 每隔 10s 每个 sentinel 会对 master 节点和 slave 节点执行 info 命令
作用就是发现 slave 节点,并且确认主从关系,因为 redis-Sentinel 节点启动的时候是知道master节点的,只是没有配置相应的 slave 节点的信息
  1. 每隔两秒,sentinel 都会通过 master节点内部的 channel 来交换信息(基于发布订阅)
作用是通过master节点的频道来交互每个Sentinel对master节点的判断信息
  1. 每隔一秒每个 sentinel 对其他的redis节点(master,slave,sentinel)执行ping操作
对于 master 来说若超过 30s 内没有回复,就对该 master进行主观下线并询问其他的 Sentinel节点是否可以客观下线

客观下线和主观下线

  • 主观下线:每个Sentinel节点对Redis节点失败的“偏见”
  • 客观下线:所有Sentinel节点对Redis节点失败达成共识

在进行领导者选举之后进行故障转移,这个过程由成为 leader 的 Sentinel 的来完成。

Sentinel 的选举流程(Raft算法)

1)每个做出主观下线操作的 Sentinel 节点向其他 Sentinel 节点发送命令,要求成为领导者。
2)收到命令的 Sentinel 节点默认同意第一个收到的请求,其他拒绝
3)当其中一个 Sentinel 节点获取到的票数一次超过 Sentinel 集合半数并且超过配置里的 quorum,那么它将成为领导者。
4)如果此过程中存在多个 Sentinel 节点成为领导者,那么将等待一段时间后重新进行选举。

故障转移

1)从 slave 节点中选出一个 “合适的” 节点作为新的 master 节点
2)对选中的 slave 节点执行 slaveof no one 命令,让其成为 master 节点
3)对剩余的 slave 节点发送命令,让他们成为新的 master 节点的slave 节点,复制规则和 parallel-syncs 参数有关。
4)将原来的 master 节点配置为 slave,并保持对其的 "关注",当它恢复后令它去复制新的 master 节点。

“合适的” slave 节点

1.选择 slave-priority(slave节点优先级)最高的 slave 节点,如果存在则返回,否则继续。
2.选择复制偏移量最大的 slave 节点(复制的最完整的),如果存在则返回,否则继续。
3.选择 runId 最小的 slave 节点。

实践

1)编辑 sentinel 配置文件

vim sentinel-26379.conf

内容如下:

# 配置 sentinel 端口号
port 26379
# 以守护进程启动
daemonize yes
# 绑定只在本地使用
bind 127.0.0.1
# 日志文件名称
logfile "sentinel_26379.log"
# 日志文件存放地址
dir "./"
# 监控 master 名字叫做 mymaster,地址是 127.0.0.1 端口号是 6379,1 表示有几个 sentinel 认为该 master 出现故障,触发主备切换动作
sentinel monitor mymaster 127.0.0.1 6379 1
# 3000 毫秒没有响应就判断出现故障
sentinel down-after-milliseconds mymaster 30000
# 主备切换时,多少个从服务器同步更新数据,数值越小越好
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
  1. 启动 sentinel
[root@VM_0_15_centos redis4]# ./redis-sentinel sentinel-26379.conf

3)将主服务器进程关闭(模拟突然出现问题)

[root@VM_0_15_centos redis4]# kill -9 9149
[root@VM_0_15_centos redis4]# ps -ef |grep redis
root      5550     1  0 16:17 ?        00:00:00 ./redis-server *:7000
root      5551     1  0 15:25 ?        00:00:03 ./redis-server *:7001
root     13044     1  0 16:14 ?        00:00:00 ./redis-sentinel 127.0.0.1:26379 [sentinel]
root     13306  1579  0 16:17 pts/0    00:00:00 grep --color=auto redis
  1. 查看 7000 主从信息
[root@VM_0_15_centos redis4]# ./redis-cli -p 7000 info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:7001
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:17931
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:0219097153045d031f7bcfdccebd52b336e542e5
master_replid2:66aa7374642058a6bb26c9c0258e3c8b2fc7d760
master_repl_offset:17931
second_repl_offset:12757
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:17931
[root@VM_0_15_centos redis4]# 

可以看到现在主服务器是端口 7001

5)将 6379 端口服务重新启动,然后查看 7001 主从状态

[root@VM_0_15_centos redis4]# ./redis-cli -p 7001 info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=7000,state=online,offset=29364,lag=1
slave1:ip=127.0.0.1,port=6379,state=online,offset=29364,lag=0
master_replid:0219097153045d031f7bcfdccebd52b336e542e5
master_replid2:66aa7374642058a6bb26c9c0258e3c8b2fc7d760
master_repl_offset:29364
second_repl_offset:12757
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset

可以看到 6379 端口也变成了一个从服务器添加进来了。要注意的是这个时候配置文件已经被 sentinel 修改了,就算你重启服务,也是按目前的主从来设置,而不是重新以 6379 为主服务器,我们可以来看看:

[root@VM_0_15_centos redis4]# ./redis-cli -p 6379 shutdown
[root@VM_0_15_centos redis4]# ./redis-cli -p 7000 shutdown
[root@VM_0_15_centos redis4]# ./redis-cli -p 7001 shutdown
[root@VM_0_15_centos redis4]# ./redis-server redis-6379.conf 
[root@VM_0_15_centos redis4]# ./redis-server redis-7000.conf 
[root@VM_0_15_centos redis4]# ./redis-server redis-7001.conf 
[root@VM_0_15_centos redis4]# ./redis-cli -p 6379 info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:7001
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:835
slave_priority:100
slave_read_only:1
connected_slaves:0
master_replid:f3ed896873d5a9024a8139dac59b86381e53ad08
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:835
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:835

重启服务后我们可以看到 6379 还是充当从服务器的角色。

原文地址:https://www.cnblogs.com/markLogZhu/p/11418884.html