热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Redis主从握手流程,你真的了解了吗?(赠书

一个典型的


Redis是开源的key-value存储系统,可作为数据库、缓存、消息组件。

Redis的作者是Salvatore Sanfilippo(网名为antirez),他在2009年开发完成并开源了Redis。

Redis由于性能极高、功能强大,迅速在业界流行,现已成为高并发系统中最常用的组件之一。 

Redis提供了多种类型的数据结构,如字符串(String)、散列(Hash)、列表(List)、集合(Set)、有序集合(Sorted Set)等。

Redis还是分布式系统,主从集群可以实现数据热备份,哨兵(Sentinel)机制可以保证主从集群高可用,Cluster集群则提供了水平扩展的能力。

Redis还提供了持久化、Lua脚本、Module模块、Stream消息流、Tracking机制等一系统强大功能,适用于各种业务场景。

Redis是一个典型的“小而美”的程序。

Redis实现简单,源码非常优雅简洁,阅读起来并不吃力,而且Redis功能齐全,涵盖了数据存储、分布式、消息流等众多特性,非常值得深入学习。

Redis中的一个重要概念就是主从复制机制

下面详细分析Redis主从复制机制中主从握手的过程。

Redis主从复制机制中有两个角色:主节点与从节点。

主节点处理用户请求,并将数据复制给从节点。

主从复制机制主要有以下作用:

(1)数据冗余,将数据热备份到从节点,即使主节点由于磁盘损坏丢失数据,从节点依然保留数据副本。

(2)读/写分离,可以由主节点提供写服务,从节点提供读服务,提高Redis服务整体吞吐量。

(3)故障恢复,主节点故障下线后,可以手动将从节点切换为主节点,继续提供服务。

(4)高可用基础,主从复制机制是Sentinel和Cluster机制的基础,Sentinel和Cluster都实现了故障转移,即主节点故障停止后,Redis负责选择一个从节点切换为主节点,继续提供服务。

下面将主从复制流程分为三个阶段。

(1)握手阶段:主从连接成功后,从节点需要将自身信息(如IP地址、端口等)发送给主节点,以便主节点能认识自己。

(2)同步阶段:从节点连接主节点后,需要先同步数据,数据达到一致(或者只有最新的变更不一致)后才进入复制阶段。

Redis支持两种同步机制:

  • 全量同步:从节点发送命令PSYNC ? -1,要求进行全量同步,主节点返回响应+FULLRESYNC,表明同意全量同步。随后,主节点生成RDB数据并发送给从节点。这种方式常用于新的从节点首次同步数据。

  • 部分同步:从节点发送命令PSYNC replid offset,要求进行部分同步,主节点响应+CONTINUE,表明同意部分同步。主节点只需要把复制积压区中offset偏移量之后的命令发送给从节点即可(主节点会将执行的写命令都写入复制积压区)。这种方式常用于主从连接断开重连时同步数据。如果offset不在复制积压区中,那么主节点也会返回+FULLRESYNC,要求进行全量同步。

(3)复制阶段:主节点在运行期间,将执行的写命令传播给从节点,从节点接收并执行这些命令,从而达到复制数据的效果。Redis使用的是异步复制,主节点传播命令后,并不会等待从节点返回ACK确认。异步复制的优点是低延迟和高性能,缺点是可能在短期内主从节点数据不一致。

本文中指的命令,包含命令名及执行命令的参数。

PSYNC命令涉及以下属性:

  • server.master_repl_offset:记录当前服务器已执行命令的偏移量。

  • server.replid:40位十六进制的随机字符串,在主节点中是自身ID,在从节点中记录的是主节点ID。

  • server.replid2:用于主节点,存放上一个主节点ID。

  • server.repl_backlog:复制积压区,主节点将最近执行的写命令写入复制积压区,用于实现部分同步。

下面介绍一下Redis主从握手流程。

主从复制的机制是由从节点发起流程,我们可以发送REPLICAOF命令到某个服务器,要求它成为指定服务器的从节点:

    REPLICAOF <masterip> <masterport>

    或者在配置文件中添加配置REPLICAOF > ,这样Redis服务器启动后将成为指定服务器的从节点。

    提示:从Redis 5开始为SLAVEOF命令提供别名REPLICAOF,这两个命令的作用一样。

    下面以从节点的视角,分析主从握手的过程。

    从节点握手阶段涉及以下属性。

    server.repl_state:用于从节点,标志从节点当前复制状态。有如下值:

    • REPL_STATE_NONE:无主从复制关系。

    • REPL_STATE_CONNECT:待连接。

    • REPL_STATE_CONNECTING:正在连接。

    • …(部分握手状态并没有列出)

    • REPL_STATE_TRANSFER:从节点正在接收RDB数据。

    • REPL_STATE_CONNECTED:已连接,主从同步完成。

    从节点使用replicaofCommand函数处理REPLICAOF命令。

    该函数执行如下逻辑:

    (1)如果处理的命令是REPLICAOF NO ONE,则将当前服务器转换为主节点,取消原来的主从复制关系,退出函数。

    (2)调用replicationSetMaster函数,与给定服务器建立主从复制关系。

    另外,我们在配置文件中配置REPLICAOF ,Redis加载该配置,也会将server.repl_state设置为REPL_STATE_CONNECT状态(config.c)。

    从节点server.repl_state进入REPL_STATE_CONNECT状态后,主从复制流程已经开始。

    serverCron时间事件负责对REPL_STATE_CONNECT状态进行处理:

      int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) {
      ...
      if (server.repl_state == REPL_STATE_CONNECT) {
      if (connectWithMaster() == C_OK) {
      serverLog(LL_NOTICE,"MASTER <-> REPLICA sync started");
      }
      }
      }

      调用connectWithMaster函数进行处理,该函数负责建立主从网络连接:

        int connectWithMaster(void) {
        // [1]
        server.repl_transfer_s = server.tls_replication ? connCreateTLS() : connCreateSocket();
        // [2]
        if (connConnect(server.repl_transfer_s, server.masterhost, server.masterport,
        NET_FIRST_BIND_ADDR, syncWithMaster) == C_ERR) {
        ...
        return C_ERR;
        }




        // [3]
        server.repl_transfer_lastio = server.unixtime;
        server.repl_state = REPL_STATE_CONNECTING;
        return C_OK;
        }

        【1】创建一个Socket套接字。connCreateTLS函数创建TLS连接,connCreateSocket函数创建TCP连接,它们都返回套接字文件描述符。该连接是主从节点网络通信的连接,本书称之为主从连接。

        【2】connConnect函数负责连接到主节点,并且在连接成功后调用syncWithMaster函数。

        【3】从节点server.repl_state进入REPL_STATE_CONNECTING状态。

        网络连接成功后,从节点调用syncWithMaster函数,进入握手阶段:

          void syncWithMaster(connection *conn) {
          char tmpfile[256], *err = NULL;
          int dfd = -1, maxtries = 5;
          int psync_result;
          ...
          // [1]
          if (server.repl_state == REPL_STATE_CONNECTING) {
          connSetReadHandler(conn, syncWithMaster);
          connSetWriteHandler(conn, NULL);
          server.repl_state = REPL_STATE_RECEIVE_PONG;
          err = sendSynchronousCommand(SYNC_CMD_WRITE,conn,"PING",NULL);
          if (err) goto write_error;
          return;
          }
          ...
          // [2]
          if (server.repl_state != REPL_STATE_RECEIVE_PSYNC) {
          goto error;
          }




          // more
          }

          【1】根据server.repl_state状态,执行对应操作。

          从节点发送给主节点的信息,主节点会记录在从节点客户端,并在INFO命令中输出这些信息。另外,Sentinel模块需要从主节点INFO命令响应中获取这些从节点信息。

          【2】执行到这里,主从握手阶段已经完成。server.repl_state必须处于REPL_STATE_ RECEIVE_PSYNC状态,否则报错。

          下面使用Linux tcpdump工具抓取主从连接报文,分析主从节点握手阶段的通信内容(主节点端口为6000):

            tcpdump tcp -i lo -nn port 6000 -T RESP

            tcpdump支持RESP协议,最后一个选项-T RESP要求tcpdump以RESP协议格式解析报文。

            其中6000端口为主节点端口,60374端口为从节点通信端口。从tcpdump的输出可以清晰地看到主从节点在握手阶段的通信内容。

            提示:tcpdump解析后的RESP内容并不会展示数据类型的标志符,如主节点对从节点PING命令的响应实际上是“-NOAUTH Authentication required.”,请读者阅读源码时注意。

            以主节点视角分析握手阶段,主节点不断处理来自从节点的命令(包括PING、AUTH、REPLCONF),感兴趣的读者可自行阅读代码。

            Redis主从握手流程到此就分析完毕了。

            本内容摘自《Redis核心原理与实践》,想了解更多关于Redis的内容,欢迎阅读此书。



            ▊《Redis核心原理与实践

            梁国斌 


            • 新版本:基于Redis 6.0.9,分析了Redis新特性,如Redis 6的ACL、Tracking等机制。

            • 重实践:本书在对应知识点的基础上提供了详细的应用示例,帮助读者循序渐进、由浅到深地学习和理解Redis新特性。

            • 易掌握:本书总结了Redis各个核心功能的实现原理,并以适量图文,对Redis源码及其实现原理进行详细分析,向读者展示Redis核心功能的设计思想和实现流程。

            • 可扩展:本书由Redis延展出了两方面内容:一是Redis中使用的UNIX机制,二是如何通过Redis实现一个分布式系统,主要是Sentinel、Cluster机制的实现原理。


            本书深入地分析了Redis核心功能的内部机制与实现方式,大部分内容源自对Redis源码的分析,并从中总结出实现原理。通过阅读本书,读者可以快速、轻松地了解Redis的内部运行机制。

            (京东满100减50,快快扫码抢购吧!)

            抽奖赠书

            活动方式关注下方“江南一点雨”公众号,在后台回复“6”获取抽奖链接。

            活动时间:截至8月26日(周四)开奖。

            快快拉上你的小伙伴参与进来吧~~



            如果喜欢本文
            欢迎 在看留言分享至朋友圈 三连
            ▼点击阅读原文,查看本书详情~


            推荐阅读
            • 深入理解Redis中的字典实现
              本文详细介绍了Redis中字典的实现机制,包括其底层数据结构、哈希表与哈希节点的关系、元素添加方法及rehash操作的具体流程。 ... [详细]
            • RocketMQ在秒杀时的应用
              目录一、RocketMQ是什么二、broker和nameserver2.1Broker2.2NameServer三、MQ在秒杀场景下的应用3.1利用MQ进行异步操作3. ... [详细]
            • 如果应用程序经常播放密集、急促而又短暂的音效(如游戏音效)那么使用MediaPlayer显得有些不太适合了。因为MediaPlayer存在如下缺点:1)延时时间较长,且资源占用率高 ... [详细]
            • MySQL Decimal 类型的最大值解析及其在数据处理中的应用艺术
              在关系型数据库中,表的设计与SQL语句的编写对性能的影响至关重要,甚至可占到90%以上。本文将重点探讨MySQL中Decimal类型的最大值及其在数据处理中的应用技巧,通过实例分析和优化建议,帮助读者深入理解并掌握这一重要知识点。 ... [详细]
            • java解析json转Map前段时间在做json报文处理的时候,写了一个针对不同格式json转map的处理工具方法,总结记录如下:1、单节点单层级、单节点多层级json转mapim ... [详细]
            • vsftpd配置(虚拟用户、匿名用户登录)
              一、ftp服务搭建(一)概述1.ftp连接及传输模式(1)控制连接TCP21,用于发送FTP命令信息 ... [详细]
            • iOS snow animation
              CTSnowAnimationView.hCTMyCtripCreatedbyalexon1614.Copyright©2016年ctrip.Allrightsreserved.# ... [详细]
            • 包含phppdoerrorcode的词条 ... [详细]
            • MySQL初级篇——字符串、日期时间、流程控制函数的相关应用
              文章目录:1.字符串函数2.日期时间函数2.1获取日期时间2.2日期与时间戳的转换2.3获取年月日、时分秒、星期数、天数等函数2.4时间和秒钟的转换2. ... [详细]
            • 本文节选自《NLTK基础教程——用NLTK和Python库构建机器学习应用》一书的第1章第1.2节,作者Nitin Hardeniya。本文将带领读者快速了解Python的基础知识,为后续的机器学习应用打下坚实的基础。 ... [详细]
            • Python 数据可视化实战指南
              本文详细介绍如何使用 Python 进行数据可视化,涵盖从环境搭建到具体实例的全过程。 ... [详细]
            • 本文详细介绍了 InfluxDB、collectd 和 Grafana 的安装与配置流程。首先,按照启动顺序依次安装并配置 InfluxDB、collectd 和 Grafana。InfluxDB 作为时序数据库,用于存储时间序列数据;collectd 负责数据的采集与传输;Grafana 则用于数据的可视化展示。文中提供了 collectd 的官方文档链接,便于用户参考和进一步了解其配置选项。通过本指南,读者可以轻松搭建一个高效的数据监控系统。 ... [详细]
            • 在CentOS 7环境中安装配置Redis及使用Redis Desktop Manager连接时的注意事项与技巧
              在 CentOS 7 环境中安装和配置 Redis 时,需要注意一些关键步骤和最佳实践。本文详细介绍了从安装 Redis 到配置其基本参数的全过程,并提供了使用 Redis Desktop Manager 连接 Redis 服务器的技巧和注意事项。此外,还探讨了如何优化性能和确保数据安全,帮助用户在生产环境中高效地管理和使用 Redis。 ... [详细]
            • 为什么多数程序员难以成为架构师?
              探讨80%的程序员为何难以晋升为架构师,涉及技术深度、经验积累和综合能力等方面。本文将详细解析Tomcat的配置和服务组件,帮助读者理解其内部机制。 ... [详细]
            • 本文是Java并发编程系列的开篇之作,将详细解析Java 1.5及以上版本中提供的并发工具。文章假设读者已经具备同步和易失性关键字的基本知识,重点介绍信号量机制的内部工作原理及其在实际开发中的应用。 ... [详细]
            author-avatar
            泉州多棱汽车销售服务有限公司
            这个家伙很懒,什么也没留下!
            PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
            Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有