RPC 原理
RPC( Remote Procedure Call ) 远程调用过程。
代码语言:javascript复制1. 定义了一个接口文件,描述了对象,对象成员,接口方法等一系列信息。
2.通过RPC 框架提供的编译器,将接口说明文件编译成对应的语言文件。
2. 在客户端和服务端分别引用 RPC 编译器生成的文件,即可像调用本地方法一样远程调用。
RPC 通信过程如下:
代码语言:javascript复制1. 客户端以正常方式调用客户桩(client stub)
2. 客户桩生成一个消息,然后调用本地操作系统。
3. 客户端操作系统将消息发送给原程操作系统。
4. 远程操作系统将消息交给服务器桩
5. 服务器桩将参数提取出来,然后调用服务过程
6. 服务器执行要求的操作,操作完成后将结果返回给服务器桩,
7. 服务器桩将结果打包成一个消息, 然后调用本地操作系统。
8. 服务器操作系统将含有结果的消息发送给客户端操作系统
9. 客户端操作系统将消息交给客户桩
10. 客户桩将结果提取出来,返回给他的调用方
- 资源粒度, RPC 调用类似于本地调用,RESTful API 每一次添加接口都可能需要额外开发接口的数据,这相当于应用视图中再写一次方法调用。
- 流量消耗,RestFull API 在应用层和使用 HTTP 协议, 即使是传输高效的 JSON 也会消耗较大流量, RPC 可以使用 TCP,也可以使用 UDP , 而且可以编码,降低数据大小和减少流量消耗。
Thrift 架构
Thrift 作用于各个服务之间的 RPC 通信,支持跨语言,thrift 是一个典型的 CS 框架,客户端服务端可以使用不同的语言开发, thrift 通过 IDL (Interface Description Language) 来关联客户端和服务器。
Thrift 整体架构
在这里插入图片描述
- your code 是业务逻辑代码
- FooService.Client /Foo.Processor() Foo.Write() Foo.Read是 thrift 根据 IDL 生成的客户端和服务端代码,对应的是 RPC 中的 Client Stub 和 Server Stub
- TProtocol 是用来对数据进行序列化和反序列化。
- TTransport 提供传输数据功能,使用 Apache Thrift 可以方便的定义一个服务并选择不同的传输协议。
Thrift 网络栈架构
在这里插入图片描述
TTransport 层
- TSocket :阻塞 Socket
- TFrametransport :以 frame 为单位进行传输, 非阻塞式服务中使用
- TFileTransport : 以文件形式进行传输
TProtocol 层
代表 thrift 客户端和服务端之间的传输数据的协议,指的是客户端和服务端传输数据的格式,比如 Json, thrift 中有如下格式:
- TBinaryProtocol:二进制格式
- TCompactProtocol:压缩格式
- TJSONProtocol : Json 格式
- TSimpleJsonProtocol:提供只写的 JSON 协议
Thrift 支持的 Server 模型
- TSimpleServer :用于简单的单线程模型,常用于测试
- TThreadPoolServer :多线程模型,使用标准的阻塞 IO
- TNoBlockingServer: 多线程服务模型,使用非阻塞 IO,需要使用TFramedTransport 数据传输方式。
- THsHaServer : THsHa 引入了线程池去处理,其模型读写任务放到线程池去处理,Half-sync/Half-async处理模式,Half-async是在处理IO事件上(accept/read/write io),Half-sync用于handler对rpc的同步处理;
Thrift 支持的基本数据类型
- byte: 有符号字节
- i16: 16 位有符号整数
- i32 : 32 位有符号整数
- i64: 64 位有符号整数
- double : 64 位浮点数
- string : 字符串
Thrift 支持的容器类型
- list:一系列由 T 类型的数据组成的有序列表, 元素可以重复
- set : 一系列由 T 类型组成的无序集合,元素不可以重复
- map: 一个字典结构,Key 为 K 类型, Value 为 V 类型,和 Java 中的 HashMap 类似
thrift 支持 struct 类型,可以将一些数据类型聚合到一块。
代码语言:javascript复制struct People {
1:string name;
2:i32 age;
3:string gender;
}
thrift 支持枚举类型
代码语言:javascript复制enum Gender {
MALE,
FEMALE
}
thrift 支持异常类型
代码语言:javascript复制exception RequestException {
1:i32 code;
2:string reason;
}
thrift 定义 Service. 格式如下:
代码语言:javascript复制service HelloWorldService {
// service中可以定义若干个服务,相当于Java Interface中定义的方法
string doAction(1:string name, 2:i32 age);
}
thrift 支持给类型定义别名
代码语言:javascript复制typedef i32 int
typedef i64 long
thrift. 支持常量的定义
代码语言:javascript复制const i32 MAX_RETRIES_TIME = 10;
const string MY_WEBSITE = "http://facebook.com";
thrift 支持命名空间,相当于 Java 中的package.
代码语言:javascript复制namespace java com.test.thrift.demo
#、//、/**/都可以作为thrift文件中的注释。
thrift提供两个关键字required和optional,分别用于表示对应的字段是必填的还是可选的(推荐尽量使用optional),如下
代码语言:javascript复制struct People {
1:required string name;
2:optional i32 age;
}
thrift也支持文件包含,相当于CPP中的include,Java中的import,使用关键字include:
代码语言:javascript复制include "global.thrift"
thrift IDL 例子
代码语言:javascript复制// data.thrift
namespace java thrift.generated
namespace py py.thrift.generated
typedef i16 short
typedef i32 int
typedef i64 long
typedef bool boolean
typedef string String
// struct关键字用于定义结构体,相当于面向对象编程语言中的类
struct Person {
// 相当于定义类中的成员,并生成相应的get和set方法,optional表示username这个成员可以没有
1: optional String username,
2: optional int age,
3: optional boolean married
}
// 定义一个异常类型,用于接口中可能抛出的异常
exception DataException {
1: optional String message,
2: optional String callStack,
3: optional String date
}
// 定义服务接口
service PersonService {
Person getPersonByUsername(1: required String username) throws (1: DataException data),
void savePerson(1: required Person person)
}
执行 thrift --gen java src/thrift/data.thrift 生成代码.
thrift 如何安装,可参考 https://wangxiaoming.blog.csdn.net/article/details/114317905
客户端可以像调用本地的方法一样调用服务端的方法
生成代码结构如下:
微信号:程序员开发者社区
博客:CSDN 王小明
关注我们,了解更多
参考资料
- https://www.cnblogs.com/jpfss/p/10881220.html