工作需要,调研了一下redis的复制实现。在2.8版本之前和之后,复制方式有所不同。2.8之前的复制方式对于初次复制数据没有问题,对于断连接重新复制比较耗性能,因为都是全量复制。2.8之后对断线重连做了优化,采用差量复制。

旧版复制功能的实现

redis复制功能有同步命令传播两种。

同步操作将从服务器的数据库状态更新至主服务器当前的数据库状态;

命令传播用于在主服务器数据库状态改变,主从服务器数据状态不一致时,让主从服务器数据库状态重新回到一致状态。

同步

客户端向从服务器发送SLAVEOF命令,从服务器开始向主服务器请求同步数据,通过向主服务器发送SYNC命令完成同步过程,下面罗列SYNC命令的执行步骤:

1.从服务器向主服务器发送SYNC命令;

2.主服务器收到SYNC命令后执行BGSAVE命令,在后台生成一个rdb文件,并使用一个缓冲区记录从此刻开始执行的所有写操作命令;

3.主服务器的BGSAVE命令执行完毕,主服务器会将生成的rdb文件发送给从服务器,从服务器接收并加载这个rdb文件,将自己的数据库状态更新至主服务器执行BGSAVE命令时的数据库状态;

4.主服务器将记录在缓冲区里面的所有写命令发送给从服务器,从服务器执行这些写命令,将自己的数据库状态更新至主服务器数据库当前所处的状态。

下表展示一个主从同步的例子:
时间 主服务器 从服务器
t0 服务器启动 服务器启动
t1 执行SET K1 V1  
t2 执行SET K2 V2  
t3 执行SET K3 V3  
t4   向主服务器发送SYNC命令

t5

接收从服务器发来的SYNC命令,执行BGSAVE命令,创建包含K1,K2,K3的rdb文件,并用缓冲区记录接下来执行的所有写操作  
t6 执行SET K4 V4,并将这个命令保存到缓冲区  
t7 执行SET K5 K5,并将这个命令保存到缓冲区  
t8 BGSAVE命令执行完毕,向从服务器发送rdb文件  

t9

  接收并加载rdb文件,使数据库更新到主服务器执行BGSAVE命令时的数据库状态
t10 向从服务器发送缓冲区保存的写命令SET K4 V4和SET K5 V5  
t11   接收并执行主服务器发来的两个SET命令
t12 同步完成,现在注册服务器状态一致 同步完成,现在注册服务器状态一致

命令传播

同步操作完成之后,主从服务器数据库状态达到一致,后续的状态就靠命令传播保持主从服务器状态一致。主服务器会将自己执行的写操作命令,原封不动地发送给从服务器,从服务器执行相同的写操作之后,主从服务器数据库状态重新达到一致。

旧版本复制功能的缺陷

在redis2.8之前,从服务器对主服务器的复制分为以下两种情况:

1.初次复制:从服务器没有复制过任何主服务器,或者从服务器要复制的主服务器和上次复制的主服务器不同;

2.断线重连重新复制:处于命令传播的主从服务器因为网络原因而中断了复制,但从服务器通过自动重连重新连接上了主服务器,并重新从头开始全量复制主服务器。

对于初次复制而言,旧版复制功能可以较好的完成任务,但对于断线重连的情况,虽然可以让主从服务器重新回到一致,但是效率确是比较低下的。

SYNC操作是一个非常耗费资源的操作

每次执行SYNC命令时,主从服务器将执行以下动作:

1.主服务器执行BGSAVE生成rdb文件,此操作耗费主服务器大量的cpu,内存和磁盘io资源。

2.主服务器要将自己生成的rdb文件发送给从服务器,此操作会消耗主从服务器大量的网络资源,并对主服务器响应命令请求的时间产生影响。

3.接收到rdb文件的从服务器需要载入rdb文件,并且载入期间,从服务器因阻塞而无法处理命令请求。

新版复制功能的实现

为了解决旧版断线重连重复复制的低效问题,2.8版本开始使用PSYNC代替SYNC命令执行同步操作。PSYNC命令包括完整同步和部分同步:

1.完整同步用于处理初次复制的情况:PSYNC执行步骤和SYNC的执行步骤基本一样;

2.部分同步用于处理断线重连的复制情况:断线重连时,如果条件允许,主服务器可以将主从服务器断连接期间执行的写命令发送给从服务器,从服务器更具这些写命令更新数据库状态至主服务器当前的状态。

下表展示PSYNC命令解决断线重连的复制情况的例子:

时间 主服务器 从服务器
t1 主从服务器完成同步 主从服务器完成同步
t2 执行并传播SET K2 V2 执行主服务器传播来的SET K2 V2
t3 执行并传播SET K3 V3 执行主服务器传播来的SET K3 V3
   
t20 执行并传播SET K20 V20 执行并传播SET K20 V20
t21 主从服务器断开连接 主从服务器断开连接
t22 执行SET K22 V22 断线,尝试重连
t23 执行SET K23 V23 断线,尝试重连
t24 主从服务器重新建立连接 主从服务器重新建立连接
t25   向主服务器发生PSYNC命令
t26 向从服务器返回+CONTINUE回复,标识执行部分同步  
t27   接收主服务回复的+CONTINUE,准备部分同步
t28 向从服务器发送SET K22 V22和SET K23 V23两个命令  
t29   接收并执行主服务器传来的两个命令
t30 主从服务器再次完成同步,状态一致 主从服务器再次完成同步,状态一致

由此可见,PSYNC在执行部分同步的时候比执行SYNC命令所需要的资源少很多,速度也加快了。执行SYNC命令需要生成,传送,载入整个rdb文件,而PSYNC的部分同步只需将差量的写命令发送给从服务器便可。

部分重同步的实现

部分重同步由以下三部分组成:

1.主服务器的复制偏移量和从服务器的复制偏移量;

2.主服务器的复制积压缓冲区;

3.服务运行的id。

复制偏移量

执行复制的双方分别维护一个复制偏移量:

1.主服务器每次向从服务器传播N个字节的数据时,就将自己的复制偏移量加N;

2.从服务器每次收到主服务器传来的N个字节的数据时,就将自己的复制偏移量加N。

如果主从服务器数据库处于一致状态时,那么主从服务器的复制偏移量总是一致的,但是如果主从服务器偏移量不相同,说明主从服务器状态不一致。

复制积压缓冲区

复制积压缓冲区是由主服务器维护的一个固定长度的先进先出队列,默认大小为1MB。

当主服务器进行命令传播时,他会做两个操作,1.将命令发送给从服务器,2.将命令写入到复制积压缓冲区,因此复制积压缓冲区里会保存一部分最近传播的写命令,并且会为队列中的每个字节记录相应的复制偏移量,如下表所示。

偏移量 10086 10087 10088 10089 10090 10091 10092 10093 10094 10095 10096
字节值 ‘*’ 3 ‘\r’ ‘\n’ ‘$’ 3 ‘\r’ ‘\n’ ‘S’ ‘E’ ‘T’

当主从服务器重连成功后,从服务器会通过PSYNC命令将自己的复制偏移量offset发送给主服务器,主服务器根据这个偏移量决定对从服务器执行何种操作:

1.如果offset偏移量之后的数据仍然存在于复制积压缓冲区里面,那么主服务器会对从服务器进行部分同步操作;

2.如果offset偏移量之后的数据不在复制积压缓存区里面,那么主服务器对从服务器进行完整同步操作。

服务器运行id

每个redis服务器,无论主从服务,都会有自己的运行id。运行id在启动时生成,由40个随机的十六进制字符组成。

当从服务器对主服务器进行初次复制时,主服务器将自己运行的id传送给从服务器,从服务器将这个id保存。

当从服务器断线并重连上上一个主服务器时,从服务器将保存的id发送给主服务器:

如果从服务器保存的运行id和当前连接的主服务运行id相同,说明从服务器断线之前复制的就是这台主服务器,主服务器可以继续吃、执行部分同步操作;

如果从服务器保存的运行id和当前连接的主服务器运行id不一致,那么说明从服务器断线之前连接的主服务器不是当前连接的主服务器民主服务器对从服务器执行完整同步操作。

总结

新redis的复制机制在老的复制机制上加了个部分同步,解决断线重连时的全量复制数据的低性能情况。部分同步的机制依赖于复制偏移量,复制积压缓冲区,服务运行id。

复制偏移量是为了让从服务器知晓下次该从何处开始进行部分重同步;

复制积压缓冲区是为了主服务器找到上次复制的点,从该点开始给从服务器复制数据。如果找不到这个点,就要执行完整同步过程了;

服务运行id主要是为保证重连的主服务器是否为上次连接的主服务器,如果是才能执行部分重同步,否则就只能进行完整同步了。

本文参考黄健宏著的 redis设计与实现

redis高可用 - 主从复制的更多相关文章

  1. redis高可用、redis集群、redis缓存优化

    今日内容概要 redis高可用 redis集群 redis缓存优化 内容详细 1.redis高可用 # 主从复制存在的问题: 1 主从复制,主节点发生故障,需要做故障转移,可以手动转移:让其中一个sl ...

  2. Redis高可用之主从复制实践(四)

    0.Redis目录结构 1)Redis介绍及部署在CentOS7上(一) 2)Redis指令与数据结构(二) 3)Redis客户端连接以及持久化数据(三) 4)Redis高可用之主从复制实践(四) 5 ...

  3. Redis高可用(持久化、主从复制、哨兵、集群)

    Redis高可用(持久化.主从复制.哨兵.集群) 目录 Redis高可用(持久化.主从复制.哨兵.集群) 一.Redis高可用 1. Redis高可用概述 2. Redis高可用策略 二.Redis持 ...

  4. Redis高可用之主从复制原理演进分析

    Redis高可用之主从复制原理演进分析 在很久之前写过一篇 Redis 主从复制原理的简略分析,基本是一个笔记类文章. 一.什么是主从复制 1.1 什么是主从复制 主从复制,从名字可以看出,至少需要 ...

  5. Redis 高可用集群

    Redis 高可用集群 Redis 的集群主从模型是一种高可用的集群架构.本章主要内容有:高可用集群的搭建,Jedis连接集群,新增集群节点,删除集群节点,其他配置补充说明. 高可用集群搭建 集群(c ...

  6. Redis高可用方案----Redis主从+Sentinel+Haproxy

    安装环境 这里使用三台服务器,每台服务器上开启一个redis-server和redis-sentinel服务,redis-server端口为6379,redis-sentinel的端口为26379. ...

  7. 9.Redis高可用-哨兵

    9.Redis高可用-哨兵9.1 基本概念9.1.1 主从复制的问题9.1.2 高可用9.1.3 Redis Sentinel的高可用性9.2 安装和部署9.2.1 部署拓扑结构9.2.2 部署Red ...

  8. Redis高可用详解:持久化技术及方案选择

    文章摘自:https://www.cnblogs.com/kismetv/p/9137897.html 前言 在上一篇文章中,介绍了Redis的内存模型,从这篇文章开始,将依次介绍Redis高可用相关 ...

  9. Redis高可用集群-哨兵模式(Redis-Sentinel)搭建配置教程【Windows环境】

    No cross,no crown . 不经历风雨,怎么见彩虹. Redis哨兵模式,用现在流行的话可以说就是一个"哨兵机器人",给"哨兵机器人"进行相应的配置 ...

随机推荐

  1. RK3288 USB触摸屏无法使用,需要添加PID和VID

    RK3288  Android5.1 现象:USB 接口触摸屏插到板子上,触摸屏无法使用,有可能出现更奇葩的,同一套代码,有的板子可以用,有的板子不能用. 1.打开串口调试,插上触摸屏,读取触摸屏的 ...

  2. 移动端固定头部和固定左边第一列的实现方案(Vue中实现demo)

    最近移动端做一份报表,需要左右滚动时,固定左边部分:上下滚动时,固定头部部分. 代码在Vue中简单实现 主要思路是: a.左边部分滚动,实时修改右边部分的滚动条高度 b.头部和内容部分都设置固定高度, ...

  3. JVM内存管理之垃圾搜集器参数精解

    本文是GC相关的最后一篇,这次LZ只是罗列一下hotspot JVM中垃圾搜集器相关的重点参数,以及各个参数的解释.废话不多说,这就开始. 垃圾搜集器文章传送门 JVM内存管理------JAVA语言 ...

  4. 数据结构与算法JavaScript描述——链表

    1.数组的缺点 数组不总是组织数据的最佳数据结构,原因如下. 在很多编程语言中,数组的长度是固定的,所以当数组已被数据填满时,再要加入新的元素就会非常困难. 在数组中,添加和删除元素也很麻烦,因为需要 ...

  5. POJ 2991 Crane(线段树)

    Crane Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 7687   Accepted: 2075   Special J ...

  6. 字符串的问题(substr,find用法)

    链接:https://www.nowcoder.com/acm/contest/77/C来源:牛客网 字符串的问题 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 262144K,其他 ...

  7. APP推送通知相关实现

      关于推送通知,iOS推送主要是通过服务端来实现的,相关过程可以参考下面两篇文章:   http://cshbbrain.iteye.com/blog/1859810   http://zxs198 ...

  8. 我为什么一直不愿意用bootstrap

    做前端有2年多的时间了,知道bootstrap已经很久了. 第一次了解bootstrap是1年前,公司的一次培训中. 当时感到非常的愤怒,因为对框架的了解不够深入产生了这样的一个想法: 怎么会有这种框 ...

  9. 十七.jQuery源码解析之入口方法Sizzle(1)

    函数Sizzle(selector,context,results,seed)用于查找与选择器表达式selector匹配的元素集合.该函数是选择器引擎的入口. 函数Sizzle执行的6个关键步骤如下: ...

  10. 浅谈PHP面向对象编程(六、自动加载及魔术方法)

    6.0 自动加载及魔术方法  6.1 自动加载 在PHP开发过程中,如果希望从外部引入一个class.通常会使用incluae和requre方法把定义这个class的文件包含进来.但是,在大型的开发项 ...