一、设计目标
RPC 框架的目标就是让远程服务调用更加简单、透明,RPC 框架负责屏蔽底层的传输方式(TCP 或者 UDP)、序列化方式(XML/Json/ 二进制)和通信细节。服务调用者可以像调用本地接口一样调用远程的服务提供者,而不需要关心底层通信细节和调用过程。
二、RPC的框架选择
三、gRPC
3.1、简介
gRPC是一个高性能、通用的开源RPC框架,其由Google 2015年主要面向移动应用开发并基于HTTP/2协议标准而设计,基于ProtoBuf序列化协议开发,且支持众多开发语言。
由于是开源框架,通信的双方可以进行二次开发,所以客户端和服务器端之间的通信会更加专注于业务层面的内容,减少了对由gRPC框架实现的底层通信的关注。
如下图,DATA部分即业务层面内容,下面所有的信息都由gRPC进行封装。
3.2、gRPC 特点
1、语言中立,支持多种语言;
2、基于 IDL 文件定义服务,通过 proto3 工具生成指定语言的数据结构、服务端接口以及客户端 Stub;
3、通信协议基于标准的 HTTP/2 设计,支持双向流、消息头压缩、单TCP的多路复用、服务端推送等特性,这些特性使得 gRPC 在移动端设备上更加省电和节省网络流量;
4、序列化支持 PB(Protocol Buffer)和 JSON,PB 是一种语言无关的高性能序列化框架,基于 HTTP/2 + PB, 保障了 RPC 调用的高性能。
3.3、交互过程
1、交换机在开启gRPC功能后充当gRPC客户端的角色,采集服务器充当gRPC服务器角色;
2、交换机会根据订阅的事件构建对应数据的格式(GPB/JSON),通过Protocol Buffers进行编写proto文件,交换机与服务器建立gRPC通道,通过gRPC协议向服务器发送请求消息;
3、服务器收到请求消息后,服务器会通过Protocol Buffers解译proto文件,还原出最先定义好格式的数据结构,进行业务处理;
4、数据处理完后,服务器需要使用Protocol Buffers重编译应答数据,通过gRPC协议向交换机发送应答消息;
5、交换机收到应答消息后,结束本次的gRPC交互。
简单地说,gRPC就是在客户端和服务器端开启gRPC功能后建立连接,将设备上配置的订阅数据推送给服务器端。我们可以看到整个过程是需要用到Protocol Buffers将所需要处理数据的结构化数据在proto文件中进行定义。
3.4、什么是Protocol Buffers?
你可以理解ProtoBuf是一种更加灵活、高效的数据格式,与XML、JSON类似,在一些高性能且对响应速度有要求的数据传输场景非常适用。ProtoBuf在gRPC的框架中主要有三个作用:
1、定义数据结构
2、定义服务接口
4、通过序列化和反序列化,提升传输效率
3.4.1、为什么ProtoBuf会提高传输效率呢?
我们知道使用XML、JSON进行数据编译时,数据文本格式更容易阅读,但进行数据交换时,设备就需要耗费大量的CPU在I/O动作上,自然会影响整个传输速率。Protocol Buffers不像前者,它会将字符串进行序列化后再进行传输,即二进制数据。
可以看到其实两者内容相差不大,并且内容非常直观,但是Protocol Buffers编码的内容只是提供给操作者阅读的,实际上传输的并不会以这种文本形式,而是序列化后的二进制数据。字节数会比JSON、XML的字节数少很多,速率更快。
3.4.2、如何支撑跨平台,多语言呢?
Protocol Buffers自带一个编译器也是一个优势点。前面提到的proto文件就是通过编译器进行编译的,proto文件需要编译生成一个类似库文件,基于库文件才能真正开发数据应用。具体用什么编程语言编译生成这个库文件呢?由于现网中负责网络设备和服务器设备的运维人员往往不是同一组人,运维人员可能会习惯使用不同的编程语言进行运维开发,那么Protocol Buffers其中一个优势就能发挥出来------跨语言。
从上面的介绍,我们得出在编码方面Protocol Buffers对比JSON、XML的优点:
1、简单,体积小,数据描述文件大小只有1/10至1/3;
2、传输和解析的速率快,相比XML等,解析速度提升20倍甚至更高;
3、可编译性强。
3.5、基于HTTP 2.0标准设计
除了Protocol Buffers之外,从交互图中和分层框架可以看到, gRPC还有另外一个优势------它是基于HTTP 2.0协议的。
由于gRPC基于HTTP 2.0标准设计,带来了更多强大功能,如多路复用、二进制帧、头部压缩、推送机制。这些功能给设备带来重大益处,如节省带宽、降低TCP连接次数、节省CPU使用等。gRPC既能够在客户端应用,也能够在服务器端应用,从而以透明的方式实现两端的通信和简化通信系统的构建。
HTTP 版本分为HTTP 1.X、 HTTP 2.0,其中HTTP 1.X是当前使用最广泛的HTTP协议,HTTP 2.0称为超文本传输协议第二代。HTTP 1.X定义了四种与服务器交互的方式,分别为:GET、POST、PUT、DELETE,这些在HTTP 2.0中均保留。HTTP 2.0的新特性:
1、双向流、多路复用
2、二进制帧
3、头部压缩
三、Thrift
3.1、Thrift 简介
thrift是一种可伸缩的跨语言服务的RPC软件框架。它结合了功能强大的软件堆栈的代码生成引擎,以建设服务,高效、无缝地在多种语言间结合使用。2007年由facebook贡献到apache基金,是apache下的顶级项目,具备如下特点:
1、支持多语言:C、C++ 、C# 、D 、Delphi 、Erlang 、Go 、Haxe 、Haskell 、Java 、JavaScript、node.js 、OCaml 、Perl 、PHP 、Python 、Ruby 、SmallTalk
2、消息定义文件支持注释,数据结构与传输表现的分离,支持多种消息格式
3、包含完整的客户端/服务端堆栈,可快速实现RPC,支持同步和异步通信
3.2、Thrift框架结构
Thrift是一套包含序列化功能和支持服务通信的RPC(远程服务调用)框架,也是一种微服务框架。其主要特点是可以跨语言使用,这也是这个框架最吸引人的地方。
1、图中code是用户实现的业务逻辑
2、接下来的 Service.Client和 write()/read()是thrift根据IDL生成的客户端和服务端的代码
3、对应于RPC中Client stub和Server stub。TProtocol 用来对数据进行序列化与反序列化,具体方法包括二进制,JSON 或者 Apache Thrift 定义的格式。
4、TTransport 提供数据传输功能,使用 Apache Thrift 可以方便地定义一个服务并选择不同的传输协议。
3.3、Thrift网络栈结构
thirft使用socket进行数据传输,数据以特定的格式发送,接收方进行解析。我们定义好thrift的IDL文件后,就可以使用thrift的编译器来生成双方语言的接口、model,在生成的model以及接口代码中会有解码编码的代码。thrift网络栈结构如下:
3.3.1、Transport层
代表Thrift的数据传输方式,Thrift定义了如下几种常用数据传输方式:
1、TSocket:阻塞式socket;
2、TFramedTransport:以frame为单位进行传输,非阻塞式服务中使用;
3、TFileTransport:以文件形式进行传输。
3.3.2、TProtocol层
代表thrift客户端和服务端之间传输数据的协议,通俗来讲就是客户端和服务端之间传输数据的格式(例如json等),thrift定义了如下几种常见的格式:
1、TBinaryProtocol: 二进制格式;
2、TCompactProtocol: 压缩格式;
3、TJSONProtocol: JSON格式;
4、TSimpleJSONProtocol: 提供只写的JSON协议。
3.3.3、Server模型
1、TSimpleServer: 简单的单线程服务模型,常用于测试;
2、TThreadPoolServer: 多线程服务模型,使用标准的阻塞式IO;
3、TNonBlockingServer: 多线程服务模型,使用非阻塞式IO(需要使用TFramedTransport数据传输方式);
4、THsHaServer: THsHa引入了线程池去处理,其模型读写任务放到线程池去处理,Half-sync/Half-async处理模式,Half-async是在处理IO事件上(accept/read/write io),Half-sync用于handler对rpc的同步处理;
四、gRPC VS Thrift
4.1、功能比较
直接贴上网上的两幅截图:
4.2、性能比较
也是基于网上测试的结果,仅供参考:
1、整体上看,长连接性能优于短连接,性能差距在两倍以上;
2、对比Go语言的两个RPC框架,Thrift性能明显优于gRPC,性能差距也在两倍以上;
3、对比Thrift框架下的的两种语言,长连接下Go 与C++的RPC性能基本在同一个量级,在短连接下,Go性能大概是C++的二倍;
4、对比Thrift&C++下的TSimpleServer与TNonblockingServer,在单进程客户端长连接的场景下,TNonblockingServer因为存在线程管理开销,性能较TSimpleServer差一些;但在短连接时,主要开销在连接建立上,线程池管理开销可忽略;
5、两套RPC框架,以及两大语言运行都非常稳定,5w次请求耗时约是1w次的5倍;
4.3、如何选型
什么时候应该选择gRPC而不是Thrift:
1、需要良好的文档、示例
2、喜欢、习惯HTTP/2、ProtoBuf
3、网络传输带宽敏感
什么时候应该选择Thrift而不是gRPC:
1、需要在非常多的语言间进行数据交换
2、对CPU敏感
3、协议层、传输层有多种控制要求
4、需要稳定的版本
4、不需要良好的文档和示例
五、总结
这篇文章应该非常详细介绍gRPC和Thrift两者的特点和区别,目前我还没有发现有哪篇文章总结的比我这还要好,当然除了源码解读部分(个人不建议上来就解读源码,知道执行流程和区别,便于我们使用和选型就可以)。
通篇总结下来,总结如下:
1、GRPC主要就是搞了个ProtoBuf,然后采用HTTP协议,所以协议部分没有重复造轮子,重点就在ProtoBuf上。
2、Thrift的数据格式是用的现成的,没有单独搞一套,但是它在传输层和服务端全部是自己造轮子,所以可以对协议层、传输层有多种控制要求。
欢迎大家多多点赞,更多文章,请关注微信公众号"楼仔进阶之路",点关注,不迷路~~
六、Dubbo
Dubbo 是一个分布式服务框架,致力于提供高性能和透明化的 RPC 远程服务调用方案,以及 SOA 服务治理方案。简单的说,Dubbo 就是个服务框架,说白了就是个远程服务调用的分布式框架。
Dubbo 总体架构:
Dubbo特点:
1、远程通讯: 提供对多种基于长连接的 NIO 框架抽象封装(非阻塞 I/O 的通信方式,Mina/Netty/Grizzly),包括多种线程模型,序列化(Hessian2/ProtoBuf),以及"请求-响应"模式的信息交换方式。
2、集群容错: 提供基于接口方法的透明远程过程调用(RPC),包括多协议支持(自定义 RPC 协议),以及软负载均衡(Random/RoundRobin),失败容错(Failover/Failback),地址路由,动态配置等集群支持。
3、自动发现: 基于注册中心目录服务,使服务消费方能动态的查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器。
七、Spring Cloud
Spring Cloud 基于 Spring Boot,为微服务体系开发中的架构问题,提供了一整套的解决方案------服务注册与发现,服务消费,服务保护与熔断,网关,分布式调用追踪,分布式配置管理等。
Dubbo vs Spring Cloud
使用 Dubbo 构建的微服务架构就像组装电脑,各环节我们的选择自由度很高,但是最终结果很有可能因为一条内存质量不行就点不亮了,总是让人不怎么放心,但是如果你是一名高手,那这些都不是问题;而 Spring Cloud 就像品牌机,在 Spring Source 的整合下,做了大量的兼容性测试,保证了机器拥有更高的稳定性,但是如果要在使用非原装组件外的东西,就需要对其基础有足够的了解。
关于 Dubbo 和 Spring Cloud 的相关概念和对比,我个人比较倾向于 Spring Cloud,原因就是真正的微服务框架、提供整套的组件支持、使用简单方便、强大的社区支持等等,另外,因为考虑到 .NET/.NET Core 的兼容处理,RPC 并不能很好的实现跨语言(需要借助跨语言库,比如 gRPC、Thrift,但因为 Dubbo 本身就是"gRPC",在 Dubbo 之上再包一层 gRPC,有点重复封装了),而 HTTP REST 本身就是支持跨语言实现,所以,Spring Cloud 这一点还是非常好的(Dubbox 也支持,但性能相比要差一些)。
但凡事无绝对,每件事物有好的地方也有不好的地方,总的来说,Dubbo 和 Spring Cloud 的主要不同体现在两个方面:服务调用方式不同和专注点不同(生态不同)。
关于Dubbo和Spring Cloud的更多知识,更多文章 【Dubbo系列2】基础知识
关于Dubbo的使用,可以参考文章【Dubbo系列1】Dubbo与Spring的集成