前言

参考资料:《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 建立套接字连接

  • 从服务器根据 masterhostmasterport 创建连向主服务器的套接字连接;
  • 套接字连接(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_offsetreplication_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设计与实现》的更多相关文章

  1. 第11章 Media Queries 与Responsive 设计

    Media Queries--媒体类型(一) 随着科学技术不断的向前发展,网页的浏览终端越来越多样化,用户可以通过:宽屏电视.台式电脑.笔记本电脑.平板电脑和智能手机来访问你的网站.尽管你无法保证一个 ...

  2. redis 笔记04 服务器、复制

    服务器 1. 一个命令请求从发送到完成主要包括以下步骤: 1). 客户端将命令请求发送给服务器 2). 服务器读取命令请求,并分析出命令参数 3). 命令执行器根据参数查找命令的实现函数,然后执行实现 ...

  3. Redis | 第7章 Redis 服务器《Redis设计与实现》

    目录 前言 1. 命令请求的执行过程 1.1 发送命令请求 1.2 读取命令请求 1.3 命令执行器(1):查找命令实现 1.4 命令执行器(2):执行预备操作 1.5 命令执行器(3):调用命令的实 ...

  4. Redis——学习之路二(初识redis服务器命令)

    上一章我们已经知道了如果启动redis服务器,现在我们来学习一下,以及如何用客户端连接服务器.接下来我们来学习一下查看操作服务器的命令. 服务器命令: 1.info——当前redis服务器信息   s ...

  5. Linux下Redis主从复制以及SSDB主主复制环境部署记录

    前面的文章已经介绍了redis作为缓存数据库的说明,本文主要说下redis主从复制及集群管理配置的操作记录: Redis主从复制(目前redis仅支持主从复制模式,可以支持在线备份.读写分离等功能.) ...

  6. Redis02 Redis客户端之Java、连接远程Redis服务器失败

    1 查看支持Java的redis客户端 本博文采用 Jedis 作为redis客户端,采用 commons-pool2 作为连接redis服务器的连接池 2 下载相关依赖与实战 2.1 到 Repos ...

  7. redis主从复制以及SSDB主主复制环境部署记录(四)

    redis配置主从和ssdb主主复制 参考:散尽浮华Linux下Redis主从复制以及SSDB主主复制环境部署记录 只做自己查阅. 环境要求:三台虚拟机一台做主,两台做从. 通过SSDB在redis做 ...

  8. Redis集群搭建,伪分布式集群,即一台服务器6个redis节点

    Redis集群搭建,伪分布式集群,即一台服务器6个redis节点 一.Redis Cluster(Redis集群)简介 集群搭建需要的环境 二.搭建集群 2.1Redis的安装 2.2搭建6台redi ...

  9. Redis | 第9章 Lua 脚本与排序《Redis设计与实现》

    目录 前言 1. Lua 脚本 1.1 Redis 创建并修改 Lua 环境的步骤 1.2 Lua 环境协作组件 1.3 EVAL 命令的实现 1.4 EVALSHA 命令的实现 1.5 脚本管理命令 ...

随机推荐

  1. 绑定socket描述符到一个网络设备

           网络编程中有时明明用eth0的地址来bind一个udp套接口, 可是发出去的包却是从eht1走的, 在网上找到这么一段话解释该问题:           在多 IP/网卡主机上,UDP ...

  2. docker使用redis过程出现的问题记录

    第一次使用docker搭建成功了单机版redis,但在使用过程中,还是遇到了不少问题,故而先把这些问题记录下来,以防后面再出现会忘记. 目前,只是在docker中搭建了三个单机版的容器,打算先捣鼓一周 ...

  3. Java测试开发--Spring Tools Suite (STS) 简介(一)

    sts是一个定制版的Eclipse,专为Spring开发定制的,方便创建调试运行维护Spring应用. 官网下载之后,可以看到一个sts-bundle,里面有三个文件夹,一个法律信息,一个tc Ser ...

  4. Kali-Linux 2020如何设置中文

    话不多说,直接上步骤 首先,想要修改系统默认语言普通用户是办不到的,这个时候就需要切换为root用户在终端输入 sudo su(切换用户指令,后面不加用户名就默认切换为root) 输入管理员密码后就像 ...

  5. springboot使用之请求参数与基本注解

    @PathVariable 作用:@PathVariable是spring3.0的一个新功能:接收请求路径中占位符的值,将URL中占位符参数{xxx}绑定到处理器类的方法形参中@PathVariabl ...

  6. vue项目部署到docker中

    通过nginx镜像部署 vue项目npm run build打包成dist目录,有的打包会加上版本号 启动 docker 将dist目录通过xftp拷贝到linux服务器上,同目录下新建Dockerf ...

  7. Ubuntu1804命令行安装vmtool

    Ubuntu1804命令行安装vmtool 安装虚拟机后快速安装vmtools的方法,仅需命令行输入即可 sudo apt-get upgrade sudo apt-get install open- ...

  8. robotframework-autoitlibrary离线安装

    由于AutoItLibrary需要依赖pywin32库.所以要使用AutoItLibrary必须要先安装好pywin32 1.pywin32下载地址安装:http://sourceforge.net/ ...

  9. 提升开发效率的notepad++一些快捷方法(实体类的创建和查询sql语句的编写)

    新手要创建数据库表中,对应字段名的实体类,是不是感觉很麻烦,可以用notepad++快速的把实体类中的字段名进行排版,随后直接粘入idea使用 下面是navicat的演示 选择一个表,右键选择设计表 ...

  10. 使用 docker + verdaccio 搭建npm私有仓库

    本文介绍如何使用 verdaccio 搭建私有npm仓库,以及使用 docker 时如何映射到本地目录,方便简单对仓库进行各种操作.系统环境是 Linux. verdaccio verdaccio 是 ...