天天看点

HTTP和RPC的关系分析

RPC由来:

RPC 风格对应的是 Restful风格。 出发点: RPC 的含义来看(远程过程调用) ,认为只要实现远程调用即可,实现的方式可以是HTTP基于应用层的协议,也可以是Socket基于传输层协议 因为Socket编程是比较复杂的,所以Dubbo在Socket编程方面是用的Netty来实现。所以RPC只是一种风格。 举一个例子: 谷歌的grpc框架,底层就是基于Http2.0 来实现。区别的话,有人认为http不属于rpc体系,基于socket的tcp方式通信的才算rpc。然而rpc的原理就是。a主机去访问b主机获取相应信息。所以http妥妥的属于rpc的一种,rpc是概念,http是实现方式的一种。

RPC要解决的两个问题:

  1. 解决分布式系统中,服务之间的调用问题。
  2. 远程调用时,要能够像本地调用一样方便,让调用者感知不到远程调用的逻辑。

HTTP与RPC的关系:

http与rpc: HTTP 调用其实也是一种特殊的 RPC,HTTP协议可以认为是RPC传输协议的一个子集。HTTP1.0 协议时,HTTP 调用还只能是短链接调用,一个请求来回之后连接就会关闭。HTTP1.1 在 HTTP1.0 协议的基础上进行了改进,引入了 KeepAlive 特性可以保持 HTTP 连接长时间不断开,以便在同一个连接之上进行多次连续的请求,进一步拉近了 HTTP 和 RPC 之间的距离。当 HTTP 协议进化到 2.0 之后,Google 开源了一个建立在 HTTP2.0 协议之上的通信框架直接取名为 gRPC,也就是 Google RPC,这时 HTTP 和 RPC 之间已经没有非常明显的界限了。其实http是最常用的承载RPC的通信协议之一。而且我们可以在http 上传输xml和json这样的文本协议,也可以是protobuf和thrift这样的二进制协议,这都不是问题。大家常用的REST api就可以很好的封装成rpc。当然,http这种协议是笨重一些,但它的穿透性比较好,配套的设施也齐全,也比较简单直观。

IPC与RPC: 如果两个子系统没有在网络上进行分离,而是运行在同一个操作系统实例之上的两个进程时,它们之间的通信手段还可以更加丰富。除了以上提到的几种分布式解决方案之外,还有共享内存、信号量、文件系统、内核消息队列、管道等,本质上都是通过操作系统内核机制来进行数据和消息的交互而无须经过网络协议栈。但在现代企业服务中,这种单机应用已经非常少见了,因为单机应用意味着单点故障 —— “一人摔跤全家跌倒”。业务子系统往往都需要经物理网络栈进行隔离,因此分布式解决方案在要求高可用无间断服务的企业环境里便大有作为,这也让 RPC 迎来自己大放异彩的时代。

为什么有的RPC框架会自定义 tcp 协议而不是http协议的 rpc 做后端进程通信?

RPC是一种技术的概念名词,RPC=Remote Produce Call 是一种技术的概念名词,HTTP是一种协议,RPC可以通过 HTTP 来实现,也可以通过Socket自己实现一套协议来实现。为何 RPC 还有除 HTTP 之外的实现法,有何必要,毕竟除了HTTP实现外,私有协议不具备通用性。要解决这个问题就应该搞清楚 http 使用的 tcp 协议,和我们自定义的 tcp 协议在报文上的区别。首先要否认一点 http 协议相较于自定义tcp报文协议,增加的开销在于连接的建立与断开。http协议是支持连接池复用的,也就是建立一定数量的连接不断开,并不会频繁的创建和销毁连接。二一要说的是http也可以使用protobuf这种二进制编码协议对内容进行编码,因此二者最大的区别还是在传输协议上。通用定义的http1.1协议的tcp报文包含太多废信息,一个POST协议的格式大致如下

HTTP/1.0 200 OK 
Content-Type: 
Content-Length: 12343
Expires: 
Last-Modified:
Server: 
           

即使编码协议也就是body是使用二进制编码协议,报文元数据也就是header头的键值对却用了文本编码,非常占字节数。如上图所使用的报文中有效字节数仅仅占约 30%,也就是70%的时间用于传输元数据废编码。当然实际情况下报文内容可能会比这个长,但是报头所占的比例也是非常可观的。那么假如我们使用自定义tcp协议, 报头占用的字节数也就只有16个byte,极大地精简了传输内容。这也就是为什么后端进程间通常会采用自定义tcp协议的rpc来进行通信的原因。

自定义RPC传输协议与http区别:

  1. 自定义TCP传输协议在第四层,不用到osi的第七层,简化传输协议。
  2. 自定义TCP传输协议传输数据少了冗余数据。传输时间短,性能高。
  3. tcp支持长链接。
  4. 支持的数据类型多
  5. rpc传输的是二进制,http传输的是文本,就拿数字类型来说,http传输的是字符串,但是rpc传输的内容几个字节,数据量就更少了
  6. rpc的缺点:修改协议麻烦,服务端修改协议很可能会导致客户端调用失败。
  7. http普适度高。特别适用于web服务。基于应用级的接口使用方便,要求的开发水平不高,容错性强。但是传输速度慢,数据包大,如实现实时交互,服务器性能压力大,数据传输安全性差。
  8. 速度来看,RPC要比http更快,虽然底层都是TCP,但是http协议的信息往往比较臃肿;难度来看,RPC实现较为复杂,http相对比较简单;灵活性来看,http更胜一筹,因为它不关心实现细节,跨平台、跨语言。

应用场景:

  • 如果对效率要求更高,并且开发过程使用统一的技术栈,那么用RPC还是不错的。
  • 如果需要更加灵活,跨语言、跨平台,显然http更合适
  • 微服务,更加强调的是独立、自治、灵活。而RPC方式的限制较多,因此微服务框架中,有大部分会采用基于Http的Rest风格服务。

RPC与HTTP收发包

TCP/IP协议中针对TCP默认开启了Nagle算法。Nagle算法通过减少需要传输的数据包,提高网络的利用率,来优化网络。rpc协议按照协议帧格式从tcp缓冲区读取协议帧大小的帧数据,解压到responpacket结构体。

for !c.isClosed {

		// 检查上游是否关闭
		select {
		case <-c.ctx.Done():
			return
		default:
		}
...
		req, err := c.fr.ReadFrame()
...
}
           

RPC(包含http)都是基于tcp发送/接收缓冲区的收发包:

  • 发送端发送数据,数据先通过网卡到服务端tcp的receive buffer中。服务端的上层应用如果需要读取数据,会申请一段业务buffer,调用JDK的IO接口,IO会将tcpreceive buffer的数据拷贝到业务的buffer里面。上层业务再通过设定的反序列化协议将业务buffer转换成对象进行业务处理。
  • 服务端读取数据时,先申请一段业务buffer(大小一般是1k),通过调用JDK的channel.read(buffer) IO方法,IO会将tcp buffer的数据拷贝到业务buffer里面。返回值为读取字节的个数:如果返回值大于0,说明读取到了对应大小的数据;如果是0,表示没有读到数据,数据读取完成(可能业务buffer是满的,不能往里面写数据);如果是-1,代表tcp连接被关闭(一般处理是关闭到该连接)