网关层技术架构中的HTTPRPC和gRPC

Posted 黑黑白白君

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网关层技术架构中的HTTPRPC和gRPC相关的知识,希望对你有一定的参考价值。

文章目录


工作中经常需要看看技术架构图,网上随便找一个图(图源http://dockone.io/article/696771):

会发现服务与网关/服务之间的关联会写RPC、HTTP,于是想要整理一下这两者的区别。

1)HTTP是什么?

HTTP 是一个协议,是一个超文本传输协议。

  • 注意:它是基于 TCP/IP 来传输文本、图片、视频、音频等。即HTTP 不提供数据包的传输功能,数据包从浏览器到服务端再来回的传输和它没关系,这是 TCP/IP 干的。

HTTP 的本质是是客户端和服务端约定好的一种通信格式

详细梳理可移步《【计算机网络】测试人关于HTTP的学习和梳理》


2)RPC是什么?

RPC(Remote Procedure Call)远程过程调用,简单的理解是一个节点请求另一个节点提供的服务,是分布式系统常见的一种通信方法。它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节。

  • 除 RPC 之外,常见的多系统数据交互方案还有分布式消息队列、HTTP 请求调用、数据库和分布式缓存等。
  • 其中 RPC 和 HTTP 调用是没有经过中间件的,它们是端到端系统的直接数据交互。

本地过程调用 VS. 远程过程调用

像之前的单体时代,我们的 service 调用就是自己实现的方法,是本地进程内的调用:
    public User getUserById(Long id) 
       return userDao.getUserById(id); // 这叫本地调用
     
现在都是微服务了,根据业务模块做了不同的拆分,像用户的服务不用我这个小组负责,我这小组只要写订单服务就行了。但是我们服务需要用到用户的信息,于是我们需要调用用户小组的服务,于是代码变成了以下这种:
    public User getUserById(Long id) 
       return userConsumer.getUserById(id); // 这是远程调用,逻辑是用户小组的服务实现的。
     

可以看到 RPC 就是通过网络进行远程调用,订单服务其实就是客户端,而用户服务是服务端。

  • 本地过程调用:如果需要将本地student对象的age+1,可以实现一个addAge()方法,将student对象传入,对年龄进行更新之后返回即可,本地方法调用的函数体通过函数指针来指定

远程过程调用:上述操作的过程中,如果addAge()这个方法在服务端,执行函数的函数体在远程机器上,如何告诉机器需要调用这个方法呢?

  1. 首先客户端需要告诉服务器,需要调用的函数,这里函数和进程ID存在一个映射,客户端远程调用时,需要查一下函数,找到对应的ID,然后执行函数的代码。
  2. 客户端需要把本地参数传给远程函数,本地调用的过程中,直接压栈即可,但是在远程调用过程中不再同一个内存里,无法直接传递函数的参数,因此需要客户端把参数转换成字节流,传给服务端,然后服务端将字节流转换成自身能读取的格式,是一个序列化和反序列化的过程
  3. 数据准备好了之后,如何进行传输?网络传输层需要把调用的ID和序列化后的参数传给服务端,然后把计算好的结果序列化传给客户端,因此TCP层即可完成上述过程。gRPC中采用的是HTTP2协议。

远程过程调用也涉及到了交互,所以也需要约定一个格式,至于要不要用 HTTP 这个格式,就是大家自己看着办。RPC 和 HTTP 的之间的关系也清楚了。


为什么要有RPC?

常听到什么什么之间是 RPC 调用的,那你有没有想过为什么要 RPC, 我们直接 WebClient HTTP 调用不行么?

其实 **RPC 调用是因为服务的拆分,或者本身公司内部的多个服务之间的通信**。
  • 服务的拆分独立部署,那服务间的调用就必然需要网络通信,用 WebClient 调用当然可行,但是比较麻烦。我们想即使服务被拆分了但是使用起来还是和之前本地调用一样方便。所以就出现了 RPC框架,来屏蔽这些底层调用细节,使得我们编码上还是和之前本地调用相差不多。

  • 并且 HTTP 协议比较的冗余,RPC 都是内部调用所以不需要太考虑通用性,只要公司内部保持格式统一即可。所以可以做各种定制化的协议来使得通信更高效。所以公司内部服务的调用一般都用RPC,而 HTTP 的优势在于通用,大家都认可这个协议。所以三方平台提供的接口都是通过 HTTP 协议调用的

RPC框架实现原理

原理图:

时序图:

RPC整个调用过程,主要经历如下几个步骤:

1、建立通信:

A机器想要调用B机器,首先得建立起通信连接。主要是通过在客户端和服务器之间建立TCP连接,远程过程调用的所有交换的数据都在这个连接里传输

  • 连接可以是按需连接,调用结束后就断掉,也可以是长连接,多个远程过程调用共享同一个连接。

2、服务寻址:

要解决寻址的问题,也就是说,A服务器上的应用怎么告诉底层的RPC框架,如何连接到B服务器(如主机或IP地址)以及特定的端口,方法的名称名称是什么

  • 通常情况下我们需要提供B机器(主机名或IP地址)以及特定的端口,然后指定调用的方法或者函数的名称以及入参出参等信息,这样才能完成服务的一个调用。

  • 可靠的寻址方式(主要是提供服务的发现)是RPC的实现基石,比如可以采用redis或者zookeeper来注册服务等等。

在RPC框架中主要有三个角色:提供者、消费者和注册中心。

  • 提供者: 暴露服务的服务提供方。
  • 调用者: 调用远程服务的服务消费方。
  • 注册中心: 服务注册与发现的注册中心。

从服务提供者的角度看:
1、当提供者服务启动时,需要自动向注册中心注册服务;
2、当提供者服务停止时,需要向注册中心注销服务;
3、提供者需要定时向注册中心发送心跳,一段时间未收到来自提供者的心跳后,认为提供者已经停止服务,从注册中心上摘取掉对应的服务。

从调用者的角度看:
1、调用者启动时订阅注册中心的消息并从注册中心获取提供者的地址;
2、当有提供者上线或者下线时,注册中心会告知到调用者;
3、调用者下线时,取消订阅。

3、网络传输:

序列化:

  • 当A机器上的应用发起一个RPC调用时,调用方法和其入参等信息需要通过底层的网络协议如TCP传输到B机器
  • 由于网络协议是基于二进制的,所有我们传输的参数数据都需要先进行序列化(Serialize)或者编组(marshal)成二进制的形式才能在网络中进行传输。然后通过寻址操作和网络传输将序列化或者编组之后的二进制数据发送给B机器。

反序列化:

  • 当B机器接收到A机器的应用发来的请求之后,又需要对接收到的参数等信息进行反序列化操作(序列化的逆操作),即将二进制信息恢复为内存中的表达方式
  • 然后再找到对应的方法(寻址的一部分)进行本地调用(一般是通过生成代理Proxy去调用,通常会有JDK动态代理、CGLIB动态代理、Javassist生成字节码技术等),之后得到调用的返回值。

4、服务调用:

B机器进行本地调用(通过代理Proxy)之后得到了返回值,此时还需要再把返回值发送回A机器,

  • 同样也需要经过序列化操作,然后再经过网络传输将二进制数据发送回A机器,
  • 而当A机器接收到这些返回值之后,则再次进行反序列化操作,恢复为内存中的表达方式,
  • 最后再交给A机器上的应用进行相关处理(一般是业务逻辑处理操作)。

常见的RPC框架

  • gRPC :gRPC是可以在任何环境中运行的现代开源高性能RPC框架。它可以通过可插拔的支持来有效地连接数据中心内和跨数据中心的服务,以实现负载平衡,跟踪,运行状况检查和身份验证。它也适用于分布式计算的最后一英里,以将设备,移动应用程序和浏览器连接到后端服务。
  • Thrift:thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发。它结合了功能强大的软件堆栈和代码生成引擎,以构建在 C++, Java, Python, php, Ruby, Erlang, Perl, Haskell, C#, Cocoa, javascript, Node.js, Smalltalk, and OCaml 这些编程语言间无缝结合的、高效的服务。
  • Dubbo:Dubbo是一个分布式服务框架,以及SOA治理方案。其功能主要包括:高性能NIO通讯及多协议集成,服务动态寻址与路由,软负载均衡与容错,依赖分析与降级等。Dubbo是阿里巴巴内部的SOA服务化治理方案的核心框架,Dubbo自2011年开源后,已被许多非阿里系公司使用。
  • Spring Cloud:Spring Cloud由众多子项目组成,如Spring Cloud Config、Spring Cloud Netflix、Spring Cloud Consul
    等,提供了搭建分布式系统及微服务常用的工具,如配置管理、服务发现、断路器、智能路由、微代理、控制总线、一次性token、全局锁、选主、分布式会话和集群状态等,满足了构建微服务所需的所有解决方案。Spring Cloud基于Spring Boot, 使得开发部署极其简单。

3)HTTP和RPC的区别

  • HTTP是一种协议,而RPC是一种框架
  • RPC 只是一种概念、一种设计,就是为了解决不同服务之间的调用问题, 它一般会包含有传输协议序列化协议这两个,实现 RPC 的传输协议可以直接建立在 TCP 之上,也可以建立在 HTTP 协议之上
  • 大部分 RPC 框架都是使用的 TCP 连接(gRPC使用了HTTP2)

一个常见的错误观点: HTTP 协议相较于自定义 TCP 报文协议,增加的开销在于连接的建立与断开

首先要否认一点 HTTP 协议相较于自定义 TCP 报文协议,增加的开销在于连接的建立与断开。
  • HTTP 协议是支持连接池复用的,也就是建立一定数量的连接不断开,并不会频繁的创建和销毁连接。
  • HTTP 也可以使用 Protobuf 这种二进制编码协议对内容进行编码,因此二者最大的区别还是在传输协议上


4)gRPC与REST

REST通常以业务为导向,将业务对象上执行的操作映射到HTTP动词,格式非常简单,可以使用浏览器进行扩展和传输,通过JSON数据完成客户端和服务端之间的消息通信,直接支持请求/响应方式的通信。不需要中间的代理,简化了系统的架构,不同系统之间只需要对JSON进行解析和序列化即可完成数据的传递

  • 但是REST也存在一些弊端,比如只支持请求/响应这种单一的通信方式,对象和字符串之间的序列化操作也会影响消息传递速度,客户端需要通过服务发现的方式,知道服务实例的位置,在单个请求获取多个资源时存在着挑战,而且有时候很难将所有的动作都映射到HTTP动词。

正是因为REST面临一些问题,因此可以采用gRPC作为一种替代方案,grpc是谷歌开源的一个 RPC 框架,面向移动和 HTTP/2 设计。

gRPC 是一种基于二进制流的消息协议,可以采用基于Protocol Buffer的IDL定义grpc API,这是Google公司用于序列化结构化数据提供的一套语言中立的序列化机制,客户端和服务端使用HTTP/2以Protocol Buffer格式交换二进制消息

  • gRPC的优势是,设计复杂更新操作的API非常简单,具有高效紧凑的进程通信机制,在交换大量消息时效率高,远程过程调用和消息传递时可以采用双向的流式消息方式,同时客户端和服务端支持多种语言编写,互操作性强;不过gRPC的缺点是不方便与JavaScript集成,某些防火墙不支持该协议。

gRPC的优势:

  • 性能:gRPC消息使用一种有效的二进制消息格式protobuf进行序列化。Protobuf在服务器和客户机上的序列化非常快。Protobuf序列化后的消息体积很小,能够有效负载,在移动应用程序等有限带宽场景中显得很重要。
  • 代码生成:所有gRPC框架都为代码生成提供了一流的支持。gRPC开发的核心文件是*.proto文件 ,它定义了gRPC服务和消息的约定。根据这个文件,gRPC框架将生成服务基类,消息和完整的客户端代码。
  • 严格的规范gRPC规范是规定有关gRPC服务必须遵循的格式。gRPC消除了争论并节省了开发人员的时间,因为gPRC在各个平台和实现之间是一致的。
  • 其他可参考:https://www.cnblogs.com/yilezhu/p/10645804.html

推荐使用gRPC的场景:

  • 微服务:gRPC设计为低延迟和高吞吐量通信。gRPC非常适用于效率至关重要的轻型微服务。
  • 点对点实时通信:gRPC对双向流媒体提供出色的支持。gRPC服务可以实时推送消息而无需轮询。
  • 多语言混合开发环境:gRPC工具支持所有流行的开发语言,使gRPC成为多语言开发环境的理想选择。
  • 网络受限环境:使用Protobuf(一种轻量级消息格式)序列化gRPC消息。gRPC消息始终小于等效的JSON消息。

gRPC的弱点:

  • 浏览器支持有限:当下,不可能直接从浏览器调用gRPC服务。gRPC大量使用HTTP/2功能,没有浏览器提供支持gRPC客户机的Web请求所需的控制级别。例如,浏览器不允许调用者要求使用的HTTP/2,或者提供对底层HTTP/2框架的访问。
  • 不是人类可读的:HTTP API请求以文本形式发送,可以由人读取和创建。默认情况下,gRPC消息使用protobuf编码。虽然protobuf的发送和接收效率很高,但它的二进制格式是不可读的。protobuf需要在*.proto文件中指定的消息接口描述才能正确反序列化。需要额外的工具来分析线路上的Protobuf有效负载,并手工编写请求。

不建议使用gRPC的场景:

  • 浏览器可访问的API:浏览器不完全支持gRPC。gRPC-Web可以提供浏览器支持,但它有局限性并引入了服务器代理。
  • 广播实时通信:gRPC支持通过流媒体进行实时通信,但不存在向已注册连接广播消息的概念。例如,在应该将新聊天消息发送到聊天室中的所有客户端的聊天室场景中,需要每个gRPC呼叫以单独地将新的聊天消息流传输到客户端。对于这种场景,SignalR是这种情况的有用框架。SignalR具有持久连接的概念和对广播消息的内置支持。
  • 进程间通信:进程必须承载HTTP/2服务才能接受传入的gRPC调用。对于Windows,进程间通信管道是一种快速,轻量级的通信方法。


【部分内容参考自】

  • HTTP 的本质?HTTP 和 RPC 的区别?:https://www.jianshu.com/p/fe5ccfc5d7bd
  • 什么是RPC?:https://www.jianshu.com/p/7d6853140e13
  • RPC三连问:什么是RPC框架?实现原理呢?与SOA、REST有啥区别?:https://www.jianshu.com/p/210c34970529
  • 服务之间的调用为啥不直接用 HTTP 而用 RPC?:https://network.51cto.com/art/202001/609479.htm
  • 进行API开发选gRPC还是HTTP APIs?:https://www.cnblogs.com/yilezhu/p/10645804.html

以上是关于网关层技术架构中的HTTPRPC和gRPC的主要内容,如果未能解决你的问题,请参考以下文章

网关层技术架构中的HTTPRPC和gRPC

gRPC 网关,针对 HTTP 2.0 长连接性能优化,提升吞吐量

网关层了解软件架构中的网关层

protoc生成gRPC代码和HTTP网关代码

protoc生成gRPC代码和HTTP网关代码

protoc生成gRPC代码和HTTP网关代码