什么情况下需要搭建redis主从架构
官方表明redis单机的读速度是110000次/s,写速度是81000次/s。但随着客户端连接数的增加redis的性能会逐步递减,这个时候如果还需要支持10W+的qps就需要搭建redis集群了。
redis主从架构模型
redis有两种架构模型:一种是主从架构,一种是分布式架构。这里主要介绍一下redis主从架构,也就是一主多从,主机节点负责写的请求,从节点来分摊读的请求。
要注意的是这个架构写请求的瓶颈并不高,因为只有一个节点能接收写的操作,但可以不断增加slave节点来满足更多的读请求。
主从结构也可以呈现树状
从节点也可以从其他从节点来同步数据,这样可以减少主节点的压力。
搭建redis主从架构
我们先准备两个节点来搭建一主一从的架构,先在两台机器上分别安装好单机的redis,可以参照这篇文章redis单机安装最佳实践 。
搭建好后在其中一个节点执行这个命令,可以看到当前节点的信息。当前节点是master节点,它有0个slave
节点(在v5.x版本以前slave表示从节点,之后换成replication)。
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:0
min_slaves_good_slaves:0
master_replid:c5221e5a3720c4ae102f6fe2fecfaa96c653b4ce
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:40538
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:5242880
repl_backlog_first_byte_offset:1
repl_backlog_histlen:40538
我们开始更改redis.conf的配置。我在实例中使用了两台虚拟机分别是
- 192.168.20.198:6379(master),
- 192.168.20.199:6379(slave)。
在slave更改以下配置
# 配置master的ip和端口
replicaof 192.168.20.198 6379
# 设置访问master的密码
masterauth red123456
# 配置从不的过从中服务是否可用
# yes:主从复制中,从服务器可以响应客户端请求
# no:主从复制中,从服务器阻塞,有客户端请求时会返回:SYNC with master in progress
replica-serve-stale-data yes
# 配置从节点是否只读,只有在slave上配置可以生效
replica-read-only yes
# slave根据指定时间间隔向master发送ping请求
# 确保master和slave之间的心跳
repl-ping-replica-period 10
在master更改以下配置
# 复制缓冲区的大小
# 缓存区的作用就是用于slave离线后的数据存放,缓冲区越大,slave离线时间就可以越长
# 缓冲区只有在有slave连接的时候才会分片内存,没有slave一段时间后内存就会被释放出来,默认是1m
# 默认没有开启
repl-backlog-size 5mb
# master在没有slave多久后会将缓冲区释放,单位为秒
# 默认没有开启
repl-backlog-ttl 3600
# redis提供可以让master停止写入的方式,这里配置的1意思是只有健康的slave<2时master就无法写入
# master最少有多少个健康的slave存活才能写入数据
# 设置为0则关闭该功能,默认也是0
# 默认没有开启
min-replicas-to-write 1
# 延迟小于min-replicas-max-lag秒的slave才认为是健康的slave
# 默认没有开启
min-replicas-max-lag 10
更改完成后重启两个redis实例,再执行以下命令查看是否配置成功:
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:1
min_slaves_good_slaves:1
slave0:ip=192.168.20.199,port=6379,state=online,offset=40594,lag=1
master_replid:a95f80f29e0a599c48b4164df0c0d0aac2fc47dc
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:40594
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:5242880
repl_backlog_first_byte_offset:40539
repl_backlog_histlen:56
connected_slaves:1
表示有一个成功连接的slave节点,然后可以在master节点set值,在slave节点get看是否可以同步。
redis主从复制原理
Redis的主从复制过程大体上分3个阶段:建立连接、数据同步、命令传播
建立连接
- 建立连接,在slave节点配置文件中配置了
replicaof
的配置后,redis启动的时候就会执行replicaof
命令,创建一个与master节点的连接。 - 发送心跳,建立连接之后,slave节点会向master节点定时发送
ping
命令,确认master节点是否可用,如果可用则进行连接,否则重连。 - 身份认证,如果master节点设置了
requirepass
选项,那么slave服务器必须配置masterauth
密码与master一致才能通过验证 - 身份验证通过后master节点会把slave节点的信息保存下来
127.0.0.1:6379> info replication
# Replication
role:master
connected_slaves:2
min_slaves_good_slaves:2
slave0:ip=192.168.20.199,port=6379,state=online,offset=40594,lag=1
slave1:ip=192.168.20.200,port=6379,state=online,offset=40594,lag=1
数据同步
身份验证通过后master和slave就开始同步数据了,slave执行PSYNC
命令向master同步数据。
同步数据分为:完整重同步(full resynchronization)和部分重同步(partial resynchronization)
完整重同步
完整重同步流程大致是这样的:
- 当slave节点第一次连接到master节点的时候就会执行完整重同步,此时slave节点向master发送的同步命令是
psync ? -1
,master节点向slave节点返回FULLRESYNC <runid> <offset>
,slave节点会把<runid>
和<offset>
这两个值保存起来,用来做数据的增量更新。 - 同时master节点会执行
bgsave
命令,把当前redis里的所有内存数据写到rdb快照文件里。 - 写完rdb文件后master会把rdb文件同步给全部的slave节点,在发送的同时如果有新的请求命令写入master节点,master会把新的请求命令写入到buffer缓冲区。
要注意的是如果同步rdb文件的时间超过60秒就会同步失败,如果master节点数据较大,需要在master的redis配置文件里修改
repl-timeout
配置的默认值。
- slave节点接收到master的rdb文件后就会清除自己的全部数据,然后加载master的rdb文件,加载完毕后master节点就会把buffer缓冲区的数据再同步给slave节点。
- slave节点接收buffer缓冲区的数据后就会开始执行,并同时更新自己的
offset
值,以保证始终和master节点数据保持一致。
master节点和slave节点都会维护自己的
offset
(slave的offset是第一次full resynchronization获取到的),会随着接收到的命令请求递增。slave节点会每秒上报自己的offset给master,master会把所有slave节点的offset
保存起来,这样master节点就知道所有slave节点数据同步的情况。当slave节点掉线重新发送psync
命令后,master就会根据自己的offset
和slave的offset
做比较来判断是触发full resynchronization还是partial resynchronization。
部分重同步
全部重排序是一个很耗时的操作,当slave节点重新连接到master节点的时候master会尽可能只让slave同步增量的数据,只同步增量的数据就是部分重同步,大概的流程是这样的:
- 当slave节点断线从新连接到master节点的时候就会执行部分重同步(大部分情况下),slave会发送
psync <runid> <offset>
给master,master会判断<runid>
是否和自己的<runid>
一致,以及<offset>
值是否可以从缓冲区同步所有断线期间的数据,如果都满足条件就会向slave发送+COUNTINUE
命令开始部分重同步,否则就会就会返回FULLRESYNC <runid> <offset>
开始完整重同步。
runid
是master节点重启后随机生成的一个唯一标识,也就是说每次master节点重启都会导致slave节点全部重同步,如果想重启主节点服务而不改变run id
,使用redis-cli debug reload
命令。
buffer缓冲区是一个固定长度的队列,默认是1M,如果缓冲区写满了redis就会用新命令覆盖旧的命令,这会导致slave断线时间较长就没办法同步掉线期间全部数据而触发full resynchronization,可以更改redis的配置repl-backlog-size
的大小来允许slave可以断线更长的时间
- 接下来就和上面讲的全部重同步一样,接收master缓冲区的数据,接收master的新命令,维护自己的
<offset>
。
命令传播
当完成数据同步之后,master和slave节点的数据暂时达到一致状态,为了持续能够使master和slave节点的数据保持一致性,master会对slave节点执行命令传播操作,即每执行一个写命令就会向slave节点发送同样的写命令。
在命令传播阶段,slave节点会默认以每秒一次的频率向master服务器发送心跳检测
REPLCONF ACK <replication_offset>
replication_offset
是当前从服务器的复制偏移量,该命令的作用有三个
- 检测主slave服务器的网络连接状态
- 辅助实现min-slaves选项
- 检测命令丢失