主从复制

这是《Redis设计与实现》系列的文章,系列导航:Redis设计与实现笔记

SLAVEOF

新旧复制功能

旧版复制功能

旧版复制功能的实现为 同步命令传播

当刚连上Master时,要做一次全同步:

sequenceDiagram
participant Slave
participant Master
Slave->>Master: SYNC
Master->>Master: BGSAVE
Master->>Master: 记录此时的命令到缓冲区中
Master->>Slave: 发送RDB
Master->>Slave: 发送命令缓冲区中的命令

之所以要用到缓冲区是因为,在主节点进行 BGSAVE 的过程中如果有命令执行,那么我们要把这些命令也记录下来。

之后,主从节点之间只用 命令传播 就可以做到同步了,也就是说主节点执行什么命令,从节点跟着执行。(当然,一些随机、时间类的函数会直接转换成定值)

旧版复制的缺陷

如果从节点断线后重新连接,旧版复制功能的效率很低,因为为了让从服务器补足一小部分的确实却要进行一次 SYNC 命令

为什么低效:

  1. 主节点 BGSAVE 要消耗大量的CPU、内存、IO资源
  2. 主节点发送需要消耗网络资源
  3. 从节点需要载入,且载入期间处于阻塞状态

新版复制功能

PSYNC 命令代替 SYNC。

PSYNC 具有 完整重同步部分重同步 两种模式,分别针对初次同步和重新同步两种场景。

复制功能的实现

复制的实现

复制的一些具体的细节,当进行复制时:

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

    struct redisServer{
    //...
    char *masterhost;
    int masterport;
    //...
    }
  2. 建立套接字连接,并关联一个专门处理复制工作的文件事件处理器

  3. 发送 PING 命令,检查套接字和主服务器的状态是否正常

  4. 身份验证,主从必须配置一致且密码正确(如果有)才能通过验证

  5. 发送端口信息:主节点也得知道给从节点的哪个端口发消息,不是么

  6. 同步:干正事儿喽

    这里书上说:

    • 在同步操作执行之前,只有从服务器是主服务器的客户端,但是在执行同步操作之后,主服务器也会成为从服务器的客户端。
    • 正是因为主服务成为了从服务器的客户端,所以主服务器才能通过发送写命令来改变从服务器的数据库状态。

    我想了想,似乎一般确实都是客户端改变服务端的数据的,所以这么说倒也在理,但是服务端不是也可以给客户端发送数据么?所以这里可能和 Redis 的具体实现有关?

  7. 命令传播:进入了第二个阶段

如何部分重同步

要关注的三个部分:

  1. 复制偏移量:主从服务器都有复制偏移量,通过这个值判断主从是否处于一致状态

  2. 主服务器的复制积压缓冲区:保存执行命令的历史记录

    一个固定长度(默认1MB)的 FIFO 的队列,当主从不一致时可以计算并从中获取缺少的命令。

    由于固定长度,所以如果缺的多了就只能进行完整重同步了。

    大小一般设为 断连平均时间 * 每秒的命令数,安全起见再乘以2。

  3. 服务器的运行 ID

    毕竟只有 ID 一致同步才有意义,否则说明换主人了,那还是全同步吧

PSYNC的逻辑

graph LR;

S(接收到SLAVEOF命令) --> A{第一次复制?}
A --Y--> A1[发送PSYNC ? -1] --> E1(返回+FULLRESYNC &ltrunid> &ltoffset&gt)
A --N--> A2[发送PSYNC &ltrunid&gt &ltoffset&gt] --> B{主服务器返回 +CONTINUE}

B --N--> E1
B --Y--> E2[执行部分重同步]

主要是判断 是否是第一次复制是否是同一个主服务器,从而决定是部分重同步还是全同步。

上图没有展示的是,如果主服务器不支持 PSYNC,则返回 -ERR

心跳检测

心跳检测:在命令传播阶段,从服务器默认每秒发送一次心跳:REPLCONF ACK <replication_offset>

作用有三:

  1. 检测主从服务器的网络状态

  2. 辅助实现 min-slaves 配置选项

    min-slaves-to-write、min-slaves-max-lag 可以防止发生脑裂现象

  3. 通过 offset 检测命令是否丢失

Redis设计与实现3.1:主从复制的更多相关文章

  1. 探索Redis设计与实现12:浅析Redis主从复制

    本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...

  2. Redis如何实现高可用【主从复制+哨兵机制+keepalived】

    实现redis高可用机制的一些方法: 保证redis高可用机制需要redis主从复制.redis持久化机制.哨兵机制.keepalived等的支持. 主从复制的作用:数据备份.读写分离.分布式集群.实 ...

  3. 探索Redis设计与实现15:Redis分布式锁进化史

    本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...

  4. 探索Redis设计与实现14:Redis事务浅析与ACID特性介绍

    本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...

  5. 探索Redis设计与实现13:Redis集群机制及一个Redis架构演进实例

    本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...

  6. 探索Redis设计与实现11:使用快照和AOF将Redis数据持久化到硬盘中

    本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...

  7. 探索Redis设计与实现10:Redis的事件驱动模型与命令执行过程

    本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...

  8. 探索Redis设计与实现9:数据库redisDb与键过期删除策略

    本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...

  9. 探索Redis设计与实现8:连接底层与表面的数据结构robj

    本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...

随机推荐

  1. 基本类型数组转List

    基本类型数组转List 小数 double[] src = {1.1,2.1,3.1}; List<Double> list = Arrays.stream( src ).boxed(). ...

  2. glusterfs架构和原理

    分布式存储已经研究很多年,但直到近年来,伴随着谷歌.亚马逊和阿里等互联网公司云计算和大数据应用的兴起,它才大规模应用到工程实践中.如谷歌的分布式文件系统GFS.分布式表格系统google Bigtab ...

  3. Oracle中between 和 in

    select * from test_s where id between 2 and 12; between 就是左右全闭区间. SELECT columnsFROM tablesWHERE col ...

  4. jQuery实现数字时钟

    运行效果: 源代码: 1 <!DOCTYPE html> 2 <html lang="zh"> 3 <head> 4 <meta char ...

  5. [MySQL]IP处理函数inet_aton()和inet_ntoa()

    INET_ATON(expr) 给出一个作为字符串的网络地址的"点地址"(如127.0.0.1)表示,返回一个代表该地址数值的整数.地址可以是4或8比特地址. mysql> ...

  6. title与h1的区别、b与strong的区别、i与em的区别

    strong标签有语义,是起到加重语气的效果,而b标签是没有的,b标签只是一个简单加粗标签.b标签之间的字符都设为粗体,strong标签加强字符的语气都是通过粗体来实现的,而搜索引擎更侧重strong ...

  7. c++对于c的拓展_引用的本质是指针常量

    本质:c++底层实现的指针常量(Type & ref =val; // Type *const ref =&val)

  8. SpatiaLite 数据库使用记录

    SpatiaLite 数据库使用记录 官网 https://www.gaia-gis.it/fossil/libspatialite/index 下载地址 https://www.gaia-gis.i ...

  9. java的collection类

    collection来源于java.util包. Collection 接口常用的方法 size():返回集合中元素的个数 add(Object obj):向集合中添加一个元素 addAll(Coll ...

  10. 夯实基础上篇-图解 JavaScript 执行机制

    讲基础不易,本文通过 9 个 demo.18 张 图.2.4k 文字串讲声明提升.JavaScript 编译和执行.执行上下文.调用栈的基础知识.