【RPC】Apache Thrift系列详解 - 概述与入门
文章目录
- 前言
- 正文
- Thrift的技术栈
- Thrift的特性
- (一) 开发速度快
- (二) 接口维护简单
- (三) 学习成本低
- (四) 多语言/跨语言支持
- (五) 稳定/广泛使用
- Thrift的数据类型
- Thrift的协议
- Thrift的传输层
- Thrift的服务端类型
- Thrift入门示例
- (一) 编写Thrift IDL文件
- (二) 新建Maven工程
- 总结
前言
Thrift读音[θrɪft],是一个轻量级、跨语言的远程服务调用框架,最初由Facebook开发,后面进入Apache开源项目。它通过自身的IDL中间语言, 并借助代码生成引擎生成各种主流语言的RPC服务端/客户端模板代码。
Thrift支持多种不同的编程语言,包括C++、Java、Python、PHP、Ruby等,本系列主要讲述基于Java语言的Thrift的配置方式和具体使用。
正文
Thrift的技术栈
Thrift对软件栈的定义非常的清晰, 使得各个组件能够松散的耦合, 针对不同的应用场景, 选择不同是方式去搭建服务。
Thrift软件栈分层从下向上分别为:传输层(Transport Layer)、协议层(Protocol Layer)、处理层(Processor Layer)和服务层(Server Layer)。
-
传输层(Transport Layer):传输层负责直接从网络中读取和写入数据,它定义了具体的网络传输协议;比如说TCP/IP传输等。
-
协议层(Protocol Layer):协议层定义了数据传输格式,负责网络传输数据的序列化和反序列化;比如说JSON、XML、二进制数据等。
-
处理层(Processor Layer):处理层是由具体的IDL(接口描述语言)生成的,封装了具体的底层网络传输和序列化方式,并委托给用户实现的Handler进行处理。
-
服务层(Server Layer):整合上述组件,提供具体的网络线程/IO服务模型,形成最终的服务。
Thrift的特性
(一) 开发速度快
通过编写RPC接口Thrift IDL文件,利用编译生成器自动生成服务端骨架(Skeletons)和客户端桩(Stubs)。从而省去开发者自定义和维护接口编解码、消息传输、服务器多线程模型等基础工作。
- 服务端:只需要按照服务骨架即接口,编写好具体的业务处理程序(Handler)即实现类即可。
- 客户端:只需要拷贝IDL定义好的客户端桩和服务对象,然后就像调用本地对象的方法一样调用远端服务。
(二) 接口维护简单
通过维护Thrift格式的IDL(接口描述语言)文件(注意写好注释),即可作为给Client使用的接口文档使用,也自动生成接口代码,始终保持代码和文档的一致性。且Thrift协议可灵活支持接口的可扩展性。
(三) 学习成本低
因为其来自Google Protobuf开发团队,所以其IDL文件风格类似Google Protobuf,且更加易读易懂;特别是RPC服务接口的风格就像写一个面向对象的Class一样简单。
初学者只需参照:thrift.apache.org/,一个多小时就可以理解Thrift IDL文件的语法使用。
(四) 多语言/跨语言支持
Thrift支持C++、 Java、Python、PHP、Ruby、Erlang、Perl、Haskell、C#、Cocoa、JavaScript、Node.js、Smalltalk等多种语言,即可生成上述语言的服务器端和客户端程序。
对于我们经常使用的Java、PHP、Python、C++支持良好,虽然对iOS环境的Objective-C(Cocoa)支持稍逊,但也完全满足我们的使用要求。
(五) 稳定/广泛使用
Thrift在很多开源项目中已经被验证是稳定和高效的,例如Cassandra、Hadoop、HBase等;国外在Facebook中有广泛使用,国内包括百度、美团小米、和饿了么等公司。
Thrift的数据类型
Thrift 脚本可定义的数据类型包括以下几种类型:
-
基本类型:
- bool: 布尔值
- byte: 8位有符号整数
- i16: 16位有符号整数
- i32: 32位有符号整数
- i64: 64位有符号整数
- double: 64位浮点数
- string: UTF-8编码的字符串
- binary: 二进制串
-
结构体类型:
- struct: 定义的结构体对象
-
容器类型:
- list: 有序元素列表
- set: 无序无重复元素集合
- map: 有序的key/value集合
-
异常类型:
- exception: 异常类型
-
服务类型:
- service: 具体对应服务的类
Thrift的协议
Thrift可以让用户选择客户端与服务端之间传输通信协议的类别,在传输协议上总体划分为文本(text)和二进制(binary)传输协议。为节约带宽,提高传输效率,一般情况下使用二进制类型的传输协议为多数,有时还会使用基于文本类型的协议,这需要根据项目/产品中的实际需求。常用协议有以下几种:
- TBinaryProtocol:二进制编码格式进行数据传输
- TCompactProtocol:高效率的、密集的二进制编码格式进行数据传输
- TJSONProtocol: 使用JSON文本的数据编码协议进行数据传输
- TSimpleJSONProtocol:只提供JSON只写的协议,适用于通过脚本语言解析
Thrift的传输层
常用的传输层有以下几种:
- TSocket:使用阻塞式I/O进行传输,是最常见的模式
- TNonblockingTransport:使用非阻塞方式,用于构建异步客户端
- TFramedTransport:使用非阻塞方式,按块的大小进行传输,类似于Java中的NIO
Thrift的服务端类型
- TSimpleServer:单线程服务器端,使用标准的阻塞式I/O
- TThreadPoolServer:多线程服务器端,使用标准的阻塞式I/O
- TNonblockingServer:单线程服务器端,使用非阻塞式I/O
- THsHaServer:半同步半异步服务器端,基于非阻塞式IO读写和多线程工作任务处理
- TThreadedSelectorServer:多线程选择器服务器端,对THsHaServer在异步IO模型上进行增强
Thrift入门示例
(一) 编写Thrift IDL文件
a). 下载0.10.0的Thrift IDL编译器,下载地址:http://thrift.apache.org/docs/install。 通过编译生成器生成.java接口的类文件。
b). 下载Windows安装环境的.exe文件,将thrift.exe的路径加入环境变量中。在Idea上安装Thrift编辑插件。
c). 编写hello.thrift的IDL文件:
service HelloWorldService {string say(1: string username)
}
d). 使用代码生成工具生成代码,执行以下命令:
thrift -gen java hello.thrift
e). 由于未指定代码生成的目标目录,生成的类文件默认存放在gen-java目录下。这里生成一个HelloWorldService.java类文件,文件大小超过数千行,下面截取一部分核心代码。
public class HelloWorldService {public interface Iface {public String say(String username) throws org.apache.thrift.TException;}public interface AsyncIface {public void say(String username, org.apache.thrift.async.AsyncMethodCallback<String> resultHandler) throws org.apache.thrift.TException;}public static class Client extends org.apache.thrift.TServiceClient implements Iface {public static class Factory implements org.apache.thrift.TServiceClientFactory<Client> {public Factory() {}public Client getClient(org.apache.thrift.protocol.TProtocol prot) {return new Client(prot);}public Client getClient(org.apache.thrift.protocol.TProtocol iprot, org.apache.thrift.protocol.TProtocol oprot) {return new Client(iprot, oprot);}}public Client(org.apache.thrift.protocol.TProtocol prot) {super(prot, prot);}public Client(org.apache.thrift.protocol.TProtocol iprot, org.apache.thrift.protocol.TProtocol oprot) {super(iprot, oprot);}public String say(String username) throws org.apache.thrift.TException {send_say(username);return recv_say();}// 省略.....}public static class AsyncClient extends org.apache.thrift.async.TAsyncClient implements AsyncIface {public static class Factory implements org.apache.thrift.async.TAsyncClientFactory<AsyncClient> {private org.apache.thrift.async.TAsyncClientManager clientManager;private org.apache.thrift.protocol.TProtocolFactory protocolFactory;public Factory(org.apache.thrift.async.TAsyncClientManager clientManager, org.apache.thrift.protocol.TProtocolFactory protocolFactory) {this.clientManager = clientManager;this.protocolFactory = protocolFactory;}public AsyncClient getAsyncClient(org.apache.thrift.transport.TNonblockingTransport transport) {return new AsyncClient(protocolFactory, clientManager, transport);}}public AsyncClient(org.apache.thrift.protocol.TProtocolFactory protocolFactory, org.apache.thrift.async.TAsyncClientManager clientManager, org.apache.thrift.transport.TNonblockingTransport transport) {super(protocolFactory, clientManager, transport);}public void say(String username, org.apache.thrift.async.AsyncMethodCallback<String> resultHandler) throws org.apache.thrift.TException {checkReady();say_call method_call = new say_call(username, resultHandler, this, ___protocolFactory, ___transport);this.___currentMethod = method_call;___manager.call(method_call);}// 省略.....}// 省略.....
}
对于开发人员而言,使用原生的Thrift框架,仅需要关注以下四个核心内部接口/类:Iface, AsyncIface, Client和AsyncClient。
- Iface:服务端通过实现HelloWorldService.Iface接口,向客户端的提供具体的同步业务逻辑。
- AsyncIface:服务端通过实现HelloWorldService.Iface接口,向客户端的提供具体的异步业务逻辑。
- Client:客户端通过HelloWorldService.Client的实例对象,以同步的方式访问服务端提供的服务方法。
- AsyncClient:客户端通过HelloWorldService.AsyncClient的实例对象,以异步的方式访问服务端提供的服务方法。
(二) 新建Maven工程
a). 新建maven工程,引入thrift的依赖,这里使用的是版本0.10.0。
<dependency><groupId>org.apache.thrift</groupId><artifactId>libthrift</artifactId><version>0.10.0</version></dependency>
b). 将生成类的HelloWorldService.java源文件拷贝进项目源文件目录中,并实现HelloWorldService.Iface的定义的say()方法。
HelloWorldServiceImpl.java
public class HelloWorldServiceImpl implements HelloWorldService.Iface {@Overridepublic String say(String username) throws TException {return "Hello " + username;}
}
c). 服务器端程序编写:
SimpleServer.java
public class SimpleServer {public static void main(String[] args) throws Exception {ServerSocket serverSocket = new ServerSocket(ServerConfig.SERVER_PORT);TServerSocket serverTransport = new TServerSocket(serverSocket);HelloWorldService.Processor processor =new HelloWorldService.Processor<HelloWorldService.Iface>(new HelloWorldServiceImpl());TBinaryProtocol.Factory protocolFactory = new TBinaryProtocol.Factory();TSimpleServer.Args tArgs = new TSimpleServer.Args(serverTransport);tArgs.processor(processor);tArgs.protocolFactory(protocolFactory);// 简单的单线程服务模型 一般用于测试TServer tServer = new TSimpleServer(tArgs);System.out.println("Running Simple Server");tServer.serve();}
}
d). 客户端程序编写:
SimpleClient.java
public class SimpleClient {public static void main(String[] args) {TTransport transport = null;try {transport = new TSocket(ServerConfig.SERVER_IP, ServerConfig.SERVER_PORT, ServerConfig.TIMEOUT);TProtocol protocol = new TBinaryProtocol(transport);HelloWorldService.Client client = new HelloWorldService.Client(protocol);transport.open();String result = client.say("Leo");System.out.println("Result =: " + result);} catch (TException e) {e.printStackTrace();} finally {if (null != transport) {transport.close();}}}
}
e). 运行服务端程序,服务端在指定端口监听客户端的连接请求,控制台输出启动日志:
f). 运行客户端程序,客户端通过网络请求HelloWorldService的say()方法的具体实现,控制台输出返回结果:
这里使用的一个基于单线程同步的简单服务模型,一般仅用于入门学习和测试!
总结
本文对Thrift的概念做了相关介绍,体验了一番thrift程序如何编写!
相关文章:

【RPC】Apache Thrift系列详解 - 概述与入门
文章目录前言正文Thrift的技术栈Thrift的特性(一) 开发速度快(二) 接口维护简单(三) 学习成本低(四) 多语言/跨语言支持(五) 稳定/广泛使用Thrift的数据类型Thrift的协议Thrift的传输层Thrift的服务端类型Thrift入门示例(一) 编写Thrift IDL文件(二) 新建Maven工程总结前言 Th…...

class03:MVVM模型与响应式原理
目录一、MVVM模型二、内在1. 深入响应式原理2. Object.entries3. 底层搭建一、MVVM模型 MVVM,即Model 、View、ViewModel。 Model > data数据 view > 视图(vue模板) ViewModel > vm > vue 返回的实例 > 控制中心, 负责监听…...

[Spring学习]08 @Resource和@Autowired注解的区别
目录前言一、Resource和Autowired注解的身世1、Resource注解2、Autowired注解3、常见的三种依赖注入方式及区别1. Filed注入2. Setter注入3. Constructor注入4. 三种依赖注入方式的区别二、Resource和Autowired注解的区别三、Resource和Autowired注解的推荐用法前言 当我们在属…...

前端开发神器VS Code安装教程
✅作者简介:CSDN一位小博主,正在学习前端 📃个人主页:白月光777的CSDN博客 💬个人格言:但行好事,莫问前程 安装VS CodeVS Code简介VS Code安装VS Code汉化结束语💡💡&…...

【Hive进阶】-- Hive SQL、Spark SQL和 Hive on Spark SQL
1.Hive SQL 1.1 基本介绍概念Hive由Facebook开发,用于解决海量结构化日志的数据统计,于2008年贡献给 Apache 基金会。Hive是基于Hadoop的数据仓库工具,可以将结构化数据映射为一张表,提供类似SQL语句查询功能本质:将Hi…...

搭建自己的直播流媒体服务器SRS,以及SRS+OBS直播推拉流使用及配置
一、前言 目前,全球直播带货什么的,成为主流,那如何自己搭建一个直播服务器呢。首先需要一个流媒体服务器,搭建流媒体有很多种方式,如下: 流媒体解决方案 Live555 (C)流媒体平台框…...

Node.js-----使用express写接口
使用express写接口 文章目录使用express写接口创建基本的服务器创建API路由模块编写GET接口编写POST接口CROS跨域资源共享1.接口的跨域问题2.使用cros中间件拒绝跨域问题3.什么是cros4.cros的注意事项5.cros请求的分类JSONP接口1.回顾jsonp的概念和特点2.创建jsonp接口的注意事…...

【Linux修炼】16.共享内存
每一个不曾起舞的日子,都是对生命的辜负。 共享内存一.共享内存的原理二.共享内存你的概念2.1 接口认识2.2演示生成key的唯一性2.3 再谈key三.共享资源的查看3.1 如何查看IPC资源3.2 IPC资源的特征3.3 进程之间通过共享内存进行关联四.共享内存的特点五.共享内存的内…...

JAVA进阶 —— Stream流
目录 一、 引言 二、 Stream流概述 三、Stream流的使用步骤 1. 获取Stream流 1.1 单列集合 1.2 双列集合 1.3 数组 1.4 零散数据 2. Stream流的中间方法 3. Stream流的终结方法 四、 练习 1. 数据过滤 2. 数据操作 - 按年龄筛选 3. 数据操作 - 演员信息要求…...

Linux基础命令大全(上)
♥️作者:小刘在C站 ♥️个人主页:小刘主页 ♥️每天分享云计算网络运维课堂笔记,努力不一定有收获,但一定会有收获加油!一起努力,共赴美好人生! ♥️夕阳下,是最美的绽放࿰…...

嵌入式 串口通信
目录 1、通信的基本概念 1.1 串行通信 1.2 并行通信 2、串行通信的特点 2.1 单工 2.2 半双工 2.3 全双工 3、串口在STM32的引脚 4、STM32的串口的接线 4.1 STM32的串口1和电脑通信的接线方式 4.2 单片机和具备串口的设备连接图 5、串口通信协议 6、串口通信…...

C语言函数调用栈
栈溢出(stack overflow)是最常见的二进制漏洞,在介绍栈溢出之前,我们首先需要了解函数调用栈。 函数调用栈是一块连续的用来保存函数运行状态的内存区域,调用函数(caller)和被调用函数…...

【高阶数据结构】红黑树
文章目录1. 使用场景2. 性质3. 结点定义4. 结点旋转5. 结点插入1. 使用场景 Linux进程调度CFSNginx Timer事件管理Epoll事件块的管理 2. 性质 每一个节点是红色或者黑色根节点一定是黑色每个叶子节点是黑色如果一个节点是红色,那么它的两个儿子节点都是黑色从任意…...

网络协议分析期末复习(二)
目录 12. 端口的定义及常见应用对应的端口号 13. UDP协议概述 14.UDP数据报格式及各字段意义 15. UDP-Lite协议概述 16. TCP数据报格式及各字段意义 17. TCP连接建立及协商参数的过程 18. TCP连接释放过程 19. 路由协议分类及各类的具体协议 20. 路由算法常用的度量 2…...

【C++】STL简介 及 string的使用
文章目录1. STL简介1.1 什么是STL1.2 STL的版本1.3 STL的六大组件2. string类的使用2.1 C语言中的字符串2.2 标准库中的string类2.3 string类的常用接口说明1. string类对象的常见构造2. string类对象的容量操作3. string类对象的修改操作4. resize和reserve5. 认识迭代器&…...

MySQL事务详解
🏆今日学习目标: 🍀Spring事务和MySQL事务详解 ✅创作者:林在闪闪发光 ⏰预计时间:30分钟 🎉个人主页:林在闪闪发光的个人主页 🍁林在闪闪发光的个人社区,欢迎你的加入: …...

ChatGPT背后的技术和多模态异构数据处理的未来展望——我与一位资深工程师的走心探讨
上周,我和一位从业三十余年的工程师聊到ChatGPT。 作为一名人工智能领域研究者,我也一直对对话式大型语言模型非常感兴趣,在讨论中,我向他解释这个技术时,他瞬间被其中惊人之处所吸引🙌,我们深…...

iOS-砸壳篇(两种砸壳方式)
CrackerXI砸壳呢,当时你要是使用 frida-ios-dump 也是可以的; https://github.com/AloneMonkey/frida-ios-dump frida-ios-dump: 代码中需要更改的:手机中的内网ip 密码 等 最后放到我的砸壳路径里: python dump.py -l查看应用…...

linux 基础
1.Shell 命令的格式如下:command -options [argument]command: Shell 命令名称。options: 选项,同一种命令可能有不同的选项,不同的选项其实现的功能不同。argument: Shell 命令是可以带参数的,也可以不带参…...
Java:SpringBoot给Controller添加统一路由前缀
网上的文章五花八门,不写SpringBoot的版本号,导致代码拿来主义不好使了。 本文采用的版本 SpringBoot 2.7.7 Java 1.8目录1、默认访问路径2、整个项目增加路由前缀3、通过注解方式增加路由前缀4、按照目录结构添加前缀参考文章1、默认访问路径 packag…...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...

Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...

微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
C++八股 —— 单例模式
文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性…...
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数
高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...

如何更改默认 Crontab 编辑器 ?
在 Linux 领域中,crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用,用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益,允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...