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 脚本管理命令 ...
随机推荐
- Jquery取值方法汇总
一.下拉框 1.jquery获取当前选中select的text值 var a = $("#ShareMoneyType").find("option:selected&q ...
- vue路由监听和参数监听
1.路由携带数据跳转 routerAction(hideDisplays, data) { switch (hideDisplays) { case "pubAccountMenu" ...
- CentOS7 安装oracle 11g (11.2.0.1.0)
1.安装依赖: #yum -y install binutils compat-libcap1 compat-libstdc++-33 gcc gcc-c++ glibc glibc-devel ks ...
- echarts 让轴自适应数据为小数整数
echarts 让轴自适应数据为小数整数,以解决y轴数值重复的问题 工作中突然遇到这个问题 试了一下用formatter自适应 ok 在yAxis中提阿尼按键属性 axisLabel 1 axis ...
- dart系列之:dart语言中的变量
目录 简介 dart中的变量 定义变量 变量的默认值 Late变量 常量 总结 简介 flutter是google在2015年dart开发者峰会上推出的一种开源的移动UI构建框架,使用flutter可 ...
- 好好的 Tair 排行榜不用,非得自己写?20 行代码实现高性能排行榜
TairZset 是阿里云自研的可实现任意维度 double 类型的分值排序的数据结构,借助 Tair 客户端同时可实现扩展性,即可以将计算任务分布至多个数据节点完成,实现分布式排行榜能力.本文介绍了 ...
- robot_framewok自动化测试--(6)Collections 库
Collections 库 Collections 库同样为 Robot Framework 标准类库,它所提供的关键字主要用于列表.索引.字典的处理. 在使用之前需要在测试套件(项目)中添加: 1. ...
- idea Mark Directory as 的几种文件类型
1. Source roots (or source folders) 源文件夹 通过为该类别分配文件夹,可以告诉IntelliJ IDEA该文件夹及其子文件夹包含应在构建过程中进行编译的源代码. 2 ...
- 解决虚拟机安装linux系统无法全屏问题 & vmtools安装
修改设置 1) 如下图右单击虚拟机名,选择[settings-],调出虚拟机设置界面. 2) 在设置界面选择[hardware]->[CD/DVD2(IDE)]->[Connection] ...
- 导出 doc
... /** * 导出word * @return * @throws Exception */ @JCall public String word() throws Exception{ Stri ...