分布式系统间通信的常见方式有两种,一种是消息通信,比如JMS,RocketMQ等,一种是RPC远程调用。我们先来看一下通信的基础知识,然后主要来看一下RPC远程调用,消息通信大家可以参考我的下一篇文章——分布式常见问题总结(五)- 消息队列。
1.传输协议 - HTTP,TCP,UDP
看下面的图,网络通信按照OSI参考模型分为七层,按照TCP/IP模型分为五层。我们关注的应用层协议有HTTP,Telnet,FTP,TFTP,DNS,SMTP协议。传输层的协议有TCP,UDP。
我们来区分下下面几个概念:
HTTP:超文本传输协议,应用层协议,基于传输层协议TCP。
TCP:面向连接的传输控制协议,传输层协议。通信前需要建立可靠的连接。
UDP:面向无连接的用户数据报协议,传输层协议。通信前不需要建立连接。
SOCKET:不是协议,是TCP或者UDP协议的具体实现API。
短连接:建立连接,发送完数据,关闭连接,TCP可以实现短连接,因为HTTP基于TCP,也可实现短连接。对于传输数据不频繁的情况下用短连接。
长连接:建立连接,发送完数据,保持连接一段时间,TCP可以实现长连接,因为HTTP基于TCP,也可实现长连接。对于传输数据频繁的情况下用长连接。
TCP三次握手四次挥手
TCP通信之前需要建立连接,我们来简单的了解下。
SYN:同步序号
ACK:应答回复
三次握手:
a.客户端 -> 服务器,发送SYN请求连接。
b.服务器 ->客户端,发送ACK确认收到请求,发送SYN是否准备好连接。 (这里的ACK应答回复和SYN同步序号是一起发送的)
c.客户端 -> 服务器,发送ACK确认可以建立连接和通信。
四次挥手:
a.客户端 -> 服务器,发送SYN请求关闭连接。
b.服务器 -> 客户端,发送ACK确认收到请求,关闭客户端到服务器的连接。
c.服务器 -> 客户端,发送SYN请求关闭连接。
d.客户端 -> 服务器,发送ACK确认收到请求,关闭服务器到客户端的连接。
b和c不同同时发送的原因是TCP连接是双向的,服务器需要等到服务器这边没有数据发送才发送SYN请求关闭连接。ACK和SYN不能同时发送,所以挥手是四次。
2.网络IO
上面讲了通信协议,基于通信协议有三种通信方式:BIO,NIO,AIO。
首先BIO,NIO,AIO都是基于socket套接字来通信的,socket是传输层协议TCP/UDP的具体实现。
BIO:同步阻塞IO,每一个Socket使用一个线程来通信。阻塞表现在,主线程调用write()方法后,不能做其他事情,阻塞了,等待返回。
NIO:同步非阻塞IO,采用Reactor模式,使用一个线程来管理所有的Socket,简单来说,Channel注册到Selector,一个线程来遍历Selector通过Channel来通信。Channel通信是基于Socket. 有通信的时候会处理。非阻塞表现在,主线程不会阻塞,会有单独的一个线程来处理接受读操作。同步表现在,如果一个Socket通信有问题,会影响其它的Socket通信。
AIO:异步IO,采用Proactor模式,另外开线程来通信,通信完成会调用类似的回调函数来通知。我们不用单独建立线程来处理通信,Java自己会建立一个线程池处理通信,并回调对应的方法。多个通信之间不会互相影响。
3.RPC远程调用
RPC(Remote Procedure Call)的含义简单的来说,RPC是进程间通信的一种方式,它让我们可以向访问远程接口像本地接口一样。它帮助我们隐藏调用的细节。
RPC调用需要考虑的两个关键问题
a.远程通信协议的选择,例如Http,基于TCP或者UDP的socket等。
b.数据传输的格式,例如Java Object,xml,json,binary等。
基于通信协议和数据传输格式的选择,出现了很多RPC框架,下面我们来一个个看一下。
a.RMI(远程方法调用)
RMI是Java定制的远程方法调用。通信是基于socket的通信,数据传输的格式是Java Object,所以传输的对象必须序列化,导致了RMI只适合两个Java应用程序的通信。通信大致过程如下:
Java Object -> 序列化 -> 远程传输(Socket) -> 反序列化 -> Java Object
b.XML-RPC,SOAP,WebService
通信是基于Http的通信,数据传输格式是XML。所以这个通信架构是可以跨语言的。通信大致过程如下:
需要传输的对象 -> XML -> 远程传输(Http) -> 解析XML -> 需要传输的对象
c.binary-RPC, hessian
通信是基于Http的通信,数据传输格式是二进制格式。所以这个通信架构是可以跨语言的。通信大致过程如下:
需要传输的对象 -> 二进制格式 -> 远程传输(Http) -> 解析二进制 -> 需要传输的对象
d.我们可以自己实现一个简单的RPC框架
通信可以基于Http,可以使用java提供的Httpclient来通信,数据传输格式可以是Json。通信大致过程如下:
需要传输的对象 -> Json -> 远程传输(Http) -> 解析Json -> 需要传输的对象
现在应用直接的通信架构太多了,我们学习一个应用间通信架构可以主要关注他的通信协议和数据传输格式。