一、前言

本文讨论redis集群模式模式之一的主从复制

需要具备知识点:redis集群方案,cap理论知识

二、主从复制

在主从复制中,数据库分为两类,一类是主库(master),另一类是同步主库数据的从库(slave)。主库可以进行读写操作,当写操作导致数据变化时会自动同步到从库。而从库一般是只读的(特定情况也可以写,通过参数slave-read-only指定),并接受来自主库的数据,一个主库可拥有多个从库,而一个从库只能有一个主库。这样就使得redis的主从架构有了两种模式:一类是一主多从,二类是“链式主从”,由于redis主从强调最终一致性,所以属于cap中的AP模式。

三、搭建配置主从

时间仓促,有时间再补充,可以自己百度

主要命令:slaveof,config rewrite, info Replication 

四、复制过程

主从复制触发机制从库执行slaveof  masterip  port 那么执行流程如下:

1:建立链接阶段

  从库发送ping 命令

  主库回复pong 命令

2:数据复制阶段

version < 2.6 版本 从库发送sync,主库接收到命令执行bgsave,并同步rdb 文件给从库

version > 2.6 从库发送psync主库接收到命令根据实际情况考虑是全量复制还是批量复制

3:命令同步阶段,同步方式类似AOF

五、复制原理

       sync&psync1&psync2

  从redis2.6到4.0开发人员对其复制流程进行逐步的优化,以下是演进过程:

  • redis版本<=2.6<2.8,复制采用sync命令,无论是第一次主从复制还是断线重连进行复制都采用全量复制;
  • 2.8<=redis版本<4.0,复制采用psync,从redis2.8开始,redis复制从sync过渡到psync,这一特性主要添加了redis在【断线重新链接】时候可使用部分复制;
  • redis版本>=4.0,也采用psync,相比与2.8版本的psync【优化了增量复制】,这里我们称为psync2,2.8版本的psync称为psync1。

  以下将分别说明各个版本的复制演进

1:sync

  在redis2.6以及以前的版本,复制采用sync命令,当一个从库启动后,会向主库发送sync命令,主库收到sync命令后执行bgsave后台保存RDB快照(该过程在上一篇已经详细介绍),同时将保存快照的将快照保存期间接受的写命令保存到缓冲队列。当快照完成以后,主库将快照文件已经缓存的所有命令发送给从库,从库接受到快照文件并载入,再将执行主库发送的命令,也就是上面我们介绍的复制初始化阶段和数据同步阶段,其后就是命令增量同步,最终主库与从库保持数据一直。

  当从库在某些情况断线重连(如从库重启、由于网络原因主从连接超时),重复上述过程,进行数据同步。由此可见,redis2.6版本以及2.6以前复制过程全部采用全量复制。

  缺点:sync虽然解决了数据同步问题,但是在数据量比较大情况下,【从库断线】重连依然采用全量复制机制,无论是从数据恢复、宽带占用来说,sync所带来的问题还是很多的。于是redis从2.8开始,引入新的命令psync。

 

2:PSYNC

疑问点: 如何实现增量复制以及判断执行增量还是全量复制

实现关键点:runid, 挤压缓冲区, offset(主从节点都有复制偏移量标识)

# Replication
role:master
connected_slaves:1
slave0:ip=192.168.111.246,port=6379,state=online,offset=15124398162(从),lag=0
master_replid:a9d6f89598b20b7d6d3e9d3c8836b0d48a64fa4f
master_replid2:f404626696706f2bfdc3249ba9c451bc68a60b9a
master_repl_offset:15124398162(主)

 

replication backlog buffer(复制积压缓冲区通过repl-backlog-size 设置):

复制积压缓冲区是一个固定长度的FIFO队列,大小由配置参数repl-backlog-size指定,默认大小1MB。需要注意的是该缓冲区由master维护并且有且只有一个,所有slave共享此缓冲区,其作用在于备份最近主库发送给从库的数据。

  在主从命令传播阶段,主节点除了将写命令发送给从节点外,还会发送一份到复制积压缓冲区,作为写命令的备份。除了存储最近的写命令,复制积压缓冲区中还存储了每个字节相应的复制偏移量(如下图),由于复制积压缓冲区固定大小先进先出的队列,所以它总是保存的是最近redis执行的命令。

 【主节点根据偏移量把复制积压缓冲区里的数据发送给从节点,保证主从复制进入正常状态】’

run_id(服务器运行的唯一ID) 

  每个redis实例在启动时候,都会随机生成一个长度为40的唯一字符串来标识当前运行的redis节点,查看此id可通过命令info server查看。

  当主从复制在初次复制时,主节点将自己的runid发送给从节点,从节点将这个runid保存起来,当断线重连时,从节点会将这个runid发送给主节点。主节点根据runid判断能否进行部分复制:

  • 如果从节点保存的runid与主节点现在的runid相同,说明主从节点之前同步过,主节点会更具offset偏移量之后的数据判断是否执行部分复制,如果offset偏移量之后的数据仍然都在复制积压缓冲区里,则执行部分复制,否则执行全量复制;
  • 如果从节点保存的runid与主节点现在的runid不同,说明从节点在断线前同步的redis节点并不是当前的主节点,只能进行全量复制;   

缺点:由此可见psync也有不足之处,当从库重启以后runid发生变化,也就意味者从库还是会进行全量复制,而在实际的生产中进行从库的维护很多时候会进行重启,而正是有由于全量同步需要主库执行快照,以及数据传输会带不小的影响。因此在4.0版本,psync命令做了改进,以下说明。

3:PSYNC2

redis 4.0的改进,优化了runid 可变的问题,增加了master_replid 和master_replid2 ,这两个信息会被记录到持久化文件里,采用master_replid1  + offset 方案替换原来runid + offset  方案,实现重启也可增量复制的问题。

 

master_replid和master_repl_offset分为两组:

第一组:master_replid(为了区别,后面称为replid1)和master_repl_offset:如果redis是主实例,则表示为自己的replid和复制偏移量; 如果redis是从实例,则表示为自己主实例的replid1和同步主实例的复制偏移量。

第二组:master_replid2和second_repl_offset:无论主从,都表示自己上次主实例repid1和复制偏移量;用于兄弟实例或【级联复制,即该实例是主也是从的情况】,主库故障切换psync。

主从复制时,当slave节点上报master_replid串,与master节点的master_replid1或replid2有一个相等,就会进行复制。