Thrift简单介绍

1.1、  Thrift是什么?能做什么?

Thrift是Facebook于2007年开发的跨语言的rpc服框架,提供多语言的编译功能,并提供多种服务器工作模式;用户通过Thrift的IDL(接口定义语言)来描述接口函数及数据类型,然后通过Thrift的编译环境生成各种语言类型的接口文件,用户可以根据自己的需要采用不同的语言开发客户端代码和服务器端代码。

例如,我想开发一个快速计算的RPC服务,它主要通过接口函数getInt对外提供服务,这个RPC服务的getInt函数使用用户传入的参数,经过复杂的计算,计算出一个整形值返回给用户;服务器端使用java语言开发,而调用客户端可以是java、c、python等语言开发的程序,在这种应用场景下,我们只需要使用Thrift的IDL描述一下getInt函数(以.thrift为后缀的文件),然后使用Thrift的多语言编译功能,将这个IDL文件编译成C、java、python几种语言对应的“特定语言接口文件”(每种语言只需要一条简单的命令即可编译完成),这样拿到对应语言的“特定语言接口文件”之后,就可以开发客户端和服务器端的代码了,开发过程中只要接口不变,客户端和服务器端的开发可以独立的进行。

Thrift为服务器端程序提供了很多的工作模式,例如:线程池模型、非阻塞模型等等,可以根据自己的实际应用场景选择一种工作模式高效地对外提供服务;

1.2、  Thrift的相关网址和资料:

(1)  Thrift的官方网站:http://thrift.apache.org/

(2)  Thrift官方下载地址:http://thrift.apache.org/download

(3)  Thrift官方的IDL示例文件(自己写IDL文件时可以此为参考):

https://git-wip-us.apache.org/repos/asf?p=thrift.git;a=blob_plain;f=test/ThriftTest.thrift;hb=HEAD

(4)  各种环境下搭建Thrift的方法:

http://thrift.apache.org/docs/install/

该页面中共提供了CentOS\Ubuntu\OS X\Windows几种环境下的搭建Thrift环境的方法。

二、  Thrift的使用

Thrift提供跨语言的服务框架,这种跨语言主要体现在它对多种语言的编译功能的支持,用户只需要使用IDL描述好接口函数,只需要一条简单的命令,Thrift就能够把按照IDL格式描述的接口文件翻译成各种语言版本。其实,说搭建Thrift环境的时候,实际上最麻烦的就是搭建Thrift的编译环境,Thrift的编译和通常的编译一样经过词法分析、语法分析等等最终生成对应语言的源码文件,为了能够支持对各种语言的编译,你需要下载各种语言对应的编译时使用的包;

1 编写IDL文件时需要注意的问题

[1]函数的参数要用数字依序标好,序号从1开始,形式为:“序号:参数名”;

[2]每个函数的最后要加上“,”,最后一个函数不加;

[3]在IDL中可以使用/*……*/添加注释

2 IDL支持的数据类型

IDL大小写敏感,它共支持以下几种基本的数据类型:

[1]string, 字符串类型,注意是全部小写形式;例如:string aString

[2]i16, 16位整形类型,例如:i16 aI16Val;

[3]i32,32位整形类型,对应C/C++/java中的int类型;例如:      I32  aIntVal

[4]i64,64位整形,对应C/C++/java中的long类型;例如:I64 aLongVal

[5]byte,8位的字符类型,对应C/C++中的char,java中的byte类型;例如:byte aByteVal

[6]bool, 布尔类型,对应C/C++中的bool,java中的boolean类型; 例如:bool aBoolVal

[7]double,双精度浮点类型,对应C/C++/java中的double类型;例如:double aDoubleVal

[8]void,空类型,对应C/C++/java中的void类型;该类型主要用作函数的返回值,例如:void testVoid(),

除上述基本类型外,ID还支持以下类型:

[1]map,map类型,例如,定义一个map对象:map<i32, i32> newmap;

[2]set,集合类型,例如,定义set<i32>对象:set<i32> aSet;

[3]list,链表类型,例如,定义一个list<i32>对象:list<i32> aList;

 在Thrift文件中自定义数据类型

在IDL中支持两种自定义类型:枚举类型和结构体类型,具体如下:

[1]enum, 枚举类型,例如,定义一个枚举类型:

enum Numberz
{
  ONE = 1,
  TWO,
  THREE,
  FIVE = 5,
  SIX,
  EIGHT = 8
}
注意,枚举类型里没有序号

[2]struct,自定义结构体类型,在IDL中可以自己定义结构体,对应C中的struct,c++中的struct和class,java中的class。例如:

struct TestV1 {
       1: i32 begin_in_both,
       3: string old_string,
       12: i32 end_in_both
}
注意,在struct定义结构体时需要对每个结构体成员用序号标识:“序号: ”。

(4)  定义类型别名

Thrift的IDL支持C/C++中类似typedef的功能,例如:

typedefi32  Integer

就可以为i32类型重新起个名字Integer。

2.4、  生成Thrift服务接口文件

搭建Thrift编译环境之后,使用下面命令即可将IDL文件编译成对应语言的接口文件:

thrift --gen <language> <Thrift filename>

这里有以下几点需要说明:

[1]在同步方式使用客户端和服务器的时候,socket是被一个函数调用独占的,不能多个调用同时使用一个socket,例如通过m_transport.open()打开一个socket,此时创建多个线程同时进行函数调用,这时就会报错,因为socket在被一个调用占着的时候不能再使用;

[2]可以分时多次使用同一个socket进行多次函数调用,即通过m_transport.open()打开一个socket之后,你可以发起一个调用,在这个次调用完成之后,再继续调用其他函数而不需要再次通过m_transport.open()打开socket;

需要注意的问题

(1)Thrift的服务器端和客户端使用的通信方式要一样,否则便无法进行正常通信;

Thrift的服务器端的种模式所使用的通信方式并不一样,因此,服务器端使用哪种通信方式,客户端程序也要使用这种方式,否则就无法进行正常通信了。例如,上面的代码2.3中,服务器端使用的工作模式为TNonblockingServer,在该工作模式下需要采用的传输方式为TFramedTransport,也就是在通信过程中会将tcp的字节流封装成一个个的帧,此时就需要客户端程序也这么做,否则便会通信失败。出现如下问题:

服务器端会爆出如下出错log:

2015-01-06 17:14:52.365 ERROR [Thread-11] Read an invalid frame size of -2147418111. Are you using TFramedTransport on the client side?

应用技巧

(1)  为调用加上一个事务ID

在分布式服务开发过程中,一次事件(事务)的执行可能跨越位于不同机子上多个服务程序,在后续维护过程中跟踪log将变得非常麻烦,因此在系统设计的时候,系统的一个事务产生之处应该产生一个系统唯一的事务ID,该ID在各服务程序之间进行传递,让一次事务在所有服务程序输出的log都以此ID作为标识。

在使用Thrift开发服务器程序的时候,也应该为每个接口函数提供一个事务ID的参数,并且在服务器程序开发过程中,该ID应该在内部函数调用过程中也进行传递,并且在日志输出的时候都加上它,以便问题跟踪。

(2)  封装返回结果

Thrift提供的RPC方式的服务,使得调用方可以像调用自己的函数一样调用Thrift服务提供的函数;在使用Thrift开发过程中,尽量不要直接返回需要的数据,而是将返回结果进行封装,例如上面的例子中的getStr函数就是直接返回了结果string,见Thrift文件test_service.thrift中对该函数的描述:

在实际开发过程中,这是一种很不好的行为,在返回结果为null的时候还可能造成调用方产生异常,需要对返回结果进行封装,例如:

/*String类型返回结果*/
struct ResultStr
{
  1: ThriftResult result,
  2: string value
}
其中ThriftResult是自己定义的枚举类型的返回结果,在这里可以根据自己的需要添加任何自己需要的返回结果类型:

enum ThriftResult
{
  SUCCESS,           /*成功*/
  SERVER_UNWORKING,  /*服务器处于非Working状态*/
  NO_CONTENT,           /*请求结果不存在*/
  PARAMETER_ERROR,     /*参数错误*/
  EXCEPTION,          /*内部出现异常*/
  INDEX_ERROR,         /*错误的索引或者下标值*/
  UNKNOWN_ERROR,      /*未知错误*/
  DATA_NOT_COMPLETE,      /*数据不完全*/
  INNER_ERROR,      /*内部错误*/
}

此时可以将上述定义的getStr函数修改为:

ResultStr  getStr(1:string srcStr1, 2:string srcStr2)

在此函数中,任何时候都会返回一个ResultStr对象,无论异常还是正常情况,在出错时还可以通过ThriftResult返回出错的类型。

将服务与数据类型分开定义

在使用Thrift开发一些中大型项目的时候,很多情况下都需要自己封装数据结构,例如前面将返回结果进行封装的时候就定义了自己的数据类型ResultStr,此时,将数据结构和服务分开定义到不通的文件中,可以增加thrift文件的易读性。例如:

在thrift文件:thrift_datatype.thrift中定义数据类型,如:

namespace java com.browan.freepp.thriftdatatype
const string VERSION = "1.0.1"
/**为ThriftResult添加数据不完全和内部错误两种类型
*/

/****************************************************************************************************
* 定义返回值,
* 枚举类型ThriftResult,表示返回结果,成功或失败,如果失败,还可以表示失败原因
* 每种返回类型都对应一个封装的结构体,该结构体其命名遵循规则:"Result" + "具体操作结果类型",结构体都包含两部分内容:
* 第一部分为枚举类型ThriftResult变量result,表示操作结果,可以 表示成功,或失败,失败时可以给出失败原因
* 第二部分的变量名为value,表示返回结果的内容;
*****************************************************************************************************/
enum ThriftResult
{
  SUCCESS,           /*成功*/
  SERVER_UNWORKING,  /*服务器处于非Working状态*/
  NO_CONTENT,           /*请求结果不存在*/
  PARAMETER_ERROR,     /*参数错误*/
  EXCEPTION,          /*内部出现异常*/
  INDEX_ERROR,         /*错误的索引或者下标值*/
  UNKNOWN_ERROR      /*未知错误*/
  DATA_NOT_COMPLETE      /*数据不完全*/
  INNER_ERROR      /*内部错误*/
}

/*bool类型返回结果*/
struct ResultBool 
{
  1: ThriftResult result,
  2: bool value
}

/*int类型返回结果*/
struct ResultInt
{
  1: ThriftResult result,
  2: i32 value
}

/*String类型返回结果*/
struct ResultStr
{
  1: ThriftResult result,
  2: string value
}

/*long类型返回结果*/
struct ResultLong
{
  1: ThriftResult result,
  2: i64 value
}

/*double类型返回结果*/
struct ResultDouble
{
  1: ThriftResult result,
  2: double value
}

/*list<string>类型返回结果*/
struct ResultListStr 
{
  1: ThriftResult result,
  2: list<string> value
}

/*Set<string>类型返回结果*/
struct ResultSetStr 
{
  1: ThriftResult result,
  2: set<string> value
}

/*map<string,string>类型返回结果*/
struct ResultMapStrStr 
{
  1: ThriftResult result,
  2: map<string,string> value
}

由于在接口服务定义的thrift文件test_service.thrift中要用到对数据类型定义的thrift文件:thrift_datatype.thrift,因此需要在其文件前通过include把自己所使用的thrift文件包含进来,另外在使用其他thrift文件中定义的数据类型时要加上它的文件名,如:thrift_datatype.ResultStr

(4)  为Thrift文件添加版本号

在实际开发过程中,还可以为Thrift文件加上版本号,以方便对thrift的版本进行控制
原文链接:https://blog.csdn.net/houjixin/article/details/42778335

thrift编写规则,及常见问题相关推荐

  1. Makefile文件的编写规则

    欢迎大家关注笔者,你的关注是我持续更博的最大动力 Makefile文件编写规则 文章目录: 1 makefile文件介绍 2 makefile文件编写 1 makefile文件介绍 makefile是 ...

  2. html-edm(邮件营销)编写规则

    最近写了一个edm邮件 以前没有接触过  使用的是很老的html页面编写规则  只能用table标签  在此记录一下edm编写的一些规则 个人参考的是这两个网址,转载一下 http://www.zco ...

  3. Docker Compose学习之docker-compose.yml编写规则 及 实战案例

    [Docker那些事]系列文章 docker 安装 与 卸载 centos Dockerfile 文件结构.docker镜像构建过程详细介绍 Dockerfile文件中CMD指令与ENTRYPOINT ...

  4. SQLServer存储过程编写规则

    SQLServer编写规则 1.  存储过程 a)         在程序应用中,对于数据库"写"操作的功能通过存储过程来实现. b)        存储过程命名: SP_+表名( ...

  5. selenium+unittest自动化测试(一)---环境搭建及用例编写规则

    目录 一.selenium.unittest简介 二.环境搭建 1.安装selenium库 2.安装unittest2框架 3.安装浏览器驱动 三.编写规则 1.测试类 2.以test开头 3.set ...

  6. linux之vim下载及编写规则

    1. vim下载 下载命令 yum -y install vim 安装成功界面当你输入vim时,如下图 2. 编写规则

  7. IDS入侵检测系统与开源IDS-snort的安装与编写规则

    目录 IDS的简介.分类与发展 1.Intrusion Detection System ​编辑2.IDS的分类 3.发展应用趋势 4.IDS的局限性 5.IDS与WAF的区别 开源IDS-Snort ...

  8. 浙大计算机学院博士毕业论文要求,浙江大学博士论文编写规则.doc

    浙江大学博士论文编写规则 浙江大学研究生学位论文编写规则 为规范我校研究生学位论文编写格式,根据<科学技术报告.学位论文和学术论文的编写格式>(GB/T 7713-1987)和<学位 ...

  9. 【oracle存储过程】-编写及调用常见问题

    [oracle存储过程]-编写及调用常见问题 大把的学习资源 1.先能看懂,再学会编写 华为出品-基本存储过程:https://support.huaweicloud.com/devg-dws/dws ...

  10. 【testbench】第1篇:testbench编写规则

    本文依据网络资料及工作经验整理而成,如有错误请留言. 文章为个人辛苦整理,付费内容,禁止私自转载. 文章专栏:<黑猫的FPGA知识合集> 1 概述 实现仿真需要自己增加testbench文 ...

最新文章

  1. 关于html和CSS的几个基本知识点
  2. python怎么做回归分析_如何在Python中进行二维回归分析?
  3. 安装ElasticSearch过程遇到的坑
  4. 用python写网络爬虫 第2版 pd_用Python写网络爬虫(第2版)
  5. position based dynamics
  6. jsf UIComponent组件接口详细注释说明(jsf1.1规范)
  7. Gym 100342E Minima (暴力,单调队列)
  8. linq to sql取出随机记录/多表查询/将查询出的结果生成xml
  9. 多备份与Symantec NBU备份软件对比
  10. Drug X跨越鸿沟:一个生物科学家的新药研发跋涉记
  11. 格雷码与二进制之间的转换
  12. Kylo 之 spark-job-profiler 源码阅读
  13. 10-新闻发布系统数据库-新闻管理数据操作
  14. 打印机连接计算机用什么端口,如何设置打印机端口,打印机端口设置的方法步骤...
  15. 2022/12/11创建openai账号(chatgpt)
  16. 对象数组中根据某个属性名的值相同,求某一项的和。
  17. 一行代码能实现什么丧心病狂的功能?
  18. 稚晖君_瀚文机械键盘
  19. 阿里云服务器:域名解析步骤
  20. MacBook Pro 一月使用体验

热门文章

  1. 刀魔王带你了解创口贴圆辊刀模的应用
  2. 服务器日志显示意外关闭,服务器多次异常关闭,错误日志:计算机已经从检测错误后重新启动。。检测错误: - Microsoft Community...
  3. LODOP直接用base64码输出图片
  4. r语言算巢式设计方差分析_R语言学习笔记(七):方差分析
  5. 方位角的表示及示意图
  6. pycharm画图出现Font family [‘Micro- soft YaHei‘] not found. Falling back to DejaVu Sans.的错误
  7. R_展示变量之间关系的图形
  8. Android超炫图片浏览器代码
  9. 对比excel 轻松学python百度云_解读《对比Excel轻松学习Python数据分析》
  10. layui列表筛选列_基于layui实现高级搜索(筛选)功能