在企业应用中RPC的使用可以说是十分的广泛,使用该技术可以方便的与各种程序交互而不用考虑其编写使用的语言。

如果你对RPC的概念还不太清楚,可以点击这里

现今市面上已经有许多应用广泛的RPC框架,比如GRPC,而今天我们要介绍的是同样使用广泛的Apache Thrift。这篇文章将带你安全越过所有坑点,请放心食用。

Thrift简介

Thrift是Facebook的一个开源项目,后来进入Apache进行孵化。Thrift也是支持跨语言的,所以它有自己的一套IDL。目前它支持几乎所有主流的编程语言:C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, OCaml and Delphi and other languages。Thrift可以支持多种信息格式,除了Thrift私有的二进制编码规则和一种LVQ(类似于TLV消息格式)的消息格式,还有常规的JSON格式。Thrift的网络协议建立在TCP协议基础上,并且支持阻塞式IO模型和多路IO复用模型。我们将在后文详细讲解Apache Thrift的使用。Thrift也是目前最流行的RPC框架之一,从网络上各种性能测试情况开,Thrift的性能都是领先的。Thrift的官网地址为:http://thrift.apache.org/

安装

首先是安装golang的库:

go get git.apache.org/thrift.git/lib/go/thrift/...

为了能编译Thrift IDL,我们还得编译thrift-compiler,主要的坑全在这里。

首先,如果你在用ubuntu,千万别用apt去安装,因为官方源和所有ppa里的compiler版本严重过时了;

其次网上的单独编译compiler教程不要看,基本都过时了,现在thrift的版本已经是1.0.0-dev,如果按那些教程编译出来的工具是无法和go get安装的库一起使用的,而且很大概率你连正常编译都无法进行,如果不使用go get,那么可以按照这里的方法2进行安装。(方法2里编译compiler的步骤请跳过,使用我在下面要讲的方法)

好了下面我们开始安装thrift-compiler,首先是安装依赖:

sudo apt-get install libboost-dev libboost-test-dev libboost-program-options-dev libboost-filesystem-dev libboost-thread-dev libevent-dev automake libtool flex bison pkg-config g++ libssl-dev

接着我们clone最新的thrift仓库,然后编译:

git clone https://github.com/apache/thrift
cd thrift
./bootstrap.sh
./configure --without-qt4 --wihout-qt5
make
sudo make install

解释一下,--without-qt*是为了加快编译并防止报错,因为qt始终要依赖moc,很容易出问题而且我们一般也用不到,所以舍去。

如果你也不需要其他语言的生成功能,可以用--without-[name]来去除,具体参见./configure --help。

make也可以改成”make -j N“,N是你cpu可用核心数,并行编译加快速度。

安装好后我们运行thrift命令验证一下安装:

thrift -version
# Thrift version 1.0.0-dev

这样Thrift就算安装完成了。

另外,不使用go get而用源码进行安装时,请保证thrift-compiler和你安装的库的版本相同,否则会有数不清的问题出现。当然,使用go get+自行编译的安装方法不会有这些问题。

Thrift的使用

首先我们要编写IDL文件,定义RPC的接口和数据。如果你还不熟悉thrift IDL的语法,可以参考这里,它和c/c++的语法十分相似,上手起来也较容易。

我们来看一个例子,我们定义一个“compute”模块,在其中定义DivMod(计算商和模)和MulRange(计算阶乘)两个服务,并定义一种包含DivMod计算结果的数据类型:

namespace go compute

struct Result {
: i64 div;
: i64 mod;
} service DivMod {
Result DoDivMod(:i64 arg1, :i64 arg2);
} service MulRange {
string BigRange(:i64 max)
}

Thrift IDL

然后我们用thrift-compiler将其编译成golang代码:

thrift -r --gen go compute.thrift

它会在当前目录下生成一个gen-go目录,在其中有个compute目录,那就是我们生成的模块,copy出来放在$GOPATH里。

接下来我们来实现服务端,现在我们只定义了接口,而没有实现它,建立服务端需要如下几个步骤:

  1. 实现服务处理接口,在1.0版本中,接口第一个参数需要是context.Context,用以支持取消或对RPC调用设置超时。
  2. 创建 Processor,也就是把实现的接口注册进RPC服务创建 Transport,Transport用于管理网络IO。它是一个interface,可以是TSocket,TServerSocket以及NewTHttpClient*或TTransportFactory.GetTransport返回的对象。
  3. 创建 Protocol,也就是传输协议,一般使用二进制协议来传输数据,当然也可以选择json或其他格式。
  4. 创建server,使用前面的Processor,Transport,Protocol以及ip地址来创建服务端。
  5. 运行server。


下面我们先实现接口:

// computeThrift 实现service中定义的方法
type divmodThrift struct {
} // 每个方法除了定义的返回值之外还要返回一个error,包括定义成void的方法。自定义类型会在名字之后加一条下划线
// 暂时用不到context,所以忽略
func (d *divmodThrift) DoDivMod(_ context.Context, arg1, arg2 int64) (*compute.Result_, error) {
divRes := int64(arg1 / arg2)
modRes := int64(arg1 % arg2)
// 生成的用于生成自定义数据对象的函数
res := compute.NewResult_()
res.Div = divRes
res.Mod = modRes return res, nil
} // 尽量一个struct对应一个service
type mulrangeThrift struct {
} func (m *mulrangeThrift) BigRange(_ context.Context, max int64) (string, error) {
result := new(big.Int)
result.SetString("", )
result = result.MulRange(, max) return result.String()
}

接口实现之后我们就要建立并启动服务器了,首先我们先建立Transport:

// 创建服务器
serverTransport, err := thrift.NewTServerSocket(net.JoinHostPort("127.0.0.1", ""))
if err != nil {
fmt.Println("Error!", err)
os.Exit()
}

然后创建传输协议:

// 创建二进制协议
protocolFactory := thrift.NewTBinaryProtocolFactoryDefault()
transportFactory := thrift.NewTFramedTransportFactory(thrift.NewTTransportFactory())

接着我们把实现的接口注册成Processor:

// 创建Processor,用一个端口处理多个服务
divmodProcessor := compute.NewDivModProcessor(new(divmodThrift))
mulrangeProcessor := compute.NewMulRangeProcessor(new(mulrangeThrift)) multiProcessor := thrift.NewTMultiplexedProcessor()
// 给每个service起一个名字
multiProcessor.RegisterProcessor("divmod", divmodProcessor)
multiProcessor.RegisterProcessor("mulrange", mulrangeProcessor)

这里我们用TMultiplexedProcessor来实现一个端口监听多个服务。

最后就是启动服务器:

// 启动服务器
server := thrift.NewTSimpleServer4(multiProcessor, serverTransport, transportFactory, protocolFactory)
server.Serve()
// 退出时停止服务器
defer server.Stop()

启动服务器这里也有坑点,网上有文章说使用NewTSimpleServer2可以直接启用二进制格式的数据传输,这是错的,想用二进制或其他格式传输数据,必须明确生成对应的ProtocolFactory并使用NewTSimpleServer4创建服务器。官方给的例子里就是这样做的,我也是在被反复坑了数次之后才确认了这个问题。

客户端:

要建立客户端,也要按照如下几个步骤:

  1. 创建 Transport
  2. 创建 Protocol
  3. 基于 Potocol 创建 Client
  4. 打开 Transport(不一定要在client创建后才打开,但必须在protocol创建后,接口调用前打开)
  5. 调用接口

下面我们来看代码:

func main() {
// 先建立和服务器的连接的socket,再通过socket建立Transport
socket, err := thrift.NewTSocket(net.JoinHostPort("127.0.0.1", ""))
if err != nil {
fmt.Println("Error opening socket:", err)
os.Exit()
}
transport := thrift.NewTFramedTransport(socket) // 创建二进制协议
protocol := thrift.NewTBinaryProtocolTransport(transport)
// 打开Transport,与服务器进行连接
if err := transport.Open(); err != nil {
fmt.Fprintln(os.Stderr, "Error opening socket to "+"localhost"+":"+"", err)
os.Exit()
}
defer transport.Close() // 接口需要context,以便在长操作时用户可以取消RPC调用
ctx := context.Background() // 使用divmod服务
divmodProtocol := thrift.NewTMultiplexedProtocol(protocol, "divmod")
// 创建代理客户端,使用TMultiplexedProtocol访问对应的服务
c := thrift.NewTStandardClient(divmodProtocol, divmodProtocol) client := compute.NewDivModClient(c)
res, err := client.DoDivMod(ctx, , )
if err != nil {
fmt.Println(err)
os.Exit()
}
fmt.Println(res) // 使用mulrange服务
// 步骤与上面的相同
mulProtocol := thrift.NewTMultiplexedProtocol(protocol, "mulrange")
c = thrift.NewTStandardClient(mulProtocol, mulProtocol)
client2 := compute.NewMulRangeClient(c)
num, err := client2.BigRange(ctx, )
if err != nil {
fmt.Println(err)
os.Exit()
}
fmt.Println(num)
}

当然,大部分情况下我们可能都是用单服务,对于单服务来说,0.11版本的接口和1.0并没有变化,这个找网上的例子即可。

go build之后我们分别运行client和server。

下面是输出,计算了100÷3和100%3的结果,还有100的阶乘,客户端调用接口后检查err,没有错误发生就输出结果:

这样一个支持多服务的RPC示例就完成了。

如果有疑问或者建议,欢迎在评论指出。

祝玩得愉快!

golang高性能RPC:Apache Thrift安装使用完全攻略的更多相关文章

  1. 【转】Hive安装及使用攻略

    Posted: Jul 16, 2013 Tags: HadoophiveHiveQLsql分区表 Comments: 18 Comments Hive安装及使用攻略 让Hadoop跑在云端系列文章, ...

  2. Android-x86虚拟机安装配置全攻略

    转自Android-x86虚拟机安装配置全攻略 注:这里安装从简,具体请参考虚拟机Vmware安装运行安卓4.0详细教程 Android-x86虚拟机安装配置网上有很多,但是全部说明白的确不多,希望这 ...

  3. 【Linux】【secureCRT】下载,安装,激活攻略

    以前公司使用的是SSH访问Linux服务器,今天争取了能看到数据,问了同事使用的是secureCRT,然后自己就装了一个. 下载地址:https://www.vandyke.com/download/ ...

  4. Apache Thrift安装介绍 (ubuntu)

    apache thrift是一种常用的远程服务调用框架. 下面对apache thrift的安装进行介绍: 下面是thrift的源码安装: Debian/Ubuntu (14+) 编译运行依赖安装 $ ...

  5. phpMyAdmin 安装教程全攻略

    管理MYSQL数据库的最好工具是PHPmyAdmin,现在最新版本是phpMyAdmin 2.9.0.2,这是一个国际上开源的软件,一直在更新版本,你可以从 http://www.phpmyadmin ...

  6. 长平狐 Android-x86虚拟机安装配置全攻略

    Android-x86虚拟机安装配置网上有很多,但是全部说明白的确不多,希望这篇文章能把主要的配置介绍给您,帮助您少走一些弯路. 本文分别针对VMWare和Virtual Box两种虚拟机介绍安装配置 ...

  7. Mac安装windows虚拟机攻略

    5月初从阿里滚粗,然后失去了公司发的Mac Air.说实话Mac机器确实比windows好用一些,于是怒而买了一个Mac Pro. 结果一个星期后我从学校带出来的联想笔记本又被老师通知要进行固定资产盘 ...

  8. mysql 在 win 安装 最全攻略(附转载的乱码终极解决方案)以及解决data too long for column 'name' at row 1, 一种可能就是因为编码一致性问题.

    [博客园cnblogs笔者m-yb原创,转载请加链接,公众号aandb7, github.com/mayangbo666,QQ群927113708] https://www.cnblogs.com/m ...

  9. MacBook使用笔记2 - 安装windows虚拟机攻略

    转载请标注原链接:http://www.cnblogs.com/xczyd/p/5498878.html 5月初从阿里滚粗,然后失去了公司发的Mac Air.说实话Mac机器确实比windows好用一 ...

随机推荐

  1. ES6学习:两个面试题目--关于模板字符串

    号称看完就能“让开发飞起来”,不过文中的两个面试题目的知识点并没包括在文中. https://www.jianshu.com/p/287e0bb867ae 文中并没有完整的知识点去完成上面的两道题,这 ...

  2. 关于Apahce服务器安装中遇到的问题

    在这篇中,将记录一下安装Apache服务器所遇到的一些问题,并简单讲一些Apache和Tomcat的区别: 1>apache安装中遇到的问题: 1.1 Apache目前不再提供编译好的exe安装 ...

  3. java面试一、1.3线程与进程

    免责声明:     本文内容多来自网络文章,转载为个人收藏,分享知识,如有侵权,请联系博主进行删除. 1.3.进程和线程 线程和进程的概念.并行和并发的概念 线程和进程: 线程:是程序执行流的最小单元 ...

  4. 2.Spring 拦截器应用

    首先咱们来了解一下具体的业务场景(这个跟第一篇中的很相似但有不同):具体的业务是这样的,现在系统中有六十多个主档(功能模块),每个主档都有新增.修改.删除功能,当我们在对每个主档做这些操作时需要对其记 ...

  5. some knowledge of the IT world

    IT世界一切皆是可信息化(数据的转换)即信息记录一切,对信息的控制{存储,运算,传输{信息的位置转移},转换}就是对一切的控制{硬件(实质维)以信息的控制{软件形式(存在维)}进行操作} 信息本身的实 ...

  6. 使用jquery实现文本框输入特效:文字逐个显示逐个消失反复循环

    前两天看到某个网站上的输入框有个小特效:文字逐个显示,并且到字符串最大长度后,逐个消失,然后重新循环显示消失,循环显示字符串数组.我对这个小特效有点好奇,于是今天自己尝试用jquery写一个简单的小d ...

  7. 复习java基础

    十进制转换成二进制:     方法:整除法,计数方式从右往左,二进制中非0即1.例子如下: 计数方式是从右往左进行,然后填写数字的顺序是余数优先 二进制转换成十进制: 方法:乘二法,例如二进制数字为: ...

  8. 【web渗透技术】渗透攻防Web篇-SQL注入攻击初级

    [web渗透技术]渗透攻防Web篇-SQL注入攻击初级 前言不管用什么语言编写的Web应用,它们都用一个共同点,具有交互性并且多数是数据库驱动.在网络中,数据库驱动的Web应用随处可见,由此而存在的S ...

  9. 面试官问我,使用Dubbo有没有遇到一些坑?我笑了。

    前言 17年的时候,因为一时冲动没把持住(当然最近也有粉丝叫我再冲动一把再更新一波),结合面试题写了一个系列的Dubbo源码解析.目前公众号大部分粉丝都是之前的粉丝,这里不过多介绍. 根据我的面试经验 ...

  10. 从Java到JVM到OS线程睡眠

    Java 中有时需要将线程进入睡眠状态,这时一般我们就会通过 Thread.sleep 使线程进入睡眠状态,接下去就看看执行该语句在 JVM 中做了什么. 简单例子 以下是一个简单的例子,使主线程睡眠 ...