《趣谈网络协议》微服务相关协议总结

1 RPC协议综述:ONC RPC为例


RPC需要解决五个问题:如何规定远程调用的语法?如果传递参数?如何表示数据?(前三个问题统称为协议问题)如何知道一个服务端都实现了哪些远程调用,从哪个端口可以访问这个远程调用?(服务发现问题)发生了错误、重传、丢包、性能等问题怎么办?(传输问题)

  • 协议问题

语法问题:RPC调用标准如下

 

比如基于RPC协议实现的NFS(Network File System,网格文件系统)可以在本地mount一个远程的目录到本地的一个目录,从而使得本地的用户在这个目录里面写入、读出任何文件的时候,其实操作的是远程另一台机器上的文件。

 

表示数据问题:XDR(External Data Representation,外部数据表示法)是一个标准的数据压缩格式,可以表示基本的数据类型,也可以表示结构体,用于编码和解码参数:

 

传递参数问题:在 RPC 的调用过程中,所有的数据类型都要封装成类似的格式。而且 RPC 的调用和结果返回,也有严格的格式:

为了可以成功调用 RPC,在客户端和服务端实现 RPC 的时候,首先要定义一个双方都认可的程序、版本、方法、参数等,格式类似上图;
有了协议定义文件,ONC RPC 会提供一个工具,根据这个文件生成客户端和服务器端的 Stub 程序,此程序最下层的是 XDR 文件,用于编码和解码参数,XDR文件是客户端和服务端共享的,因为只有双方一致才能成功通信;

最终的通信:客户端通过Stub的函数来调用RPC类库来真正发生请求,服务端将结果返回服务端的 Stub,服务端 Stub 程序发送结果给客户端,客户端的 Stub 程序正在等待结果,当结果到达客户端 Stub,就将结果返回给客户端的应用程序,从而完成整个调用过程。

  • 传输问题可以通过类库解决

  • 服务发现问题可以通过注册中心来解决

如下为内嵌在服务端的类似注册中心的portmapper:

 

当然也可以独立出来

2 基于XML的SOAP

原先的二进制RPC有很多缺点:格式要求严格,修改过于复杂,不面向对象,因此产生了基于文本的调用方式—基本XML的SOAP

  • 传输协议问题(HTTP)

SOAP为简单对象访问协议(Simple Object Access Protocol),使用XML编写简单的请求和回复消息,并用HTTP协议进行传输,多为POST

SOAP将请求和回复放在一个信封里面,就像传递一个邮件一样。信封里面的信分抬头和正文。

  • 协议约定问题(WSDL)

使用Web服务描述语言,即WSDL(Web Service Description Languages)。它也是一个XML文件,客户端根据WSDL来调用,有工具可以根据WSDL生成客户端Stub,让客户端通过Stub进行远程调用,就跟调用本地的方法一样。

  • 服务发现问题(UDDL)

UDDI(Universal Description, Discovery, and Integration),即统一描述、发现和集成协议。
它是一个注册中心,服务提供方可以将WSDL描述文件发布到这个注册中心,注册完毕后,服务使用方可以查找到服务的描述,封装为本地的客户端进行调用。

3 基于JSON的RESTFUL


SOAP过于复杂,而且设计是面向动作的,因而往往因为架构问题导致并发量上不去,因此用在企业内部中,互联网应用一般使用RESTFUL

  • 传输协议问题

xml格式改为使用Json来表示,且HTTP除了POST,把PUT、DELETE、GET等方法也使用上

  • 协议约定问题

以资源为核心,而不是以过程为核心,按照这种设计模式,RESTful API和SOAP API都可以将架构实现成无状态的,面向资源的、幂等的、横向扩展的、可缓存的。

但是SOAP的XML正文中,是可以放任何动作的。
例如XML里面可以写< ADD >,< MINUS >等。这就方便使用SOAP的人,将大量的动作放在API里面。

RESTful正文里的JSON基本描述的就是资源的状态,没办法描述动作,而且能够出发的动作只有CRUD,也即POST、GET、PUT、DELETE,也就是对于状态的改变,所以,从接口角度就阻止了动作;
不过也有很多技巧的方法,在使用RESTful API的情况下,依然提供基于动作的有状态请求,这就属于反模式了。

  • 服务发现问题

如Eureka、zookeeper,通过注册中心的方式来实现

4 二进制类RPC协议

文本的最大问题是占用字节数目比较多,因而对于数据中心内部的相互调用,一般采用更加省空间和带宽的二进制的方案,如Dubbo的二进制的RPC方式,默认使用Hession2,这是自描述的协议,综合了XML和二进制的优势;

通信方式和标准RPC类似:

 

当并发量越来越大,已经到了微服务的阶段的时候,同SOA不同,微服务粒度更细,模块之间的关系更加复杂。(可见微服务和微内核架构一文)

如上图架构,如果使用二进制的方式进行序列化,虽然不用协议文件来生成Stub,但是对于接口的定义,以及传的对象DTO,还是需要共享JAR。因为只有客户端和服务端都有这个JAR,才能成功地序列化和反序列化。

但当关系复杂的时候,JAR的依赖也变得异常复杂,难以维护,而且如果在DTO里加一个字段,双方的JAR没有匹配好,也会导致序列化不成功,而且还有可能循环依赖。

这个时候,一般有两种选择。第一种,建立严格的项目管理流程:

不允许循环调用,不允许跨层调用,只准上层调用下层,不允许下层调用上层。
接口要保持兼容性,不兼容的接口新添加而非改原来的,当接口通过监控,发现不用的时候,再下掉。
升级的时候,先升级服务提供端,再升级服务消费端。

第二种,改用RESTful的方式:

使用Spring Cloud,消费端和提供端不用共享JAR,各声明各的,只要能变成JSON就行,而且JSON也是比较灵活的。

使用RESTful的方式,性能会降低,所以需要通过横向扩展来抵消单机的性能损耗。

Dubbo是SOA时代的产物,底层使用Netty之类的NIO框架,基于TCP协议传输,配合以Hession序列化完成RPC通信。
SpringCloud基于Http协议+Restful接口调用实现远程过程的通信。

相对来说,Http请求会有更大的报文,占的带宽也会更多。但是REST相比RPC更为灵活,服务提供方和调用方的依赖只依靠一纸契约,不存在代码级别的强依赖,这在强调快速演化的微服务环境下,显得更为合适,至于注重通信速度还是方便灵活性,具体情况具体考虑。

5 跨语言类RPC协议


要求:

传输性能:服务之间的调用如此频繁了,还是二进制的越快越好。

跨语言:服务多了,什么语言写成的都有,而且不同的场景适宜用不同的语言,不能一个语言走到底。

最好既严谨又灵活,添加个字段不用重新编译和发布程序。

最好既有服务发现,也有服务治理,就像Dubbo和Spring Cloud一样。

GRPC正在努力完成这四个要求,,其二进制序列化协议是Protocol Bufers

GRPC序列化使用Protocol Bufers,网络传输使用HTTP 2.0,服务治理可以使用基于Envoy的Service Mesh。

Service Mesh:可以将应用之间的调用全部由中间层代理,服务之间的治理也是,到平台层解决,就成了Service Mesh,如GRPC的的Envoy:

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值