【Redis进阶】主从复制

1. 主从结构引入

在分布式系统中,涉及到一个严重问题:单点问题
即如果某个服务器程序只有一个节点(单台机器提供服务),就会出现以下两个问题:

  1. 可用性问题,如果这台机器挂了,意味着服务中断
  2. 并发性能问题,单台机器承受的并发量是有上限的

引入分布式系统,也就是为了能解决上述的单点问题,因此往往在redis中会部署多台redis服务器构建redis集群,此时就可以通过这个集群提供更高性能/更稳定的服务,主要的部署结构有以下几种:

  1. 主从模式
  2. 主从+哨兵模式
  3. 集群模式

主从模式:
在若干个redis节点中,有的是"主节点",有的是"从节点",假设有三台物理服务器,分别部署了一个redis-server进程,此时就可以把其中一个节点作为"主节点",另外两个节点作为"从节点",此时引入从节点后主节点上保存的数据就需要同步给从节点,后续主节点进行的数据修改也要同步给从节点

💡 注意:在redis主从模式中,不允许从节点修改数据!

配置主从模式后,就可以实现 “读写分离” ,即通过主节点来处理写操作,从节点处理读操作,这样的结构就可以完美的解决上述出现的"单点问题":

  1. 在可用性方面:如果有一个从节点挂了,那么问题不大,可以继续从其他从节点上读取数据,但是如果挂的是主节点,在当前结构来看还是有一定影响的,但是也可以通过哨兵机制来解决(此处先不介绍),总之相比于单点服务器程序提升了可用性
  2. 在性能方面:实际业务场景读操作频率 >> 写操作频率,因此配置一主多从节点,每个从节点都能分摊请求压力,引入了更多的硬件资源,因此性能也就提高了

2. 主从结构搭建

当前为了简化部署流程,我们使用单台物理服务器,启动多个redis-server进程来模拟多个物理服务器

💡 提示:此处需要保证redis-server进程启动的端口号各不相同!可以在启动时用选项配置或者在配置文件中进行配置

我们需要保存三份redis.conf配置,设置daemonize为yes以后台方式启动,port必须不同

# 绑定ip
bind=0.0.0.0
# 启动端口号
port=6379
# 关闭保护模式
protect-mode=no
# 以后台方式运行
daemonize=yes

image.png
但是当前几个redis服务还是各自为政的,我们还需要进一步通过以下方式配置成主从结构:

  1. 方式一:在配置文件中配置slaveof [masterIP] [masterPort]
  2. 方式二:在redis-server启动命令后使用--slaveof [masterIP] [masterPort]
  3. 方式三:在redis客户端中使用slaveof [masterIP] [masterPort]

此处我们希望能够使配置永久生效,因此选择在配置文件中修改,比如此处将6379端口进程作为主节点,6380和6181端口进程作为从节点,因此需要在从节点的配置文件中配置slaveof [127.0.0.1] [6379]并重启redis服务!

💡 注意:此处如果是使用redis-server方式启动进程,需要搭配kill -9杀死进程,但是如果是使用service redis-server start方式启动,使用kill -9杀死后仍会自动重启,此时必须要搭配service redis-server stop停止

image.png
此时下面几个进程就是redis主节点和从节点之间建立的TCP连接,后续同步机制就是通过这些TCP连接进行通信的,我们可以尝试登陆主节点使用info replication查看主从配置信息:
image.png

3. 主从复制过程

3.1 replid和offset字段含义

redis提供了psync命令用于完成数据同步(psync命令不需要手动执行,redis服务器会在建立好主从关系后,自动执行psync命令),比如从节点就会执行psync replicationid offset从主节点拉取数据
replicationid:当主节点启动时生成 / 从节点晋升成为主节点的时候生成(注意:就算是同一个主节点,每次启动生成的replicationid也是不重复的)我们可以通过info replication进行查看:
image.png

💡 注意:此处replid2在一般情况下是用不到的,但是可能存在以下场景:比如主节点A与从节点B之间配置主从关系,但是由于网络抖动导致B节点认为A主节点挂了,此时B自动晋升为主节点,给自己生成一个replid,同时还会记录之前的主节点信息保存在replid2上,后续如果主节点A恢复就可以手动配置恢复

offset:偏移量,用来记录从节点和主节点之间的数据同步进度,此处主节点和从节点都需要维护双方的偏移量,主节点会收到很多的修改命令,每一个命令都占据相应字节数,主节点就会把这些命令字节数累加作为偏移量,而从节点的偏移量就描述了从节点当前的同步进度,同时从节点每秒都需要上报给主节点当前的复制偏移量
此时replicationid和offset就构成了一组"数据集合",如果说某两台机器上的replid和offset都相同那就说明两者的数据是完全一致的!

3.2 主从数据复制

在redis中使用psync replicationid offset进行数据同步,但是数据同步有两种方式:1、全量同步,2、增量同步主要就是根据offset这个字段值进行区分:

  1. 如果是全量复制,就将offset值置为-1
  2. 如果offset值为正整数,则从当前偏移量开始进行部分复制

3.2.1 全量复制过程

  1. 从节点发送psync命令给主节点进行数据同步,由于是第一次通信不知道主节点replid因此发送psync ? -1
  2. 主节点根据命令判定为全量同步,返回FULLRESYNC响应
  3. 从节点将主节点的replid进行保存
  4. 主节点使用bgsave命令生成rdb持久化文件,同时在这期间接收到的修改命令保存到缓冲区
  5. 主节点生成完毕rdb文件后发送给从节点
  6. 发送完rdb文件后将缓冲区中的数据也以rdb文件格式追加写入,保证主从一致
  7. 从节点清空自身数据信息
  8. 重放rdb文件中的内容复制数据
  9. 如果还开启了AOF持久化功能,则会执行bgrewriteaof重写,得到最近的AOF文件

🍬 提示:主节点进行全量复制的过程也支持无硬盘模式(diskless),即主节点生成rdb文件的过程可以不保存在硬盘上,而是直接将数据进行网络传输(省去了多次硬盘IO操作)同理从节点加载数据也可以直接进行加载,但是网络传输的开销仍然很大,因此全量复制的开销也是比较大的!

runid和replicationid的区别:
在一个redis服务器上会出现replid和runid两个概念,但是这两个是不一样的,我们可以通过info replication查看replid,可以通过info server查看runid:

  • slave1:

    image.png
    image.png

  • slave2:

    image.png image.png

他们之间的区别概括如下:

  1. 在应用场景上:replid主要作用于主从复制的场景,runid则主要作用于哨兵模式中
  2. 在产生方式上:replid是在主从结构中由主节点启动的时候分配的(主从结构中replid相同),而runid则是每一个节点启动后系统分配的(每个节点均不同)

3.2.2 部分复制过程

在全量复制过程中,开销是比较大的,有些情况下从节点已经复制了主节点上的大部分数据,此时就需要"部分复制"了:比如说出现了网络抖动,此时主节点上最新的修改内容就无法及时同步给从节点,当从节点恢复之后就需要重新建立连接并进行部分同步
部分复制

  1. 当出现网络抖动时,主从节点之间超过repl-timeout时间,主节点就会认为从节点故障并中断连接
  2. 在这期间主节点依旧响应客户端命令,暂时将这些内容写入复制积压缓冲区(repl-backlog-buffer)中
  3. 当从节点恢复后就会重新建立与主节点之间的连接
  4. 从节点将之前保存的replicationidoffset作为psync参数发送给主节点,请求部分复制
  5. 主节点接收到psync请求后解析出部分复制,就会尝试在复制积压缓冲区查找合适数据,并响应continue给从节点
  6. 主节点将同步的数据发送给从节点,保证数据一致性

repl-backlog-buffer:
就是内存中类似于一个环形队列这样的数据结构,会保存最近的一些修改操作,但是总量毕竟还是有上限的,随着时间推移,会逐步删除最早的一些数据
image.png
当主节点接收到从节点的psync replid offset的时候就会先根据offset的值去repl-backlog-buffer查找有无这部分数据,如果有就会从该偏移量开始将后续的数据返回给从节点,如果没有那就只能进行全量复制了

3.2.3 实时复制过程

实时复制:描述的是主从已经完成数据同步之后,主节点这边不断地接收到数据修改操作,就需要实时同步给从节点
从节点和主节点之间会建立TCP的长连接,然后主节点就可以将自己收到的修改数据的请求发送给从节点,从节点再根据这些请求修改内存中的数据,同时为了实时复制能够处于可用状态,还需要借助 心跳包 机制:
主节点:默认每隔10s给从节点发送一个ping命令,从节点收到返回poing
从节点:默认每隔1s给主节点发送特定的请求,就会上报当前的节点同步数据的进度(offset)

4. 主从故障处理

当前配置的主从结构还需要考虑故障处理的问题:

  • 如果挂了的是从节点,那问题不大
  • 如果挂了的是主节点,此时就需要进行处理

当前主从断开连接有两种情况:

  1. 从节点和主节点之间断开连接:比如执行slaveof no one命令,这个时候从节点就会晋升成为主节点
  2. 主节点挂了:此时不会自动将从节点晋升成为主节点,于是引入了哨兵机制的概念(下次讲)
  • 24
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值