简单分布式架构
- 基本问题
- 传输什么样的数据,用哪种协议
- 哪种方式数据交换的效率好
- 服务端如何处理请求
需要扩展服务端时
- 当你的服务超过最简单结构时,你想要
- 灵活性
- 可扩展
- 低延迟
- 当然,你更想要简单
应该用这些协议吗
- 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
- gRPC是一个高性能、通用的开源RPC框架,其由Google
- 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!
Tthritr操作原理
gRPC实现原理类似
Interface Definition Language (IDL)
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);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
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> person;
6: required Player player;
}
struct MediaRq {
1: required string uri;
}
service media {
MediaRp media(1: MediaRq mediaRq);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
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用以最频繁使用的字段
比较
测试环境:
116做RPC服务器,118做AS server、RPC客户端
116 24核CPU 128G内存, 118 32核CPU 196G内存,
都是万兆网
多版本
- 系统应该支持多版本,哪怕是老的客户端调用新的服务端,或者相反
- 在Thrift和protobuf中,多版本是通过字段标识符实现的
- 正在使用的字段,请不要更新整数标识符
- 可以删除不在使用的字段,原标识符可以分给其他字段
- PB中[deprecated=true]标识废弃字段
- 字段标识符和字段类型唯一标识一个字段
- 不需要重新编译新版本
如何选择
- 什么时候应该选择gRPC而不是Thrift
- 需要良好的文档、示例
- 喜欢、习惯HTTP/2、ProtoBuf
- 对网络传输带宽敏感
- 什么时候应该选择Thrift而不是gRPC
- 需要在非常多的语言间进行数据交换
- 对CPU敏感
- 协议层、传输层有多种控制要求
- 需要稳定的版本
- 不需要良好的文档和示例
参考
gRPC官网 http://www.grpc.io/
Thrift官网 http://thrift.apache.org/
Pb vs thrift vsf avro http://www.slideshare.net/IgorAnishchenko/pb-vs-thrift-vs-avro
golang gRPC示例 http://blog.csdn.net/dazheng/article/details/46544045
THRIFT VS. PROTOCOL BUFFERS http://old.floatingsun.net/articles/thrift-vs-protocol-buffers/
Thrift使用指南 http://dongxicheng.org/search-engine/thrift-guide/