2. 网络通信
在上一节,我们介绍了etcd
集群的启动过程。在其中也简单介绍了会初始化与其他成员节点通信的连接,以及启动为其他成员节点提供服务的GRPC
服务和Http
服务以及启动服务客户端的服务。本章我们将详细介绍通信相关的实现。
2.1 成员节点间通信(peer)
前一章节介绍了peer服务端启动过程。下面,我们来讲解下调用端是如何初始化以及如何调用的。
与成员节点间通信传输的初始化之前介绍过,是调用Transport.AddPeer
方法。
前面我们介绍了Transport
的作用:向成员节点发送raft消息,并从成员节点获取raft消息。下面将详细描述其作用。
首先来看其初始化和启动过程:
1 | tr := &rafthttp.Transport{ |
接下来,继续了解AddPeer
实现:
1 | Transport/AddPeer |
从上面的流程可以看出 peer
使用stream模式通信方式。读写分别用不同的协程去监听处理。其中streamWriter
负责消息发送,streamReader
负责消息接收。见下面详情:
1 | w := &streamWriter{ |
streamWriter
里比较关键的一点是,这里的conn
从哪来?往cw.connc
传递conn
的只有peer.attachOutgoingConn
方法。
而在上面初始化并启动peer
的时候是没有发现调用这个方法的 ???哪是哪里进行执行的呢?通过 追踪peer.attachOutgoingConn
的调用方,最终发现,其在rafthhtp/http.go/ServeHTTP() L483
处调用。而这个方法会在客户端建立连接进行http服务调用的时候执行。所以,在这里调用 peer.attachOutgoingConn
的作用是复用连接
。当我们分析完读处理过程后,再来整体看 etcd
节点是怎么建立通信链路的。
StreamReader
的处理比StreamWriter
的处理要简单一些。初始化完其属性后,调用start
方法启动监听读请求过程。
1 | StreamReader/start |
这样每个peer之间的链路就建立了。回过头来,可以看出每对peer
之间至少会有两条connection
。且他们之间交互交错使用。
单peer
往对方发送的消息,是通过 对方跟自己建立的连接 来发送的。
最后,我们通过单次请求响应过程,来介绍节点间的通信过程。
当要想集群其他成员节点发送消息时,最终会调用peer.send
方法:
1 | peer.send |
目标节点的 StreamReader(p.msgAppReader
)接收到消息后,通过解析后传递到 EtcdServer
(Process),即完成单次通信;对于请求的响应,则通过对方的peer
来发送给本节点,本节点的StreamReader
来接受响应消息。
2.2 客户端通信
对于客户端通信,因为是GRPC
或者HTTP
简单的请求响应方式,因此这里就不再介绍了。