Redis主从架构 | 黑马Redis高级篇

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

目录

一、搭建主从架构

1、为什么要搭建

2、准备实例和配置

3、启动

4、开启主从关系

二、 数据同步原理

1、全量同步

2、命令传播

3、增量同步

三、常见面试题


一、搭建主从架构

1、为什么要搭建

如果服务器发生了宕机由于数据恢复是需要点时间那么这个期间是无法服务新的请求的

如果这台服务器的硬盘出现了故障可能数据就都丢失了

要避免这种单点故障最好的办法是将数据备份到其他服务器上让这些服务器也可以对外提供服务这样即使有一台服务器出现了故障其他服务器依然可以继续提供服务。

单节点Redis的并发能力是有上限的要进一步提高Redis的并发能力就需要搭建主从集群实现读写分离

2、准备实例和配置

1创建目录

我们创建三个文件夹名字分别叫7001、7002、7003

# 进入/tmp目录
cd /tmp
# 创建目录
mkdir 7001 7002 7003

2拷贝配置文件到每个实例目录

然后将redis-6.2.4/redis.conf文件拷贝到三个目录中在/tmp目录执行下列命令

# 方式一逐个拷贝
cp redis-6.2.4/redis.conf 7001
cp redis-6.2.4/redis.conf 7002
cp redis-6.2.4/redis.conf 7003
 
# 方式二管道组合命令一键拷贝
echo 7001 7002 7003 | xargs -t -n 1 cp redis-6.2.4/redis.conf

3修改每个实例的端口、工作目录

修改每个文件夹内的配置文件将端口分别修改为7001、7002、7003将rdb文件保存位置都修改为自己所在目录在/tmp目录执行下列命令

sed -i -e 's/6379/7001/g' -e 's/dir .\//dir \/tmp\/7001\//g' 7001/redis.conf
sed -i -e 's/6379/7002/g' -e 's/dir .\//dir \/tmp\/7002\//g' 7002/redis.conf
sed -i -e 's/6379/7003/g' -e 's/dir .\//dir \/tmp\/7003\//g' 7003/redis.conf

3、启动

为了方便查看日志我们打开3个ssh窗口分别启动3个redis实例启动命令

# 第1个
redis-server 7001/redis.conf
# 第2个
redis-server 7002/redis.conf
# 第3个
redis-server 7003/redis.conf

4、开启主从关系

现在三个实例还没有任何关系要配置主从可以使用replicaof 或者slaveof5.0以前命令。

有临时和永久两种模式

修改配置文件永久生效

在redis.conf中添加一行配置slaveof <masterip> <masterport>

使用redis-cli客户端连接到redis服务执行slaveof命令重启后失效

slaveof <masterip> <masterport>

这里我们为了演示方便使用方式二。

通过redis-cli命令连接7002执行下面命令

# 连接 7002
redis-cli -p 7002
# 执行slaveof
slaveof 192.168.150.101 7001

通过redis-cli命令连接7003执行下面命令

# 连接 7003
redis-cli -p 7003
# 执行slaveof
slaveof 192.168.150.101 7001

然后连接 7001节点查看集群状态 

# 连接 7001
redis-cli -p 7001
# 查看状态
info replication

二、 数据同步原理

1、全量同步

全量同步只有第一次的时候才会发送

master如何判断slave是不是第一次来同步数据呢?

判断replid数据集的标记id一致则说明是同一数据集每一个master都有唯一的replidslave则会继承master节点的replid第一次来主会把id同步给从节点

offset偏移量随着记录在repl——baklog中的数据增多slave完成同步时也会记录当前同步的offset。如果slave的offset小于master的offset说明slave数据落后于master需要更新

因此slave做数据同步必须向master声明自己的replication id和offsetmaster才可以判断到底需要同步哪些数据

详细解析步骤

第一阶段建立链接、协商同步

执行了 replicaof 命令后从服务器就会给主服务器发送 psync 命令表示要进行数据同步。

psync 命令包含两个参数分别是主服务器的 runID 和复制进度 offset

  • runID每个 Redis 服务器在启动时都会自动生产一个随机的 ID 来唯一标识自己。当从服务器和主服务器第一次同步时因为不知道主服务器的 run ID所以将其设置为 "?"。
  • offset表示复制的进度第一次同步时其值为 -1。

主服务器收到 psync 命令后会用 FULLRESYNC 作为响应命令返回给对方。

并且这个响应命令会带上两个参数主服务器的 runID 和主服务器目前的复制进度 offset。从服务器收到响应后会记录这两个值。

FULLRESYNC 响应命令的意图是采用全量复制的方式也就是主服务器会把所有的数据都同步给从服务器。

所以第一阶段的工作时为了全量复制做准备。

那具体怎么全量同步呀呢我们可以往下看第二阶段。

第二阶段主服务器同步数据给从服务器

接着主服务器会执行 bgsave 命令来生成 RDB 文件然后把文件发送给从服务器。

从服务器收到 RDB 文件后会先清空当前的数据然后载入 RDB 文件。

这里有一点要注意主服务器生成 RDB 这个过程是不会阻塞主线程的因为 bgsave 命令是产生了一个子进程来做生成 RDB 文件的工作是异步工作的这样 Redis 依然可以正常处理命令。

但是这期间的写操作命令并没有记录到刚刚生成的 RDB 文件中这时主从服务器间的数据就不一致了。

那么为了保证主从服务器的数据一致性主服务器在下面这三个时间间隙中将收到的写操作命令写入到 replication buffer 缓冲区里

  • 主服务器生成 RDB 文件期间
  • 主服务器发送 RDB 文件给从服务器期间
  • 「从服务器」加载 RDB 文件期间

第三阶段主服务器发送新写操作命令给从服务器

在主服务器生成的 RDB 文件发送完从服务器收到 RDB 文件后丢弃所有旧数据将 RDB 数据载入到内存。完成 RDB 的载入后会回复一个确认消息给主服务器。

接着主服务器将 replication buffer 缓冲区里所记录的写操作命令发送给从服务器从服务器执行来自主服务器 replication buffer 缓冲区里发来的命令这时主从服务器的数据就一致了。

至此主从服务器的第一次同步的工作就完成了。

2、命令传播

主从服务器在完成第一次同步后双方之间就会维护一个 TCP 连接。

图片

后续主服务器可以通过这个连接继续将写操作命令传播给从服务器然后从服务器执行该命令使得与主服务器的数据库状态相同。

而且这个连接是长连接的目的是避免频繁的 TCP 连接和断开带来的性能开销。

上面的这个过程被称为基于长连接的命令传播通过这种方式来保证第一次同步后的主从服务器的数据一致性 

3、增量同步

一般从节点重启之后会做增量同步从节点突然断开了一段时间又不可能重新全量同步性能太低

repl_baklog大小是有上限的写满后会覆盖最早的数据如果slave断开太久导致未备份的数据被覆盖了则无法基于log增量同步只能再次全量同步

优化Redis主从

在master中配置repl-diskless-sync yes启动无磁盘赋值避免全量同步时的磁盘IO全量同步写入RDB文件时候是写入磁盘的效率太低了我们配置写入网络然后直接发给从提高全量同步性能

Redis单节点上的内存占用不要太大减少RDB导致的过多磁盘IO不用写太多提高全量同步性能角度

适当提高repl_baklog的大小发现slave宕机时尽快实现故障恢复尽可能避免全量同步

限制一个master的slave节点数量如果实在太多slave则可以采用主从从链式结构减少master压力

增量详细步骤

  • 从服务器在恢复网络后会发送 psync 命令给主服务器此时的 psync 命令里的 offset 参数不是 -1

  • 主服务器收到该命令后然后用 CONTINUE 响应命令告诉从服务器接下来采用增量复制的方式同步数据
  • 然后主服务将主从服务器断线期间所执行的写命令发送给从服务器然后从服务器执行这些命令。

那么关键的问题来了主服务器怎么知道要将哪些增量数据发送给从服务器呢

答案藏在这两个东西里

  • repl_backlog_buffer是一个「环形」缓冲区用于主从服务器断连后从中找到差异的数据
  • replication offset标记上面那个缓冲区的同步进度主从服务器都有各自的偏移量主服务器使用 master_repl_offset 来记录自己「」到的位置从服务器使用 slave_repl_offset 来记录自己「」到的位置。

那 repl_backlog_buffer 缓冲区是什么时候写入的呢

在主服务器进行命令传播时不仅会将写命令发送给从服务器还会将写命令写入到 repl_backlog_buffer 缓冲区里因此 这个缓冲区里会保存着最近传播的写命令。

网络断开后当从服务器重新连上主服务器时从服务器会通过 psync 命令将自己的复制偏移量 slave_repl_offset 发送给主服务器主服务器根据自己的 master_repl_offset 和 slave_repl_offset 之间的差距然后来决定对从服务器执行哪种同步操作

  • 如果判断出从服务器要读取的数据还在 repl_backlog_buffer 缓冲区里那么主服务器将采用增量同步的方式
  • 相反如果判断出从服务器要读取的数据已经不存在 repl_backlog_buffer 缓冲区里那么主服务器将采用全量同步的方式。

当主服务器在 repl_backlog_buffer 中找到主从服务器差异增量的数据后就会将增量的数据写入到 replication buffer 缓冲区这个缓冲区我们前面也提到过它是缓存将要传播给从服务器的命令。

图片

repl_backlog_buffer 缓行缓冲区的默认大小是 1M并且由于它是一个环形缓冲区所以当缓冲区写满后主服务器继续写入的话就会覆盖之前的数据。因此当主服务器的写入速度远超于从服务器的读取速度缓冲区的数据一下就会被覆盖。

那么在网络恢复时如果从服务器想读的数据已经被覆盖了主服务器就会采用全量同步这个方式比增量同步的性能损耗要大很多。

因此为了避免在网络恢复时主服务器频繁地使用全量同步的方式我们应该调整下 repl_backlog_buffer 缓冲区大小尽可能的大一些减少出现从服务器要读取的数据被覆盖的概率从而使得主服务器采用增量同步的方式。

 

三、常见面试题

Redis主从节点时长连接还是短连接

长连接

怎么判断 Redis 某个节点是否正常工作

Redis 判断节点是否正常工作基本都是通过互相的 ping-pong 心态检测机制如果有一半以上的节点去 ping 一个节点的时候没有 pong 回应集群就会认为这个节点挂掉了会断开与这个节点的连接。

Redis 主从节点发送的心态间隔是不一样的而且作用也有一点区别

  • Redis 主节点默认每隔 10 秒对从节点发送 ping 命令判断从节点的存活性和连接状态可通过参数repl-ping-slave-period控制发送频率。
  • Redis 从节点每隔 1 秒发送 replconf ack{offset} 命令给主节点上报自身当前的复制偏移量目的是为了
    • 实时监测主从节点网络状态
    • 上报自身复制偏移量 检查复制数据是否丢失 如果从节点数据丢失 再从主节点的复制缓冲区中拉取丢失数据。

主从复制架构中过期key如何处理

主节点处理了一个key或者通过淘汰算法淘汰了一个key这个时间主节点模拟一条del命令发送给从节点从节点收到该命令后就进行删除key的操作。

Redis 是同步复制还是异步复制

Redis 主节点每次收到写命令之后先写到内部的缓冲区然后异步发送给从节点。

主从复制中两个 Buffer(replication buffer 、repl backlog buffer)有什么区别

replication buffer 、repl backlog buffer 区别如下

  • 出现的阶段不一样
    • repl backlog buffer 是在增量复制阶段出现一个主节点只分配一个 repl backlog buffer
    • replication buffer 是在全量复制阶段和增量复制阶段都会出现主节点会给每个新连接的从节点分配一个 replication buffer
  • 这两个 Buffer 都有大小限制的当缓冲区满了之后发生的事情不一样
    • 当 repl backlog buffer 满了因为是环形结构会直接覆盖起始位置数据;
    • 当 replication buffer 满了会导致连接断开删除缓存从节点重新连接重新开始全量复制

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: redis