gRPC vs Thrift

g.csdn.net/dazheng/article/details/48830511



简单分布式架构
这里写图片描述



基本问题
传输什么样的数据,用哪种协议
哪种方式数据交换的效率好
服务端如何处理请求
需要扩展服务端时
当你的服务超过最简单结构时,你想要
灵活性
可扩展
低延迟
当然,你更想要简单
应该用这些协议吗
SOAP
XML, XML还是XML
CORBA
美好的想法,糟糕的实现
过渡设计和臃肿
DCOM, COM+



主要用于windows平台
HTTP/TCP/Socket/Whatever
久经考验的
但是缺少协议处理
需要自己实现协议封装
自己实现客户端、服务端
关注底层协议及状态
那我们需要什么
不同的语言间可以透明交互
平台和语言无关
可以很好的平衡
效率(时间、空间)
开发易用性和执行速度
使用已有的类库

RPC编程简介
远程过程调用(Remote Procedure Call,RPC)
是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编程。
为什么选择RPC
提高开发效率,开发人员可以把更多精力放在具体的接口实现,而不必考虑数据的底层传输问题。
大多数rpc框架都是很多优秀开发人员的智慧结晶,它们的功能实现和执行效率都很优秀。
client端和server端必须遵循统一的接口规范,避免产生client和server之间接口或数据局结构不匹配的情况。
Google gRPC
gRPC
gRPC是一个高性能、通用的开源RPC框架,其由Google
2015年主要面向移动应用开发并基于HTTP/2协议标准而设计,基于ProtoBuf(Protocol
Buffers)序列化协议开发,且支持众多开发语言。gRPC提供了一种简单的方法来精确地定义服务和为iOS、Android和后台支持服务自动生成可靠性很强的客户端功能库。客户端充分利用高级流和链接功能,从而有助于节省带宽、降低的TCP链接次数、节省CPU使用、电池寿命。
最新的Google API支持gRPC
支持 C, C++, Node.js, Python, Ruby, Objective-C,PHP and C#
当前版本Alpha
协议 BSD
ProtoBuf
其由Google 2001年设计,2008年开源。
Google内部的服务几乎都是用的PB协议
久经考验、充分验证、良好实现
-使用ProtoBuf: Google、Hadoop、ActiveMQ、Netty
当前版本v3.0.0-alpha-3
协议 BSD
Apache Thrift
thrift是一种可伸缩的跨语言服务的RPC软件框架。它结合了功能强大的软件堆栈的代码生成引擎,以建设服务,高效、无缝地在多种语言间结合使用。2007年由facebook贡献到apache基金,是apache下的顶级项目。
支持C、C++ 、C# 、D 、Delphi 、Erlang 、Go 、Haxe 、Haskell 、Java 、JavaScript
、node.js 、OCaml 、Perl 、PHP 、Python 、Ruby 、SmallTalk
使用Thrift:Hadoop、HBase、Cassandra、Scribe、LastFM、Facebook、 Evernote
当前版本 0.9.2
协议Apache License 2.0
典型操作模型
IDL-like语言定义接口
运行工具生成java、python、Go等引用程序
如: thrift –gen go MyProject.thrift
生成的引用程序哪怕再多,都是可读的
在自己的程序中引用生成的程序
DO NOT EDIT!



gRPC



syntax = “proto3”; //protobuf3协议
package infg;



option optimize_for=SPEED;



message Person {
string name = 1;
map<string, int64> tel = 2;
}
message MediaRp {
string uri = 1;
string title = 2;
int32 width = 3;
int32 height = 4;
repeated Person person = 5;
enum Player {
JAVA = 0;
FLASH = 1;
}
Player player = 6;
}
message MediaRq {
string uri = 1;
}



service media {
rpc Media(MediaRq) returns (MediaRp);
}



Thrift



namespace go inft



typedef i32 int;
typedef i64 long;



enum Player {
JAVA = 0;
FLASH = 1;
}
struct Person {
1: required string name;
2: optional map<string, long> tel;
}
struct MediaRp {
1: required string uri;
2: optional string title;
3: required int width;
4: required int height;
5: required list person;
6: required Player player;
}
struct MediaRq {
1: required string uri;
}



service media {
MediaRp media(1: MediaRq mediaRq);
}
IDL 规则
每列必须有一个唯一的正整数标识符
Thrift每列可以标识是“optional”、“required”,pb不可以,每列都是“optional”
gRPC service中,都必须有输入和输出,而且参数及返回值必须是定义好的message类型,而thrift中,输入和输出都可以为空,而且参数可以是定义好的struct,也可以是其他支持的类型
structs/messages都可以包含其他的structs/messages
每列可以有“default”值
同一个文件中, 多个structs/messages可以被引用
可以引入其他文件定义
整数标识符
“= 1”, “ = 2” or “ 1:”, “ 2:”,在二进制文件中唯一标识一列
保持数字标识不变非常重要
数字1到15占用一个字节
数字16到2047占用两个字节
保持1到15用以最频繁使用的字段


多版本
系统应该支持多版本,哪怕是老的客户端调用新的服务端,或者相反
在Thrift和protobuf中,多版本是通过字段标识符实现的
正在使用的字段,请不要更新整数标识符
可以删除不在使用的字段,原标识符可以分给其他字段
PB中[deprecated=true]标识废弃字段
字段标识符和字段类型唯一标识一个字段
不需要重新编译新版本
如何选择
什么时候应该选择gRPC而不是Thrift
需要良好的文档、示例
喜欢、习惯HTTP/2、ProtoBuf
对网络传输带宽敏感
什么时候应该选择Thrift而不是gRPC
需要在非常多的语言间进行数据交换
对CPU敏感
协议层、传输层有多种控制要求
需要稳定的版本
不需要良好的文档和示例
GoLang
Go语言是由Google开发的一个开源项目,目的之一为了提高开发人员的编程效率。 Go语言语法灵活、简洁、清晰、高效。它对的并发特性可以方便地用于多核处理器 和网络开发,同时灵活新颖的类型系统可以方便地编写模块化的系统。Go集成了C、Python(PHP)、ErLang等语言的优点,主要特点有:
面向过程的改良, 不追求极致面向对象;
强类型、静态编译,几乎没有部署依赖(Java需要JVM,PHP/Python需要解析执行器,与静态编译的C/C++相当);性能优秀,与C/C++、Java同量级;
为分布式而生,优雅高效的并发能力,基于消息的并发和同步;
自动垃圾回收,不用再担心内存泄露;
内置各种高级语言类型,各种互联网协议和类库;



gRPC



一个高性能、通用的开源RPC框架,其由Google主要面向移动应用开发并基于HTTP/2协议标准而设计,基于ProtoBuf(Protocol Buffers)序列化协议开发,且支持众多开发语言。
gRPC基于HTTP/2标准设计,带来诸如双向流控、头部压缩、单TCP连接上的多复用请求等特性。这些特性使得其在移动设备上表现更好,更省电和节省空间占用。



为什么选择RPC
提高开发效率,开发人员可以把更多精力放在具体的接口实现,而不必考虑数据的底层传输问题。
大多数rpc框架都是很多优秀开发人员的智慧结晶,它们的功能实现和执行效率都很优秀。
client端和server端必须遵循统一的接口规范,避免产生client和server之间接口或数据局结构不匹配的情况。
区别
Grpc
Grpc 是高性能,通用的开源RPC框架,基于HTTP/2协议标准
Grpc 以protobuf作为LDL(接口描述语言),通过protoc来编译框架代码
支持 C, C++, Node.js, Python, Ruby, Objective-C,PHP and C#
Thrift
Thrift是一种可伸缩的跨语言服务的RPC软件框架。它结合了功能强大的软件堆栈的代码生成引擎,以建设服务,高效、无缝地在多种语言间结合使用
Thrift 以thrift 作为LDL
支持C、C++ 、C# 、D 、Delphi 、Erlang 、Go 、Haxe 、Haskell 、Java 、JavaScript 、node.js 、OCaml 、Perl 、PHP 、Python 、Ruby 、SmallTalk
使用Thrift:Hadoop、HBase、Cassandra、Scribe、LastFM、Facebook、 Evernot blockchain blockchain
如何选择
什么时候应该选择gRPC而不是Thrift
需要良好的文档、示例
喜欢、习惯HTTP/2、ProtoBuf
对网络传输带宽敏感
什么时候应该选择Thrift而不是gRPC
需要在非常多的语言间进行数据交换
对CPU敏感
协议层、传输层有多种控制要求
需要稳定的版本
不需要良好的文档和示例



为什么选择RPC
提高开发效率,开发人员可以把更多精力放在具体的接口实现,而不必考虑数据的底层传输问题。
大多数rpc框架都是很多优秀开发人员的智慧结晶,它们的功能实现和执行效率都很优秀。
client端和server端必须遵循统一的接口规范,避免产生client和server之间接口或数据局结构不匹配的情况。
区别
Grpc
Grpc 是高性能,通用的开源RPC框架,基于HTTP/2协议标准
Grpc 以protobuf作为LDL(接口描述语言),通过protoc来编译框架代码
支持 C, C++, Node.js, Python, Ruby, Objective-C,PHP and C#
Thrift
Thrift是一种可伸缩的跨语言服务的RPC软件框架。它结合了功能强大的软件堆栈的代码生成引擎,以建设服务,高效、无缝地在多种语言间结合使用
Thrift 以thrift 作为LDL
支持C、C++ 、C# 、D 、Delphi 、Erlang 、Go 、Haxe 、Haskell 、Java 、JavaScript 、node.js 、OCaml 、Perl 、PHP 、Python 、Ruby 、SmallTalk
使用Thrift:Hadoop、HBase、Cassandra、Scribe、LastFM、Facebook、 Evernot blockchain blockchain
如何选择
什么时候应该选择gRPC而不是Thrift
需要良好的文档、示例
喜欢、习惯HTTP/2、ProtoBuf
对网络传输带宽敏感
什么时候应该选择Thrift而不是gRPC
需要在非常多的语言间进行数据交换
对CPU敏感
协议层、传输层有多种控制要求
需要稳定的版本
不需要良好的文档和示例



Dubbo 是阿里巴巴公司开源的一个Java高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成。不过,略有遗憾的是,据说在淘宝内部,dubbo由于跟淘宝另一个类似的框架HSF(非开源)有竞争关系,导致dubbo团队已经解散(参见http://www.oschina.net/news/55059/druid-1-0-9 中的评论),反到是当当网的扩展版本仍在持续发展,墙内开花墙外香。其它的一些知名电商如当当、京东、国美维护了自己的分支或者在dubbo的基础开发,但是官方的库缺乏维护,相关的依赖类比如Spring,Netty还是很老的版本(Spring 3.2.16.RELEASE, netty 3.2.5.Final),倒是有些网友写了升级Spring和Netty的插件。



Motan是新浪微博开源的一个Java 框架。它诞生的比较晚,起于2013年,2016年5月开源。Motan 在微博平台中已经广泛应用,每天为数百个服务完成近千亿次的调用。



rpcx是Go语言生态圈的Dubbo, 比Dubbo更轻量,实现了Dubbo的许多特性,借助于Go语言优秀的并发特性和简洁语法,可以使用较少的代码实现分布式的RPC服务。



gRPC是Google开发的高性能、通用的开源RPC框架,其由Google主要面向移动应用开发并基于HTTP/2协议标准而设计,基于ProtoBuf(Protocol Buffers)序列化协议开发,且支持众多开发语言。本身它不是分布式的,所以要实现上面的框架的功能需要进一步的开发。



thrift是Apache的一个跨语言的高性能的服务框架,也得到了广泛的应用。



服务架构的治理原则
服务部署上线之后,最重要的工作就是服务治理。微服务治理原则:线上治理、实时动态生效。
微服务常用的治理策略:



流量控制:动态、静态流控制。
服务降级。
超时控制。
优先级调度。
流量迁移。
调用链跟踪和分析。
服务路由。
服务上线审批、下线通知。
SLA策略控制



服务架构的治理原则
服务部署上线之后,最重要的工作就是服务治理。微服务治理原则:线上治理、实时动态生效。
微服务常用的治理策略:



流量控制:动态、静态流控制。
服务降级。
超时控制。
优先级调度。
流量迁移。
调用链跟踪和分析。
服务路由。
服务上线审批、下线通知。
SLA策略控制。
微服务治理模型如下所示:



最上层是为服务治理的UI界面,提供在线、配置化的治理界面供运维人员使用。SDK层是提供了微服务治理的各种接口,供服务治理Portal调用。最下面的就是被治理的微服务集群,集群各节点会监听服务治理的操作去做实时刷新。例如:修改了流控阈值之后,服务治理服务会把新的流控的阈值刷到服务注册中心,服务提供者和消费者监听到阈值变更之后,获取新的阈值并刷新到内存中,实现实时生效。由于目前服务治理策略数据量不是特别大,所以可以将服务治理的数据放到服务注册中心(例如etcd/ZooKeeper),没有必要再单独做一套。



服务最佳实践
介绍完微服务实施之后,下面我们一起学习下微服务的最佳实践。
服务路由:本地短路策略。关键技术点:优先调用本JVM内部服务提供者,其次是相同主机或者VM的,最后是跨网络调用。通过本地短路,可以避免远程调用的网络开销,降低服务调用时延、提升成功率。原理如下所示:



服务调用方式:同步调用、异步调用、并行调用。一次服务调用,通常就意味着会挂一个服务调用线程。采用异步调用,可以避免线程阻塞,提升系统的吞吐量和可靠性。但是在实际项目中异步调用也有一些缺点,导致使用不是特别广泛:
需要写异步回调逻辑,与传统的接口调用使用方式不一致,开发难度大一些。
一些场景下需要缓存上下文信息,引入可靠性问题。
并行调用适用于多个服务调用没有上下文依赖,逻辑上可以并行处理,类似JDK的Fork/Join, 并行服务调用涉及到同步转异步、异步转同步、结果汇聚等,技术实现难度较大,目前很多服务框架并不支持。采用并行服务调用,可以把传统串行的服务调用优化成并行处理,能够极大的缩短服务调用时延。



微服务故障隔离:线程级、进程级、容器级、VM级、物理机级等。关键技术点:



支持服务部署到不同线程/线程池中。
核心服务和非核心服务隔离部署。
为了防止线程膨胀,支持共享和独占两种线程池策略。



谈到分布式,就绕不开事务一致性问题:大部分业务可以通过最终一致性来解决,极少部分需要采用强一致性。



具体的策略如下:



最终一致性,可以基于消息中间件实现。
强一致性,使用TCC框架。服务框架本身不会直接提供“分布式事务”,往往根据实际需要迁入分布式事务框架来支持分布式事务。
微服务的性能三要素:



I/O模型,这个通常会选用非堵塞的,Java里面可能用java原生的。
线程调度模型。
序列化方式。
公司内部服务化,对性能要求较高的场景,建议使用异步非阻塞I/O(Netty) + 二进制序列化(Thrift压缩二进制等) + Reactor线程调度模型。



最后我们一起看下微服务的接口兼容性原则:技术保障、管理协同。



制定并严格执行《微服务前向兼容性规范》,避免发生不兼容修改或者私自修改不通知周边的情况。
接口兼容性技术保障:例如Thrift的IDL,支持新增、修改和删除字段、字段定义位置无关性,码流支持乱序等。
持续交付流水线的每日构建和契约化驱动测试,能够快速识别和发现不兼容。
现在流行的RPC框架:
服务治理型
dubbo
dubbox
motan
多语言型
grpc
thrift
avro
Protocol Buffers (google)



服务性能
在服务化,或者微服务化过程中,首先考虑的问题就是性能问题,因为在服务化之后,会增加以下额外的性能开销:



客户端需要对消息进行序列化,主要占用CPU计算资源。
序列化时需要创建二进制数组,耗费JVM堆内存或者堆外内存。
客户端需要将序列化之后的二进制数组发送给服务端,占用网络带宽资源。
服务端读取到码流之后,需要将请求数据报反序列化成请求对象,占用CPU计算资源。
服务端通过反射的方式调用服务提供者实现类,反射本身对性能影响就比较大。
服务端将响应结果序列化,占用CPU计算资源。
服务端将应答码流发送给客户端,占用网络带宽资源。
客户端读取应答码流,反序列化成响应消息,占用CPU资源。
RPC框架高性能设计
要想提高效率,除了硬件的提升,主要考虑以下三个方面:



I/O调度模型:同步阻塞I/O(BIO)还是非阻塞I/O(NIO)。
序列化框架的选择:文本协议、二进制协议或压缩二进制协议。
线程调度模型:串行调度还是并行调度,锁竞争还是无锁化算法。
IO调度现在主流的就是netty。
高性能序列化目前性能最好的是ice,google 的 pb协议,FB的thrift协议等
线程没啥好说的,肯定多线程了。当然也可以是AKKA(java)


Category golang