WorldCloud 工厂模式 random soap graph eloquent parameters constructor vbscript routes npm安装vue ai视频教程下载 eclipse闪退 mysql小数用什么类型 android逆向工程师 js对象添加元素 matlab网页版 matlab图像滤波 python数据类型转换 flutter 缺点 mysql入门 表白网页源码 python如何实现多线程 pythoninput python的编译器 python环境变量配置 java安装环境 java中class java时间转换 金山wps2003 pr滤镜插件 只狼脚本 千千静听老版本 ABViewer js验证码 奥法隐藏外观 udp测试工具 c4d挤压怎么用 ie拒绝访问 键盘指法练习游戏
当前位置: 首页 > 学习教程  > 编程语言

Redis源码思考 - Cluster节点之间的handshake

2020/8/11 20:24:53 文章标签:

Redis支持Cluster,那么必然要有一个协议来支撑这些Cluster node之间进行状态数据同步。Redis采用了gossip,关于gossip,网上有很多文章,可以去搜来看。gossip的特点是去中心化,并且尽量减小信息扩散带来的网络消息爆炸。

我理解的gossip,是一种分布式系统状态同步(扩散)的实现思想,我只搜到了的各种文章都是些gossip实现的算法。我没有看到gossip的标准协议,所以Redis的gossip应该是基于gossip思想的私有协议。

好,回到正题。gossip的基础,肯定是先要让不同的cluster node之间建立某种信任关系,这个过程在任何协议交互中几乎都叫做“handshake”。

一个简单的handshake其实非常简单,一个request-ack来回两个消息就可以达到握手的效果。

Redis的实现,其实也是这么简单的。它定义了两个消息PING和PONG,A给B发个PING,B给A回个PONG,就握手成功了。当然,在某些情况下,用MEET消息替代了PING。

不过,真要这么简单,我就不写这篇文章了。Redis有些地方的实现细节,确实需要多看几遍源码才能理解的。我们慢慢来分析。

 

Redis的通信模型

Redis的通信和大多数通信设备软件一样,是分层的,大同小异。

最底层是POSIX SOCKET,当然下面还有操作系统,被封装了,我们不管。Redis实现了一个Connect层,该层封装了socket的概念,并且屏蔽了不同操作系统之间的一些差异,这是个公共模块,凡是要用到socket通信的都可以基于Connect。

Cluster再封装了一层叫ClusterLink,它和ClusterNode关联(也可以不关联,后面会讲),同时提供了消息收发的buf操作。

所以,Redis Cluster之间通信的模型就很清晰了,ClusterNode-Link-Conn-socket,层层上送层层下发。

 

handshake过程详解

了解了上面的通信模型,那么如何打通两个NODE之间的通信通路呢?我们很自然地能想到,首先得要TCP/IP层打通,也就是socket要建立好。这样就行了吗?当然不行,我们的通信模型是要实现业务层面的通信,那么业务层面肯定是要有一个协议交换过程的,这个过程其实就是handshake。

所以,本质上来说,我们的MEET\PING\PONG,这些是业务层的协议过程。和socket得分开看。

我们先想想,如果你来实现这个代码,你的socket会怎么设计呢?至少我最开始看代码的时候想当然地认为它的socket应该是完美对称的,像下面这样:

这样多好,每两个NODE之间创建一个socket,两两连接。完美,简单,合理。

我一开始其实也是抱着这个方案去看的代码(我最初看代码的时候是没有动手启动过Redis Cluster的,就是硬读代码),但是越读代码越感觉不对劲,很多逻辑都不通顺。后来总算抛弃了先入为主的思想,从头理了一遍,慢慢读懂了作者的用意。Redis两个ClutesrNode之间的socket并不是完美对称的,存在两个socket。我们以两个Node节点为例。

每两个NODE之间,存在两个socket来进行通信(注意,这里不包括那些个用于listen端口的socket)。Why??目前我没法解释清楚,看完下面的才行!

好,我们记住每两个NODE之间存在两个socket。下面我们先看看参与handshake过程的三个消息:

CLUSTERMSG_TYPE_MEET - 当你配置了cluster meet命令后,触发的handshake过程发的第一个业务消息就是meet。它发给对端node,告诉本node的存在,并让对端建立对应的node。

CLUSTERMSG_TYPE_PING - ping的主要作用的检查某个node是否还存活着,它和meet很像,但是对端不会保存本地为node。

CLUSTERMSG_TYPE_PONG - pong是meet和ping的回复应答消息。pong可以通告本端的状态,比如本端的node name、ip等。ping收到pong的话,认为节点还活着。

同时,上面三个消息参与gossip过程。它们除去消息头以外,会协议一个gossip section,里面包含本地节点存的若干个node信息。gossip就是这样扩散node状态的,它没有中心节点,所有节点每次随机选几个node发给其它节点,只要算法设计得好,整个cluster中的所有节点都能获取到全量的节点状态信息,实现整网同步。这是主备倒换、vote机制等的基础,后面文章我们再详细分析其实现细节。

 

好,我们继续handshake。

最简单的一个场景,用户在NodeA上面去meet NodeB,通过执行命令行 cluster meet ip port。

NodeA的执行过程如下:

1、解析命令行

2、触发handshake(clusterStartHandshake)。这里面主要做了两件事:创建ClusterNode、置node中的flag为CLUSTER_NODE_HANDSHAKE|CLUSTER_NODE_MEET。需要注意的是,这里并没有创建ClusterLink。同时这里创建的ClusterNode的name是一个随机值(假的name)。

3、ClusterCron会不停滴检查ClusterNode中是否有link为null的,第2步创建的这个肯定就命中了。然后给它创建link(假设这个socket为FD-A1),并且触发connect。

4、connect成功(clusterLinkConnectHandler),向对端发送一个CLUSTERMSG_TYPE_MEET。同时,关联ClusterNode和Link之间的关系。

5、收到NodeB的PONG消息。这时候能获取到NodeB的真实name,所以需要刷新一下。

6、NodeA这一端的handshake完成。

 

NodeB的执行过程如下:

1、在监听端口accept到NodeA的connect连接,生成一个新的socket(假设叫 FD-B1),注意这个socket和上面那个FD-A1是匹配的,是一对儿。NodeA发过来的meet消息,以及给回复的PONG消息,都是基于该socket。另外,这个FD-B1只会对应创建link,不会产生ClusterNODE。node在哪产生呢?答案是收到NodeA的meet消息时。但是一定要记住,这里创建的node并没有绑定FD-B1。这就是上面说的Redis通信模型没有完美对称的根源。

2、NodeB在收到MEET消息后,创建了一个link为null的ClusterNode。下面的流程你肯定也猜到了,和NodeA一毛一样,ClusterCron会遍历到这个node,创建link(注意,这是一个新的socket,假设叫FD-B2),并且触发connect。connect成功后,发送PING消息(注意这里是Ping不是MEET)。

3、收到A回复的PONG,更新本地的nodeb name。

4、NodeB这一端的handshake完成。

 

大家看明白了吗? 两个NODE之间其实是各自主动发起了一次handshake,并且建立了两对儿socket。

如何理解呢?

可以认为,socket有主动和被动之分,或者用在redis代码中提到的概念(incoming conn和outgoing conn)。我倾向于前者,好理解些。

主动socket - 主动发起Handshake过程(发起ping、meet)的一端拥有的socket。这个socket和node绑定。

被动socket - 被动参与handshake过程(回复pong)的一端拥有的socket。这个socket不和node绑定。

 

当NODE需要向其他node主动发送消息时,通过主动socket。被动socket则是被动接收消息,以及回复消息。你可能有疑问了,被动socket不是没有绑定node吗?如果回复消息中需要填充node信息怎么办? 答案是,被动socket只是说没有绑定node,并不代表它找不到node啊。它会通过消息头里面的name,去查找node(clusterLookupNode)。

 

如果让被动socket绑定node,是不是就只需要一对儿socket通信了呢?

这其实也是我很困惑的地方。理论上是完全没有问题的。比如在PONG后面再增加一个消息,这样双方都能握手,并且能获取到对方node的name。

这种不对称的设计还会带来一些看着不那么合理的现象,比如,如果其中一条link故障,而另外一条是好的。结果表现为,A认为B是pfail状态,而B认为A是ok的。 

也许是我考虑多了...

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


本文链接: http://www.dtmao.cc/news_show_100335.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?