Redis复制

1.概述

Redis使用复制功能在主从服务器之间实现数据的同步。
Redis的复制功能分为两个版本:

  • 2.8版本之前的旧版复制功能
  • 2.8版本之后的新版复制功能

这两个版本的主要区别在与新版的复制功能支持部分重同步,可以有效的提升断线后重连的数据同步效率。

2.旧版复制功能

Redis复制功能都是分为两个步骤:

  • 同步
    将主服务器数据同步至从服务器
  • 命令传播
    数据同步完成后,当主服务器数据状态发生改变时(发生写命令等),将命令传播至从服务器从而使得主从服务器状态一致

2.1 同步

同步过程:

时间 主服务器 从服务器
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 v5
T8 BGSAVE命令执行完毕,向从服务器发送RDB文件
T9 接收并载入主服务器发来的RDB文件,获得k1、k2、k3三个键
T10 由缓冲区向从服务器发送命令set k4 v4、set k5 v5
T11 接收并执行主服务器发送来的两个set命令,获得键k4、k5
T2 同步完成,主从服务器数据一致,都包含k1、k2、k3、k4、k5 同步完成,主从服务器数据一致,都包含k1、k2、k3、k4、k5

2.2 命令传播

命令传播是在主从服务器数据完成同步之后,主服务器数据发生变化时,会将相应的命令传播至从服务器使得主从数据完成一致。

2.3 旧版复制功能的缺陷

旧版复制功能在从服务器首次进行数据复制时,没有任何问题,但是当从服务器发生断线进行重连时,有可能从服务器只是缺失了很小的一部分数据,但是进行复制时却要复制整个主服务器全部的数据,从而大大的浪费了资源。
缺陷具体示例如下:

时间 主服务器 从服务器
T0 主从服务器完成同步 主从服务器完成同步
T1 执行 set k1 v1
T2 执行 set k2 v2
。。。 。。。 。。。
T10001 执行并传播 set k10001 v10001 执行主服务器传来的set k10001 v10001
T10002 执行并传播 set k10002 v10002 执行主服务器传来的set k10002 v10002
T10003 主从服务器连接断开 主从服务器连接断开
T10004 执行 set k10003 v10003 断线,尝试重连主服务器
T10005 执行 set k10004 v10004 断线,尝试重连主服务器
T10006 执行 set k10005 v10005 断线,尝试重连主服务器
T10007 主从服务器重新连接 主从服务器重新连接
T10008 向主服务器发送SYNC命令
T10009 接收到从服务发送的SYNC命令,执行BGSAVE命令,创建包含键k1~k10005的RDB文件,并使用缓冲区记录接下来执行的所有写命令
T10010 BGSAVE命令执行完毕,向从服务器发送RDB文件
T10011 接收并载入主服务器发来的RDB文件,获得k1~k10005键
T10012 BGSAVE命令期间没有任何写命令,因此跳过缓冲区发送命令
T10013 同步完成,主从服务器数据一致 同步完成,主从服务器数据一致

如上示例,本来只需要进行set k10003 v10003、set k10004 v10004、set k10005 v10005三个命令的同步,使用旧版复制功能却需要进行k1~k10005整个RDB文件的恢复,带来了相当大的资源浪费。

3 新版复制功能

为了解决旧版复制功能中存在的断线重连导致的资源浪费的问题,Redis从2.8版本开始使用PSYNC代替SYNC执行进行复制时的同步操作。
PSYNC具有完整重同步、部分重同步两种模式:

  • 完整重同步:处理初次复制的情况,与SYNC执行步骤基本一样
  • 部分重同步:用于处理断线后重新复制的情况。当从服务器断线后,如果条件允许,主服务器可以将主从服务器断开期间执行的写命令发送给从服务器,从服务器只要执行这些命令即可完成数据同步。

PSYNC具体示例如下:

时间 主服务器 从服务器
T0 主从服务器完成同步 主从服务器完成同步
T1 执行 set k1 v1
T2 执行 set k2 v2
。。。 。。。 。。。
T10001 执行并传播 set k10001 v10001 执行主服务器传来的set k10001 v10001
T10002 执行并传播 set k10002 v10002 执行主服务器传来的set k10002 v10002
T10003 主从服务器连接断开 主从服务器连接断开
T10004 执行 set k10003 v10003 断线,尝试重连主服务器
T10005 执行 set k10004 v10004 断线,尝试重连主服务器
T10006 执行 set k10005 v10005 断线,尝试重连主服务器
T10007 主从服务器重新连接 主从服务器重新连接
T10008 向主服务器发送PSYNC命令
T10009 向从服务器发送+CONTINUE回复,表示执行部分重同步
T10010 接收+CONTINUE回复,准备执行部分重同步
T10011 向从服务发送set k10003 v10003、set k10004 v10004、set k10005 v10005三个命令
T10012 执行主服务器发送来的三个命令
T10013 同步完成,主从服务器数据一致 同步完成,主从服务器数据一致

3.1 部分重同步

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

  • 主服务的复制偏移量 和 从服务器的复制偏移量
  • 主服务器的复制积压缓冲区
  • 服务器的运行ID

3.1.1 复制偏移量

执行复制的主服务器、从服务器会分别维护一个复制偏移量。
这个偏移量记录了执行命令的字节数。主服务器每次向从服务器传播N个字节时就会将自己的复制偏移量+N,从服务在接收到主服务器传送来的N个字节的命令时,就将自己的复制偏移量+N。


复制偏移量变化

3.1.2 复制积压缓冲区

复制积压缓冲区是一个由主服务器维护的固定长度的先进先出对接,默认大小为1M,可调整

固定长度的先进先出队列:出队、入队方式与普通先进先出队列一致,新元素由一边进入,旧元素由另一边弹出,不同的地方在于长度固定,例如长度为3的固定长度的先进先出队列,我们将1,2,3,4,5存入其中时,那么1,2,3会被放入队列中,当4放入时,1被弹出,5入队时,2被弹出,因此最终会存储:3,4,5

主服务在进行命令传播时会如下图所示:


主服务器向复制积压缓冲区和从服务器传播写命令

当从服务器重新连接上主服务器后,从服务器会通过PSYNC命令将自身的复制偏移量offset发送给主服务器,主服务器会根据这个复制偏移量来决定对从服务器采用何种操作:

  • 如果offset偏移量之后的数据存在与复制积压缓冲区中,那么主服务器将对从服务器执行部分重同步
  • 如果offset偏移量之后的数据已经不存在于复制积压缓冲区中,那么主服务会对从服务器采用完整重同步

Redis复制积压缓冲区的大小可以设置,一般将其设置为 second * write_size_per_second * 2的大小

3.1.3 服务器运行ID

每个Redis 服务器无论主服务器还是从服务器都有自己的运行ID
运行ID在服务器启动时生成,由40个随机的十六进制字符组成
当从服务器对主服务器进行初次复制时,主服务器会将自身的运行ID回传给从服务器,从服务器会将这个运行ID保存下来。
当从服务器断线重连主服务器时,会将这个运行ID发送个主服务器,主服务器会检查这个运行ID是否为自己的运行ID,如果不是则会直接执行完成重同步,如果是自行运行ID,则根据具体情况来决定是采用部分重同步还是完整重同步。

3.2 PSYNC命令

执行过程


PSYNC命令执行

4 复制的实现过程

1.设置主服务器的地址和端口

SLAVEOF 127.0.0.7 6379

2.建立套接字连接
3.发送PING命令


发送PING命令

4.身份验证
从服务器向主服务器发送一条AUTH命令,将密码带给主服务器。

身份验证

5.发送端口信息
执行命令

REPLCONF listening-port <port-number>

向主服务器发送从服务器监听端口
6.同步
7.命令传播

5.心跳检测

发送命令:

REPLCONF ACK <replication_offset>

其中replication_offset是从服务器当前的偏移量
这个命令主要有三个作用:

  • 检测主从服务器的连接状态
  • 辅助实现min-slaves选项
  • 检测命令丢失

5.1 检测主从服务器网络连接状态

执行如下命令:

127.0.0.1:9001> INFO replication
# Replication
role:master
connected_slaves:1
# lag值表示1s前发送过REPLCONF ACK
slave0:ip=127.0.0.1,port=9004,state=online,offset=293566,lag=1
master_replid:1bb39e63541f367d670879f7be07f49855d96aad
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:293580
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:293580

一般情况下lag值应该在0秒或1秒之间跳动,如果超过了1秒那么说明主从服务器之间连接出了问题

5.2 辅助实现min-slaves选项

Redis的min-slaves-to-write 和 min-slaves-max-lag 这两个选项可以防止主服务器在不安全的情况下执行写命令。
例如我们进行如下配置:

min-slaves-to-write 3
min-slaves-max-lag 10

那么在从服务器数量少于3个,或者三个从服务器的延迟(lag)值都大于或等于10时,主服务器将拒绝执行写命令。

5.3 检测命令丢失

如果因为网络故障,主服务器传播给从服务器的写命令丢失,那么当从服务器向
主服务器发送REPLCONF ACK <replication_offset>命令时,主服务器会发现从服务器当前的复制偏移量少于自己的复制偏移量,然后主服务就会根据从服务器提交的复制偏移量在复制积压缓冲区中找到从服务器中缺少的数据,并将这些数据重新发送给从服务器。

这里有个问题不是很清楚:
Redis从服务器由主服务器同步命令时,假如从服务器复制偏移量为:10000,主服务器复制偏移量也为:10000,
此时,主服务器接受了新的写入命令:set msg 'aaa',此时假如主服务器复制偏移量变为:10020,在向从服务器传播这条命令时失败,此时从服务器的复制偏移量还是为:10000,之后主服务器接受命令:set msg1 'bbbbbb',此时假如主服务器复制偏移量变为:10050,此时命令传播成功,那么从服务器的复制偏移量变为:10030,而主从服务器之间的心跳检测时,发现两边复制偏移量不一致,主为:10050,从为:10030,此时如果主服务器将复制缓冲区中从10030开始的命令传播给从服务器的话,会存在两个问题:
1、10030~10050是否为一个有效的Redis命令
2、10030开始的命令不是从服务器缺失的命令,破坏了主从数据的一致性
???这个问题需要后续找寻下答案

6 参考资料

《Redis设计与实现》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,039评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,223评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,916评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,009评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,030评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,011评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,934评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,754评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,202评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,433评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,590评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,321评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,917评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,568评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,738评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,583评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,482评论 2 352

推荐阅读更多精彩内容

  • 在Redis的持久化中曾提到,Redis高可用的方案包括持久化、主从复制(及读写分离)、哨兵和集群。其中持久化侧重...
    不变甄心阅读 1,496评论 0 5
  • 本篇就一下方面展开分析 如何使用主从复制? 主从复制的原理(重点是全量复制和部分复制、以及心跳机制) 实际应用中需...
    lucode阅读 994评论 0 5
  • Redis的单机模式不难,配置文件参数了解具体含义,设定业务上符合自己的就好了。 之前记录了关于Redis的数据结...
    JingQ阅读 807评论 0 0
  • 六点不到,老家堂弟来电:老大,二爷在河沟大田放的野猪夹,己夹到野猪,叫二爷赶快回家。 原来我父亲,天刚亮,就步行到...
    泗四坊方阅读 988评论 37 34
  • 你好,六方来财 看过一部电影,《朱莉与朱莉娅》,突发奇想,想学她写东西,今天是第一天,2017年12月28日。女主...
    文半子sky阅读 233评论 0 0