跨语言RPC框架Thrift详解

一、 概念
Apache的Thrift软件框架,是用来进行可伸缩的、跨语言的服务开发,它通过一个代码生成引擎来构建高效、无缝的服务,这些服务能够实现跨语言调度,目前支持的语言有: C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, OCaml and Delphi 等。
二、 安装Thrift
目前官网最新的版本是v0.10.0。下面主要介绍基于mac os系统的Thrift的安装。windows系统可参考官网教程进行安装。

mac os官网提供的安装方法比较复杂,这里介绍下mac 下的home brew的安装方法。

打开终端,如果你的mac还没有安装home brew,那么先要安装home brew,使用以下命令:

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

然后安装最新版本的Thrift:

brew install thrift

然后安装最新版本的Thrift:

brew install thrift

等待安装完成,然后输入以下命令,如果打印了Thrift的版本信息,表示安装成功:

thrift -version

三、 Thrift支持的类型

  1. 基本类型
    bool:布尔值(true或者false)
    byte:8位的有符号字节(java的byte类型)
    i16:16位的有符号整数(java的short类型)
    i32:32位的有符号整数(java的int类型)
    i64:64位的有符号长整型(java的long类型)
    double:一个64位的浮点数(java的double类型)
    string: 一个utf8编码的字符串文本(java的String)

  2. Structs
    Thrift的structs用来定义一个通用对象,但是没有继承关系。

  3. 集合类型
    list:一个有序的元素列表。元素可以重复。
    set:一个无序的元素集合,集合中元素不能重复。
    map:一个键值对的数据结构,相当于Java中的HashMap。

  4. 异常类型Exceptions
    Thrift的异常类型,除了是继承于静态异常基类以外,其他的跟struct是类似的。表示的是一个异常对象。

  5. 服务类型Services
    Thrift 的service类型相当于定义一个面向对象编程的一个接口。Thrift的编译器会根据这个接口定义来生成服务端和客户端的接口实现代码。

四、一个简单的Thrift调用实例

  1. 编写.thrift文件,也就是IDL(接口描述语言)文件
    以下是data.thrift文件:
namespace java thrift.generated
namespace py py.thrift.generatedtypedef i16 short
typedef i32 int
typedef i64 long
typedef bool boolean
typedef string Stringstruct Person {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 dataException),void savePerson(1: required Person person) throws (1: DataException dataException)
}
  1. 使用thrift的编译器,生成客户端和服务端的代码
    生成java的客户端服务端代码:
thrift --gen java src/thrift/data.thrift

生成Python的客户端服务端代码:

thrift --gen py src/thrift/data.thrift

其他语言的生成也是类似。

  1. Thrift的调用
    以java作为服务端,java作为客户端以及Python作为客户端对服务端进行请求。
    java服务端代码:
public class PersonServiceImpl implements PersonService.Iface {@Overridepublic Person getPersonByUsername(String username) throws DataException, TException {System.out.println("Got client param: " + username);Person person = new Person();person.setUsername(username);person.setAge(20);person.setMarried(false);return person;}@Overridepublic void savePerson(Person person) throws DataException, TException {System.out.println("Got client param: ");System.out.println(person.getUsername());System.out.println(person.getAge());System.out.println(person.isMarried());}
}

java客户端代码:

public class ThriftClient {public static void main(String[] args) {TTransport transport = new TFramedTransport(new TSocket("localhost", 8899), 600);TProtocol protocol = new TCompactProtocol(transport);PersonService.Client client = new PersonService.Client(protocol);try {transport.open();Person person = client.getPersonByUsername("张三");System.out.println(person.getUsername());System.out.println(person.getAge());System.out.println(person.isMarried());System.out.println("------------");Person person1 = new Person();person1.setUsername("李四");person1.setAge(30);person1.setMarried(true);client.savePerson(person1);} catch (Exception e) {throw new RuntimeException(e.getMessage(), e);} finally {transport.close();}}}

python客户端代码:

__author__ = '作者'from py.thrift.generated import PersonService
from py.thrift.generated import ttypesfrom thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TCompactProtocolimport sysreload(sys)
sys.setdefaultencoding('utf8')try:tSocket = TSocket.TSocket('localhost', 8899)tSocket.setTimeout(600)transport = TTransport.TFramedTransport(tSocket)protocol = TCompactProtocol.TCompactProtocol(transport)client = PersonService.Client(protocol)transport.open()person = client.getPersonByUsername('张三')print person.usernameprint person.ageprint person.marriedprint '------------------'newPerson = ttypes.Person()newPerson.username = '李四'newPerson.age = 30newPerson.married = Trueclient.savePerson(newPerson)except Thrift.TException, tx:print '%s' % tx.message

先运行服务端,然后再运行客户端,观察服务端和客户端的输出来理解下thrift的一个调用流程是什么样的。

五、Thrift的架构原理
以下是thrift的客户端和服务端交互的一个原理图:
在这里插入图片描述
如上图,客户端在进行远程方法调用时,首先是通过Thrift的编译器生成的客户端,将调用信息(方法名,参数信息)以指定的协议进行封装,而传输层TTransport是对协议层的封装进行处理(比如封装成帧frame),并通过网络发送出去。服务端这边流程跟客户端相反,收到客户端发过来的数据后,首先经过传输层对传过来的数据进行处理,然后使用特定的协议(跟客户端是一一对应的)进行解析,然后再通过生成的Processor调用用户编写的代码,如果有返回值的话,返回值以逆向的顺序,即通过协议层封装,然后传输层处理对数据进行发送,到了客户端那边就是对服务端返回的数据进行处理,使用特定协议进行解析,然后得到一个调用个的结果。

以上就是Thrift的RPC调用的一个完整流程。

六、 Thrift的传输格式(协议层)
Thrift之所以被称为一种高效的RPC框架,其中一个重要的原因就是它提供了高效的数据传输。
以下是Thrift的传输格式种类:

TBinaryProtocol: 二进制格式。效率显然高于文本格式。
TCompactProtocol:压缩格式。在二进制基础上进一步压缩。
TJSONProtocol:JSON格式。
TSimpleJSONProtocol:提供JSON只写协议(缺少元数据信息),生成的文件很容易用过脚本语言解析。
TDebugProtocol:使用易懂的刻度文本格式,以便于调试。
以上可以看到,在线上环境,使用TCompactProtocol格式效率是最高的,同等数据传输占用网络带宽是最少的。

七、Thrift的数据传输方式(传输层)
TSocket:阻塞式socket。
TFramedTransport:以frame为单位进行传输,非阻塞式服务中使用。
TFileTransport:以文件形式进行传输。
TMemoryTransport:将内存用于I/O,Java是现实内部实际使用了简单的ByteArrayOutputStream。
TZlibTransport:使用zlib进行压缩,与其他传输方式联合使用。当前无java实现。
八、Thrift的服务模型
TSimpleServer
简单的单线程服务模型,常用于测试。只在一个单独的线程中以阻塞I/O的方式来提供服务。所以它只能服务一个客户端连接,其他所有客户端在被服务器端接受之前都只能等待。
TNonblockingServer
它使用了非阻塞式I/O,使用了java.nio.channels.Selector,通过调用select(),它使得程序阻塞在多个连接上,而不是单一的一个连接上。TNonblockingServer处理这些连接的时候,要么接受它,要么从它那读数据,要么把数据写到它那里,然后再次调用select()来等待下一个准备好的可用的连接。通用这种方式,server可同时服务多个客户端,而不会出现一个客户端把其他客户端全部“饿死”的情况。缺点是所有消息是被调用select()方法的同一个线程处理的,服务端同一时间只会处理一个消息,并没有实现并行处理。
THsHaServer(半同步半异步server)
针对TNonblockingServer存在的问题,THsHaServer应运而生。它使用一个单独的线程专门负责I/O,同样使用java.nio.channels.Selector,通过调用select()。然后再利用一个独立的worker线程池来处理消息。只要有空闲的worker线程,消息就会被立即处理,因此多条消息能被并行处理。效率进一步得到了提高。
TThreadedSelectorServer
它与THsHaServer的主要区别在于,TThreadedSelectorServer允许你用多个线程来处理网络I/O。它维护了两个线程池,一个用来处理网络I/O,另一个用来进行请求的处理。
TThreadPoolServer
它使用的是一种多线程服务模型,使用标准的阻塞式I/O。它会使用一个单独的线程来接收连接。一旦接受了一个连接,它就会被放入ThreadPoolExecutor中的一个worker线程里处理。worker线程被绑定到特定的客户端连接上,直到它关闭。一旦连接关闭,该worker线程就又回到了线程池中。
这意味着,如果有1万个并发的客户端连接,你就需要运行1万个线程。所以它对系统资源的消耗不像其他类型的server一样那么“友好”。此外,如果客户端数量超过了线程池中的最大线程数,在有一个worker线程可用之前,请求将被一直阻塞在那里。
如果提前知道了将要连接到服务器上的客户端数量,并且不介意运行大量线程的话,TThreadPoolServer可能是个很好的选择。
九、 其他
Facebook开源了一个简化thrift java开发的一个库——swift。swift是一个易于使用的、基于注解的java库,主要用来创建thrift可序列化类型和服务。

github地址:https://github.com/facebook/swift

十、 总结
Thrift是一个跨语言的RPC框架,如果有跨语言交互的业务场景,Thrift可能是一个很好的选择。如果使用恰当,thrift将是一个非常高效的一个RPC框架。开发时应根据具体场景选择合适的协议,传输方式以及服务模型。缺点就是Thrift并没有像dubbo那样提供分布式服务的支持,如果要支持分布式,需要开发者自己去开发集成。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/249743.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小知识

1.时间格式的处理 new Date().format(yyyy-MM-dd hh:mm:ss) 2.保留两位小数的方法 element.recTime element.recTime.toFixed(2) 3.如何判断一个对象为空的方法 JSON.stringify(this.getEcho) ! "{}" 4.判断时间是否为标准格式的方法 (this.formValidate.outDateti…

增加标 和增加其内容

create table student( sno varchar(20) not null comment学号, sname varchar(20) not null comment学生姓名, ssex varchar(20) not null comment学生性别, sbirthday datetime comment学生出生年月, class varchar(20) comment 学生所在班级, primary key…

RPC服务和HTTP服务对比

很长时间以来都没有怎么好好搞清楚RPC(即Remote Procedure Call,远程过程调用)和HTTP调用的区别,不都是写一个服务然后在客户端调用么?这里请允许我迷之一笑~Naive!本文简单地介绍一下两种形式的C/S架构&am…

MTK-TP(电阻屏校准程序ts_lib移植)

现今的项目中已经很少有使用电阻TP,但总有些奇怪的需求。如果项目中遇到需要校准电阻屏如何保证较快且较稳的调试TP呢。这里介绍使用ts_lib库来进行调试。 当然也可以使用一些常见的校准算法,采集5点,但最终的公式应该是不变的: X…

mac vscode 实用快捷键

cmddel:光标左边删到头 cmdfndel:光标右侧删到头转载于:https://www.cnblogs.com/smzd/p/11474488.html

ONENET读取与控制麒麟座MINI开发板LED状态

硬件 麒麟座MINI开发板V1.4 嵌入式软件 OneNET_Demo_ESP8266_EDP_Led 工程修改内容 led.c文件修改 函数LED_Init,mini开发板LED所在GPIO为PB6、PB7、PB8、PB9 函数LED_GetValue,mini开发板LED状态与IO口状态相反 /** * brief LED指示灯初始化函数**/v…

洛谷 - P1217 - 回文质数 - 枚举

https://www.luogu.org/problemnew/show/P1217 考虑暴力生成所有的回文数然后再判断是不是质数。注意个位的选择实际上只有4种。所以是 $4*10^3*10^34*10^6$ &#xff0c;完全充裕的复杂度。 #include<bits/stdc.h> using namespace std; #define ll long longint a,b; v…

git commit之后,想撤销commit

写完代码后&#xff0c;我们一般这样git add . //添加所有文件git commit -m "本功能全部完成"执行完commit后&#xff0c;想撤回commit&#xff0c;怎么办&#xff1f;这样凉拌&#xff1a;git reset --soft HEAD^这样就成功的撤销了你的commit注意&#xff0c;仅仅…

引用数据类型

1.Scanner类 Scanner类是引用数据类型的一种&#xff0c;我们可以使用该类来完成用户键盘录入&#xff0c;获取到录入的数据。 引用数据类型的使用&#xff1a; 与定义基本数据类型变量不同&#xff0c;引用数据类型的变量定义及赋值有一个相对固定的步骤或格式。 数据类型 变…

phpmyadmin登录远程mysql数据库

之前只用phpmyadmin登录本地的mysql&#xff0c;管理另一个远程数据库的时候发现&#xff0c;单纯用命令行处理字符串、换行符实在是不好使&#xff0c;所以配置了远程登录mysql&#xff0c;很简单的问题结果没有搜到合适的方法&#xff0c;所以记录下我的配置方式。 phpmyadmi…

activemq的使用场景

一、消息队列概述 消息队列中间件是分布式系统中重要的组件&#xff0c;主要解决应用耦合&#xff0c;异步消息&#xff0c;流量削锋等问题。实现高性能&#xff0c;高可用&#xff0c;可伸缩和最终一致性架构。是大型分布式系统不可缺少的中间件。 目前在生产环境&#xff0c…

复习JavaScript随手记

数据类型 基本类型 stringnumberbooleanundefinednumber类型,包含整数浮点数 NaN和自己都不相等,涉及NaN的计算结果都是NaN isNaN()函数用于判断一个数是不是NaN 引用类型 object类型 function类型 继承自object object类型定义了prototype属性 可以通过它动态给对象绑定方法和…

TP5在前端时间戳转换为时间格式

value"{:date(Y-m-d H:i:s,$data[add_date])}" 例如&#xff1a; <td>{:date(Y-m-d H:i:s,$d[create_time])}</td> 转载于:https://www.cnblogs.com/shark1100913/p/9468077.html

Java(发布/订阅模式)

1、概述 观察者模式又称为发布/订阅(Publish/Subscribe)模式 观察者设计模式涉及到两种角色&#xff1a;主题&#xff08;Subject&#xff09;和观察者&#xff08;Observer&#xff09; &#xff08;1&#xff09;Subject模块 Subjec模块有3个主要操作 addObserver()&#…

VUE $SET源码

转载于:https://www.cnblogs.com/smzd/p/11634255.html

JS 日期格式化

1、将中国标准时间格式化为&#xff08;2017-06-06 15:05:04&#xff09; function formatDateTime(theDate) { var _hour theDate.getHours(); var _minute theDate.getMinutes(); var _second theDate.getSeconds(); var _year theDate.getFullYear() var _month theDat…

canvas 入门

<canvas>是HTML5新增的&#xff0c;是可以使用脚本&#xff08;JavaScript&#xff09;在其中绘制图像的HTML元素。 canvas是由HTML代码配合高度和宽度属性而定义出的可绘制区域&#xff0c;JavaScript代码可访问该区域&#xff0c;类似于其它通用的二维API&#xff0c;通…

Java实现消息队列服务

使用 JAVA 语言自己动手来写一个MQ (类似ActiveMQ,RabbitMQ) 主要角色 首先我们必须需要搞明白 MQ (消息队列) 中的三个基本角色 ProducerBrokerConsumer 整体架构如下所示 自定义协议 首先从上一篇中介绍了协议的相关信息,具体厂商的 MQ(消息队列) 需要遵循某种协议或者…

Knockout中ko.utils中处理数组的方法集合

每一套框架基本上都会有一个工具类&#xff0c;如&#xff1a;Vue中的Vue.util、Knockout中的ko.utils、jQuery直接将一些工具类放到了$里面&#xff0c;如果你还需要更多的工具类可以试试lodash。本文只介绍一下Knockout中ko.utils中处理数组的一些方法。 ko.utils.arrayForEa…

$nextTick 源码

x现在没时间&#xff0c;留个坑 转载于:https://www.cnblogs.com/smzd/p/11634665.html