Redis | 第11章 服务器的复制《Redis设计与实现》
前言
参考资料:《Redis设计与实现 第二版》;
第四部分为多机数据库的实现,主要由以下模块组成:复制、Sentinel、集群;
本篇将介绍 Redis 的复制功能。在 Redis 中,用户可以通过执行 SLAVEOF 命令或者设置 salveof 选项,让一个从服务器复制主服务器。
与本章相关的 Redis 命令总结在下篇文章,欢迎点击收藏,本篇将不再重复:
《Redis常用命令及示例总结(API)》:https://blog.csdn.net/dlhjw1412/article/details/119713214
1. 旧版复制功能的实现
- 旧版指 Redis 2.8 以前版本;
- 旧版 Redis 的复制功能分为同步(sync)和命令传播(command propagate)两个操作:
- 同步操作:将从服务器的数据库状态更新至主服务器当前所处的数据库状态;
- 命令传播:用于在主服务器的数据库状态被修改,导致主从服务器的数据库状态出现不一致时,让主从服务器重新回到一致状态;
1.1 同步与命令传播
- 同步:客户端向从服务器发送 SLAVEOF 命令,从服务器执行以下步骤:
- 1)从服务器向主服务器发送 SYNC 命令;
- 2)收到 SYNC 命令的主服务器执行 BGSAVE 命令,在后台生成 RDB 文件,并使用一个缓冲区记录此刻开始执行的所有写命令;
- 3)当主服务器完成 BGSAVE 命令时,将 RDB 文件发给从服务器,从服务器接收并载入 RDB 文件,将数据库状态更新至主服务器执行 BGSAVE 命令时的数据库状态;
- 4)主服务器将记录在缓冲区里的所有写命令发送给从服务器,从服务器执行写命令,将数据库状态更新至主服务器数据库当前的状态;

- 命令传播:同步操作完成后,主服务器会将自己执行的写命令,发送给从服务器。从服务器执行后,主从服务器数据库状态再次回到一致状态;
1.2 旧版复制功能的缺陷
- 处于命令传播阶段的主从服务器因为网络问题中断了复制,重连后从服务器会向主服务器发送 SYNC 命令执行同步操作;

- SYNC 命令非常消耗资源:
- 主服务器执行 BGSAVE 命令时:耗费主服务器大量 CPU、内存与磁盘 IO 资源;
- 主服务器将 RDB 文件发给从服务器时:耗费主从服务器大量网络资源(流量和带宽),并对主服务器响应命令请求的时间产生影响;
- 从服务器在载入 RDB 文件期间:从服务器阻塞无法处理命令请求;
2. 新版复制功能的实现
- 新版指 Redis 2.8 以后版本;
- 新版 Redis 的复制功能分为完全重同步(full resynchronization)和部分重同步(partial resynchronization)两个操作:
- 完全重同步:与初次复制情况相同;
- 部分重同步:主服务器仅将主从服务器在断线期间的写命令发给从服务器。使用 PSYNC 命令;

2.1 部分重同步的实现原理
- 部分重同步依赖以下三个部分:
- 主从服务器的复制偏移量(replication offset);
- 主服务器的复制积压缓冲区(replication backlog);
- 主服务器的运行 ID(run ID);
- 复制偏移量:
- 执行复制的主从服务器双方会分别维护一个复制偏移量;
- 主服务器每次向从服务器传播 N 个字节数据时,将自己的复制偏移量加 N;
- 从服务器每次收到主服务器传播来的 N 字节数据时,将自己的复制偏移量加 N;
- 通过对比主从服务器的复制偏移量可以判断其数据库状态是否一致;

- 复制积压缓冲区
- 复制积压缓冲区由主服务器维护一个固定长度(fixed-size)先进先出(FIFO)队列,默认大小 1MB;
- 当主服务器进行命令传播时,会将命令发给从服务器,同时将写命令入队到复制积压缓冲区;
- 重连时,从服务器将自己的复制偏移量
offset发给主服务器:- 若
offset+1的内容在复制积压缓冲区内,主服务器对从服务器执行部分同步操作; - 反之,执行完整重同步操作;
- 若
- 复制积压缓冲区的大小可以根据公式估算:
second * write_size_per_second:- second 为从服务器断线后重连所需平均时间;
- write_size_per_second 为主服务器平均每秒产生的写命令数据量;
- 为安全起见,可将复制积压缓冲区大小设置为:上述公式乘 2;

- 服务器运行 ID:
- 每个 Redis 都有自己的运行 ID;
- 运行 ID 在服务器启动时自动生成,由 40 个随机的十六进制字符组成;
- 从服务器对主服务器进行初次复制时,主服务器会将自己的运行 ID 传送给从服务器,从服务器将这个 ID 保存;
- 重连时,从服务器向主服务器发送保存的运行 ID:
- 若从服务器保存的 ID 为当前主服务器运行 ID,根据偏移量判断重同步方式;
- 反之,执行完整重同步操作;
3. PSYNC 命令的实现
- PSYNC 命令的调用方法有两种:
- 从服务器没有复制过任何主服务器,或之前执行过 SLAVEOF NO ONE 命令,那么从服务器在开始复制时向主服务器发送 PSYNC ? -1 命令,主动请求主服务器进行完整重同步;
- 反之,从服务器发送 PSYNC master_run_id offset 命令,
master_run_id为上一次复制时的主服务器的运行 ID,offset为从服务器当前的复制偏移量;
- 主服务器接受 PSYNC 命令后会产生三种回复:
- 完整重同步:返回
+FULLRESYNC master_run_id offset,master_run_id 为当前主服务器的运行 ID,offset 为主服务器当前的复制偏移量; - 部分重同步:返回
+CONTINUE,从服务器只需要等待主服务器发送自己缺少的部分数据; - 错误:返回
-ERR,主服务器版本低于 Redis 2.8,从服务器发送 SYNC 命令,与主服务器执行完整同步操作;
- 完整重同步:返回

4. 复制的详细步骤
- 该步骤为 Redis 2.8 版本以上
- 客户端向从服务器发送 SLAVEOF ip port 命令;
4.1 设置主服务器的地址和端口
从服务器将 SLAVEOF ip port 命令的 ip 地址和 port 端口保存到服务器状态里:
struct redisServer{
//...
//主服务器的地址
char *masterhost;
//主服务器的端口
int masterport;
};
从服务器向客户端返回 OK,然后开始复制;
4.2 建立套接字连接
- 从服务器根据
masterhost和masterport创建连向主服务器的套接字连接; - 套接字连接(connect)成功后,从服务器为该套接字关联一个文件事务处理器,专门用来处理复制工作;
- 主服务器接受(accept)从服务器的套接字连接后,为该套接字创建响应客户端状态,并将从服务器视作客户端(client);
- 此时,从服务器具备服务器(server)和客户端(client)双重身份;

4.3 发送 PING 命令
- 从服务器成为主服务器的客户端后,向主服务器发送 PING 命令;
- PING 命令的作用:
- 检查套接字的读写状态是否正常;
- 检查主服务器能否正常处理命令请求;
- 主服务器对 PING 命令的回复有 3 种情况:
- 返回命令回复:但从服务器不能在有限时间内读取命令内容,表示主从服务器间网络连接状态不佳。此时从服务器会断开并重新创建连向主服务器的套接字;
- 返回错误:表示主服务器暂时没法处理从服务器的命令请求。此时从服务器会断开并重新创建连向主服务器的套接字;
- 返回
PONG:表示网络连接正常,从服务器可以继续执行复制工作;

4.4 身份验证
从服务器收到 PONG 回复后,根据是否设置
masterauth选项决定是否进行身份验证;- 从服务器没有设置 masterauth 选项,不进行身份验证;
- 从服务器设置了 masterauth 选项,需要进行身份验证;
在需要进行身份验证的情况下,从服务器给主服务器发送 AUTH password 命令,命令的参数
password为从服务器masterauth选项的值;从服务器在进行身份验证时根据:主服务器的
requirepass选项和从服务器的masterauth选项不同,可能遇到以下情况:主服务器的 requirepass选项从服务器的 masterauth选项情况 设置 设置 相同则继续复制,不同则返回 invalid password 错误 设置 没有设置 返回 NOAUTH 错误 没有设置 设置 返回 no password is set 错误 没有设置 没有设置 继续复制工作

4.5 发送端口信息
身份验证完成后,从服务器执行 REPLCONF listening-port port-number 命令,向主服务器发送自己的监听端口号
port-number;主服务器接受后,存储在从服务器的客户端状态
slave_listening_port属性中:typedef struct redisClient{
//...
// 从服务器的监听端口号
int slave_listening_port;
} redisClient;
4.6 同步
- 从服务器向主服务器发送 PSYNC 命令,执行同步操作,将自己的数据库更新至主服务器数据库当前所处的状态;
- 在同步操作执行完后,主服务器会成为从服务器的客户端,理由如下:
- 完整重同步情况:需要将缓冲区里的写命令发送给从服务器;
- 部分重同步情况:需要将复制积压缓冲区里的写命令发送给从服务器;

4.7 命令传播
- 完成同步后,主服务器进入命令传播阶段,一直将写命令发给从服务器;
5. 心跳检测
- 在命令传播阶段,从服务器默认每秒向主服务器发送命令 REPLCONF ACK replication_offset,
replication_offset参数是从服务器当前的复制偏移量; - 心跳检测的三个作用:
- 检测主从服务器的网络连接状态:使用 INFO replication 命令可以查看从服务器最后一次向主服务器发送 REPLCONF ACK 命令距离现在过了多久,一般在 0~1 秒为正常;
- 辅助 min-slaves 配置选项:当从服务器数量 x 少于
min-slaves-to-write属性值或 x 个服务器的延迟大于等于min-slaves-max-lag属性值时,主服务器拒绝写命令; - 检测命令丢失:当主服务器发现从服务器的
replication_offset参数与自己的不一致时,补发写命令数据;
- 补发命令数据与部分重同步的区别在于:前者没有断线,后再断线了;
- Redis 2.8 版本以前没有补发命令数据功能;
最后
新人制作,如有错误,欢迎指出,感激不尽!
欢迎关注公众号,会分享一些更日常的东西!
如需转载,请标注出处!

Redis | 第11章 服务器的复制《Redis设计与实现》的更多相关文章
- 第11章 Media Queries 与Responsive 设计
Media Queries--媒体类型(一) 随着科学技术不断的向前发展,网页的浏览终端越来越多样化,用户可以通过:宽屏电视.台式电脑.笔记本电脑.平板电脑和智能手机来访问你的网站.尽管你无法保证一个 ...
- redis 笔记04 服务器、复制
服务器 1. 一个命令请求从发送到完成主要包括以下步骤: 1). 客户端将命令请求发送给服务器 2). 服务器读取命令请求,并分析出命令参数 3). 命令执行器根据参数查找命令的实现函数,然后执行实现 ...
- Redis | 第7章 Redis 服务器《Redis设计与实现》
目录 前言 1. 命令请求的执行过程 1.1 发送命令请求 1.2 读取命令请求 1.3 命令执行器(1):查找命令实现 1.4 命令执行器(2):执行预备操作 1.5 命令执行器(3):调用命令的实 ...
- Redis——学习之路二(初识redis服务器命令)
上一章我们已经知道了如果启动redis服务器,现在我们来学习一下,以及如何用客户端连接服务器.接下来我们来学习一下查看操作服务器的命令. 服务器命令: 1.info——当前redis服务器信息 s ...
- Linux下Redis主从复制以及SSDB主主复制环境部署记录
前面的文章已经介绍了redis作为缓存数据库的说明,本文主要说下redis主从复制及集群管理配置的操作记录: Redis主从复制(目前redis仅支持主从复制模式,可以支持在线备份.读写分离等功能.) ...
- Redis02 Redis客户端之Java、连接远程Redis服务器失败
1 查看支持Java的redis客户端 本博文采用 Jedis 作为redis客户端,采用 commons-pool2 作为连接redis服务器的连接池 2 下载相关依赖与实战 2.1 到 Repos ...
- redis主从复制以及SSDB主主复制环境部署记录(四)
redis配置主从和ssdb主主复制 参考:散尽浮华Linux下Redis主从复制以及SSDB主主复制环境部署记录 只做自己查阅. 环境要求:三台虚拟机一台做主,两台做从. 通过SSDB在redis做 ...
- Redis集群搭建,伪分布式集群,即一台服务器6个redis节点
Redis集群搭建,伪分布式集群,即一台服务器6个redis节点 一.Redis Cluster(Redis集群)简介 集群搭建需要的环境 二.搭建集群 2.1Redis的安装 2.2搭建6台redi ...
- Redis | 第9章 Lua 脚本与排序《Redis设计与实现》
目录 前言 1. Lua 脚本 1.1 Redis 创建并修改 Lua 环境的步骤 1.2 Lua 环境协作组件 1.3 EVAL 命令的实现 1.4 EVALSHA 命令的实现 1.5 脚本管理命令 ...
随机推荐
- JAVA笔记4__static关键字/对象数组/foreach/方法的可变参数
/** * static关键字:修饰属性(实质就是全局变量).方法(无需本类的对象即可调用此方法).类. * 1.static方法只能调用static方法 * 2.static方法只能访问static ...
- 优客源创会 西安站 西邮Linux兴趣小组
2016年5月19日晚7:00,优客源创会西安站在西安邮电大学长安校区东区教学楼FF305如期举行,西安邮电大学计算机学院教授.西邮Linux兴趣小组指导老师陈莉君.王小银老师和来自开源中国的周凯先生 ...
- 攻防世界 WEB 高手进阶区 XCTF 4th-CyberEarth ics-06 Writeup
攻防世界 WEB 高手进阶区 XCTF 4th-CyberEarth ics-06 Writeup 题目介绍 题目考点 掌握暴力破解手段 Writeup 打开链接 http://220.249.52. ...
- 【AI测试】人工智能 (AI) 测试--开篇
人工智能测试 什么是人工智能,人工智能是怎么测试的.可能是大家一开始最想了解的.大家看图中关于人工智能的定义.通俗点来说呢,就是 让机器实现原来只有人类才能完成的任务:比如看懂照片,听懂说话,思考等等 ...
- js 事件流和事件冒泡阻止
js 事件流和事件冒泡阻止 事件流 当浏览器发展到第四代的时候(IE4与Netscape4)浏览器开发团队遇到一个有意思的的问题: 页面的哪一部分会拥有某个特定的事件? 比如在纸上画上一组同心圆,如果 ...
- 基于I2C的AHT20温湿度传感器的数据采集
关于:IC( Inter-- Integrated Circuit)总线是一种由 PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备.它是由数据线SDA和时钟SCL构成的串行总线,可 ...
- Git 修改已提交的commit注释
两种情况: 1.已经将代码push到远程仓库 2.还没将代码push到远程仓库,还在本地的仓库中 这两种情况下的修改大体相同,只是第一种情况最后会多一步 下面来说怎么修改 先搞清楚你要修改哪次的提交注 ...
- 【死磕 NIO】— 深入分析Buffer
大家好,我是大明哥,今天我们来看看 Buffer. 上面几篇文章详细介绍了 IO 相关的一些基本概念,如阻塞.非阻塞.同步.异步的区别,Reactor 模式.Proactor 模式.以下是这几篇文章的 ...
- liunx基础知识点1:系统管理相关命令、目录操作命令、文本编辑、关闭防火墙、重启和关闭
Linux(一) liunx系统那么重要,作为一个测试人员,不掌握你就损失了好几千,为了这个钱,也为了面子,什么鬼?我爱膨胀.你看看这些知识喽.我整理的,可费工夫了. 下次给大家一个面试题啊,更直观
- ES6--ES12笔记整理(1)
一.let const 五个共同特点 不允许重复声明 块级作用域 不存在变量提升 不影响作用域链 暂时性死区---在代码块内,使用let/const命令声明变量之前,该变量都是不可用的.这在语法上,称 ...