10.3、节点通信

节点通信

  1. 通信流程

    在分布式存储中需要提供维护节点元数据信息的机制,所谓元数据是指:节点负责那些数据,是否出现故障等状态信息。常见的元数据维护方式分为:集中式和P2P方式。Redis集群采用P2P的Gossip(留言)协议,Gossip协议工作原理就是节点彼此不断通信交换信息,一段时间后所有的节点都会知道集群完整的信息,这种方式类似留言传播。

    通信过程说明;

    1)集群中的每个节点都会单独开辟一个TCP通道,用于节点之间彼此通信,通信端口号在基础端口上加10000.

    2)每个节点在固定周期内通过特定规则选择几个节点发送ping消息。

    3)接收到ping消息的节点用pong消息作为相应。

    集群中每个节点通过一定规则挑选要通信的节点,每个节点可能知道全部节点,也可能仅知道部分节点,只要这些节点彼此可以正常通信,最终它们会达到一致的状态。当节点出故障、新节点加入、主从角色变化、槽信息变更等时间发生时,通过不断的ping/pong消息通信,经过一段时间后所有的节点都会知道整个集群全部节点的最新状态,从而达到集群状态同步的目的。

  2. Gossip消息

    Gossip协议的主要职责就是信息交换。信息交换的载体就是节点彼此发送的Gossip消息,了解这些消息有助于我们理解集群如何完成信息交换。

    常用的Gossip消息可分为:ping消息、pong消息、meet消息、fail消息等。

    • meet消息:用于通知新节点加入。消息发送者通知接收者加入到当前集群,meet消息通信正常完成后,接收节点会加入到集群中并进行周期性的ping、pong消息交换。

    • ping消息:集群内交换最频繁的消息,集群内每个节点每秒向多个其他节点发送ping消息,用于检测节点是否在线和交换彼此状态信息。ping消息发送封装了自身节点和部分其他节点的状态数据。

    • pong消息:当接收到ping、meet消息时,作为响应消息回复给发送方确认消息正常通信。pong消息内部封装了自身状态数据。节点也可以向集群内广播自身的pong消息来通知整个集群对自身状态进行更新。

    • fail消息:当节点判定集群内另一个节点下线是,会向集群内广播一个fail消息,其他节点接收到fail消息之后吧对应节点更新为下线状态。

    所有的消息格式划分为:消息头和消息体。消息头包含发送节点自身状态数据,接收节点根据消息头就可以获取到发送节点的相关数据,结构如下:

    typedef struct {
        char sig[4]; /* 信号标示 */
        uint32_t totlen; /* 消息总长度 */
        uint16_t ver; /* 协议版本 */
        uint16_t type; /* 消息类型,用于区分meet,ping,ping等消息 */
        uint16_t count; /* 消息体包含的节点数量,仅用于meet,ping,pong消息类型 */
        uint64_t currentEpoch; /* 当前发送节点的配置纪元 */
        uint64_t configEpoch; /* 主节点/从节点的主节点配置纪元 */
        uint64_t offset; /* 复制偏移量 */
        char sender[CLUSTER_NAMELEN]; /* 发送节点的nodeId */
        unsigned char myslots[CLUSTER_SLOTS/8]; /* 发送节点负责的槽信息 */
        char slaveof[CLUSTER_NAMELEN]; /* 如果发送节点是从节点,记录对应主节点的nodeId */
        uint16_t port; /* 端口号 */
        uint16_t flags; /* 发送节点标识,区分主从角色,是否下线等 */
        unsigned char state; /* 发送节点所处的集群状态 */
        unsigned char mflags[3]; /* 消息标识 */
        union clusterMsgData data; /* 消息正文 */
    } clusterMsg;
    

    集群内所有的消息都采用相同的消息头结构clusterMsg,它包含了发送节点关键信息,如节点id、槽映射、节点标识(主从角色,是否下线)等。消息体在Redis内部采用clusterMsgData结构声明,结构如下:

    union clusterMsgData {
        /* ping,meet,pong 消息体 */
        struct {
            /* gossip消息结构数组 */
            clusterMsgDataGossip gossip[1];
        } ping;
        /* FAIL 消息体 */
        struct {
            clusterMsgDataFail about;
        } fail;
    // ...
    };
    

    消息体clusterMsgData定义发送消息的数据,其中ping、meet、pong都采用clusterMsgDataGossip数组作为消息体数据,实际消息类型使用消息头的type属性区分。每个消息体包含该节点的多个clusterMsgDataGossip结构数据,用于信息交换,结构如下:

    typedef struct {
        char nodename[CLUSTER_NAMELEN]; /* 节点的nodeId */
        uint32_t ping_sent; /* 最后一次向该节点发送ping消息时间 */
        uint32_t pong_received; /* 最后一次接收该节点pong消息时间 */
        char ip[NET_IP_STR_LEN]; /* IP */
        uint16_t port; /* port */
        uint16_t flags; /* 该节点标识 */
    } clusterMsgDataGossip;
    

    当接收到ping、meet消息时,接收节点会解析消息内容并根据自身的识别情况作出相应处理,执行解析消息头和消息体的流程:

    • 解析消息头过程:消息头包含了发送节点的信息,如果发送节点是新节点且消息是meet类型,则加入本地节点列表;如果是已知节点,则尝试更新发送节点的状态,如槽映射关系、主从角色等状态。

    • 解析消息体过程:如果消息体的clusterMsgDataGossip数组包含的节点是新节点,则尝试发起与新节点的meet握手流程;如果是已知节点,则根据clusterMsgDataGossip中的flags字段判断该节点是否下线,用于故障转移。

    消息处理完后回复pong消息,内容同样包含消息头和消息体,发送节点接收到回复的pong消息后,采用类似的流程解析处理消息并更新与接收节点最后通信时间,完成那个一次消息通信。

  3. 节点选择

    虽然Gossip协议的信息交换机制具有天然的分布式特性,但它是有成本的。由于内部需要频繁地进行节点信息交换,而ping/pong消息会携带当前节点和部分其他节点的状态数据,势必会加重带宽和计算的负担。Redis集群内节点通信采用固定频率(定时任务每秒执行10次)。因此节点每次选择需要通信的节点列表变得非常重要。通信节点选择过多虽然可以做到信息及时交换但成本过高。节点选择过少会降低集群内所有节点彼此信息交换频率,从而影响故障判定、新节点发现等需求的速度。因此Redis集群Gossip协议需要兼顾信息交换实时性和成本开销。

    消息交换的成本主要体现在单位时间选择发送消息的节点数量和每个消息携带的数据量。

    1. 选择发送消息的节点数量

      集群内每个节点维护定时任务默认每秒执行10次,每秒会随机选取5个节点找出最久没有通信的节点发送ping消息,用于保证Gossip信息交换的随机性。每100毫秒都会扫描本地节点列表,如果发现节点最近一次接收pong消息的时间大于cluster_node_timeout/2,则立刻发送ping消息,防止该节点的信息太长时间未更新。根据以上规则的出每个节点每秒需要发送ping消息的数量=1 + 10 * num(node.pong_received > cluster_node_timeout/2),因此cluster_node_timeout参数对消息发送的节点数量影响非常大。当我们的带宽资源紧张是,可以适当调大这个参数,如从默认15秒改为30秒来减低带宽占用率。过度调大cluster_node_timeout会影响消息交换的频率从而影响故障转移、槽信息更新、新节点发现的速度。因此需要根据业务容忍度和资源消耗进行平衡。同时整个集群消息总交换量也跟节点数成正比。

    2. 消息数据量

      每个ping消息的数据量体现在消息头和消息体中,其中消息头主要占用空间的字段是myslots[CLUSTER_SLOTS/8],占用2KB,这块空间占用相对固定。消息体会携带一定数量的其他节点信息用于信息交换。具体数量见一下伪代码:

      def get_wanted():
          int total_size = size(cluster.nodes)
          # 默认包含节点总量的1/10
          int wanted = floor(total_size/10);
          if wanted > 3:
              # 至少携带3个其他节点信息
              wanted = 3;
          if wanted > total_size - 2 :
              # 最多包含total_size - 2 个
              wanted = total_size - 2;
      return wanted;
      

      根据伪代码可以看出消息体携带数据量跟集群的节点数息息相关,更大的集群每次消息通信的成本也就更高,因此对于Redis集群来说并不是大而全的集群更好,对于集群规模控制的建议在后面的章节会介绍。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342