您的位置:首页 > 运维架构 > Apache

Apache Thrift 配置和使用指南

2017-03-16 12:00 946 查看

Thrift 安装

Mac 下 Thrift 安装

快速安装

使用 Mac 的包管理器 Homebrew。首先安装 Homebrew:

ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)"[/code] 
使用 Homebrew 安装 thrift:

brew install thrift


如需手动安装特定版本,请参考以下若干小节。

手动安装

首先编译安装 Thrift 的依赖 Boost 和 libevent,然后编译安装 Thrift。

安装 Boost

boost.org 下载 boost 库,解压进入文件夹,并通过以下命令编译:

./bootstrap.sh
sudo ./b2 threading=multi address-model=64 variant=release stage install


Boost 库是对 C++ 标准库提供扩展的一些 C++ 程序库的总称。

安装 libevent

libevent.org 下载 libevent, 解压并通过如下命令编译安装:

./configure --prefix=/usr/local
make
sudo make install


libevent 是用 C 语言编写的、轻量级开源高性能网络库,基于事件驱动且支持跨平台。

安装 Apache Thrift

下载最新版本的 Apache Thrift,解压并通过如下命令编译安装:

./configure --prefix=/usr/local/  \
--with-boost=/usr/local           \
--with-libevent=/usr/local        \
--without-ruby ## 不需要的语言可以通过 --without-[language] 去掉


运行时可能会报错:
Bison version 2.5 or higher must be installed on the system!
。参考 How to install bison on mac OSX 解决:

brew install bison
brew link bison --force


brew link bison
是在系统路径下添加 bison 的 symlinks。在装完 thrift 之后记得:

brew unlink bison


Ubuntu 下 Thrift 配置

参考链接

[1] Debian/Ubuntu install

[2] Building from source

[3] Apache Thrift Tutorial

安装依赖

执行命令:

sudo apt-get install automake bison flex g++ git libboost1.55-all-dev libevent-dev libssl-dev libtool make pkg-config


安装 Thrift

Thrift 官网 下载最新的打包文件,解压后进入文件夹,输入如下命令编译安装:

./configure && make && sudo make install


Thrift C++ 实例

本节中我们实现一个简单的加减乘除计算器 C/S 实例。

基本过程

编写接口描述文件 calculator.thrift,定义数据类型和服务接口

编译 calculator.thrift 生成 gen-cpp 源代码文件夹

编写 server 代码,引用 gen-cpp 与 thrift 库目录编译

编写 client 代码,引用 gen-cpp 与 thrift 库目录编译

运行 ./server

运行 ./client

Thrift 脚本

假设服务端(Server)为客户端(Client)提供简单的数学运算功能,编写 calculator.thrift 脚本文件如下:

namespace cpp MathServer

service MathService{
i32 add (1:i32 a, 2:i32 b),
i32 sub (1:i32 a, 2:i32 b),
i32 mul (1:i32 a, 2:i32 b),
i32 div (1:i32 a, 2:i32 b),
i32 mod (1:i32 a, 2:i32 b)
}


编译 Thrift 脚本的基本命令格式为:

thrift --gen <language> <Thrift filename>


如果在一个 .thrift 文件里包含了其他的 .thrift 文件,需要递归编译,执行:

thrift --gen -r <language> <Thrift filename>


本例中,我们执行如下命令编译:

thrift --gen cpp calculator.thrift


在当前目录下会生成一个 gen-cpp 文件夹。文件夹里包含 MathService.h/cpp, calculator_constants.h/cpp, calculator_types.h/cpp 和 MathService_server.skeleton.cpp 7 个文件。前 6 个文件用于接口定义,需要同时被 Client 和 Server 代码引用(调用或实现),而 MathService_server.skeleton.cpp 则提供了 Server 端代码的一个基本框架。

Server 程序

新建 calculator 文件夹,把 gen-cpp 复制进去,并将 gen-cpp 里的 MathService_server.skeleton.cpp 重命名为 server.cpp,移动到 server 文件夹。实现 server.cpp 后的完整代码如下:

// This autogenerated skeleton file illustrates how to build a server.
// You should copy it to another filename to avoid overwriting it.

#include "gen-cpp/MathService.h"
#include <iostream>
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TBufferTransports.h>

using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace ::apache::thrift::server;

using boost::shared_ptr;

using namespace  ::MathServer;

class MathServiceHandler : virtual public MathServiceIf {
public:
MathServiceHandler() {
// Your initialization goes here
}

int32_t add(const int32_t a, const int32_t b) {
return a + b;
}

int32_t sub(const int32_t a, const int32_t b) {
return a - b;
}

int32_t mul(const int32_t a, const int32_t b) {
return a * b;
}

int32_t div(const int32_t a, const int32_t b) {
return a / b;
}

int32_t mod(const int32_t a, const int32_t b) {
return a % b;
}

};

int main(int argc, char** argv) {
int port = 9090;
shared_ptr<MathServiceHandler> handler(new MathServiceHandler());
shared_ptr<TProcessor> processor(new MathServiceProcessor(handler));
shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());

TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);

std::cout << "Start server..." << std::endl;
server.serve();
return 0;
}


Client 程序

在 calculator 文件夹里新建 client.cpp 文件,代码如下:

#include <iostream>

#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/transport/TSocket.h>
#include <thrift/transport/TTransportUtils.h>

#include "gen-cpp/MathService.h"

using namespace std;
using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;

using boost::shared_ptr;

using namespace  ::MathServer;

int main(int argc, char** argv) {
int port = 9090;
boost::shared_ptr<TTransport> socket(new TSocket("localhost", port));
boost::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));
MathServiceClient client(protocol);

try {
transport->open();

cout << "1 + 1 = " << client.add(1, 1) << endl;
cout << "1 * 2 = " << client.mul(1, 2) << endl;
cout << "8 / 2 = " << client.div(8, 2) << endl;

transport->close();
} catch (TException& tx) {
cout << "ERROR: " << tx.what() << endl;
}
}


编译

用 g++ 编译,先针对各个 .cpp 文件生成 .o 目标,然后链接 thrift 库,生成可执行文件 client 和 server。由于 thrift 里用到 c++11 里的 bind 方法,需要指定
-std=c++11
。假设 thrift 库安装在 /usr/local/lib 里,thrift 的头文件在 /usr/local/include/thrift 中,则完整的编译命令如下:

# build object files
g++ -I/usr/local/include -std=c++11 -c -o \
gen-cpp/calculator_constants.o gen-cpp/calculator_constants.cpp
g++ -I/usr/local/include -std=c++11 -c -o \
gen-cpp/calculator_types.o gen-cpp/calculator_types.cpp
g++ -I/usr/local/include -std=c++11 -c -o \
gen-cpp/MathService.o gen-cpp/MathService.cpp

# build server.o
g++ -I/usr/local/include -std=c++11 -c -o \
server.o server.cpp

# build client.o
g++ -I/usr/local/include -std=c++11 -c -o \
client.o client.cpp

# build target files: client, server
g++ -L/usr/local/lib -lthrift -o server server.o \
gen-cpp/calculator_constants.o gen-cpp/calculator_types.o \
gen-cpp/MathService.o
g++ -L/usr/local/lib -lthrift -o client client.o \
gen-cpp/calculator_constants.o gen-cpp/calculator_types.o \
gen-cpp/MathService.o

# clear *.o
rm ./*.o gen-cpp/*.o


可以直接执行以上命令,也可以将以上命令写进一个 build.sh 文件里,然后执行:

sh ./build.sh


生成完 client 和 server 后,分别在两个终端执行
./server
./client
,可以分别看到
Start server...
1 + 1 = 2 ...


综上。

Thrift 脚本语法

Thrift 用于跨语言的 RPC 通信,因此其接口定义文件
*.thrift
中包含的数据结构与函数定义必须对于不同语言都适用。官网的 Thrift Wiki Tutorial 基本包含了所有的 Thrift 语法,无须赘述,这里只是把它复制过来:

#
# Thrift Tutorial
# Mark Slee (mcslee@facebook.com)
#
# This file aims to teach you how to use Thrift, in a .thrift file. Neato. The
# first thing to notice is that .thrift files support standard shell comments.
# This lets you make your thrift file executable and include your Thrift build
# step on the top line. And you can place comments like this anywhere you like.
#
# Before running this file, you will need to have installed the thrift compiler
# into /usr/local/bin.

/**
* The first thing to know about are types. The available types in Thrift are:
*
*  bool        Boolean, one byte
*  byte        Signed byte
*  i16         Signed 16-bit integer
*  i32         Signed 32-bit integer
*  i64         Signed 64-bit integer
*  double      64-bit floating point value
*  string      String
*  map<t1,t2>  Map from one type to another
*  list<t1>    Ordered list of one type
*  set<t1>     Set of unique elements of one type
*
* Did you also notice that Thrift supports C style comments?
*/

// Just in case you were wondering... yes. We support simple C comments too.

/**
* Thrift files can reference other Thrift files to include common struct
* and service definitions. These are found using the current path, or by
* searching relative to any paths specified with the -I compiler flag.
*
* Included objects are accessed using the name of the .thrift file as a
* prefix. i.e. shared.SharedObject
*/
include "shared.thrift"

/**
* Thrift files can namespace, package, or prefix their output in various
* target languages.
*/
namespace cpp tutorial
namespace java tutorial
php_namespace tutorial
namespace perl tutorial
namespace smalltalk.category Thrift.Tutorial

/**
* Thrift lets you do typedefs to get pretty names for your types. Standard
* C style here.
*/
typedef i32 MyInteger

/**
* Thrift also lets you define constants for use across languages. Complex
* types and structs are specified using JSON notation.
*/
const i32 INT32CONSTANT = 9853
const map<string,string> MAPCONSTANT = {'hello':'world', 'goodnight':'moon'}

/**
* You can define enums, which are just 32 bit integers. Values are optional
* and start at 1 if not supplied, C style again.
*              ^ ThriftIDL page says "If no constant value is supplied,
*   the value is either 0 for the first element, or one greater than the
*   preceding value for any subsequent element" so I'm guessing that's a bug.
*   PS: http://enel.ucalgary.ca/People/Norman/enel315_winter1997/enum_types/ states that if values are not supplied, they start at 0 and not 1.
*/
enum Operation {
ADD = 1,
SUBTRACT = 2,
MULTIPLY = 3,
DIVIDE = 4
}

/**
* Structs are the basic complex data structures. They are comprised of fields
* which each have an integer identifier, a type, a symbolic name, and an
* optional default value.
*
* Fields can be declared "optional", which ensures they will not be included
* in the serialized output if they aren't set.  Note that this requires some
* manual management in some languages.
*/
struct Work {
1: i32 num1 = 0,
2: i32 num2,
3: Operation op,
4: optional string comment,
}

/**
* Structs can also be exceptions, if they are nasty.
*/
exception InvalidOperation {
1: i32 what,
2: string why
}

/**
* Ahh, now onto the cool part, defining a service. Services just need a name
* and can optionally inherit from another service using the extends keyword.
*/
service Calculator extends shared.SharedService {

/**
* A method definition looks like C code. It has a return type, arguments,
* and optionally a list of exceptions that it may throw. Note that argument
* lists and exception lists are specified using the exact same syntax as
* field lists in struct or exception definitions.  NOTE: Overloading of
* methods is not supported; each method requires a unique name.
*/

void ping(),

i32 add(1:i32 num1, 2:i32 num2),

i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch),

/**
* This method has an oneway modifier. That means the client only makes
* a request and does not listen for any response at all. Oneway methods
* must be void.
*
* The server may execute async invocations of the same client in parallel/
* out of order.
*/
oneway void zip(),
}

/**
* It's possible to declare more than one service per Thrift file.
*/
service CalculatorExtreme extends shared.SharedService {
void pingExtreme(),
}

/**
* That just about covers the basics. Take a look in the test/ folder for more
* detailed examples. After you run this file, your generated code shows up
* in folders with names gen-<language>. The generated code isn't too scary
* to look at. It even has pretty indentation.
*/


参考链接

[1] Apache Thrift OS X Setup

[2] mac os x10.10 安装thrift

[3] Thrift C++ Tutorial
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  thrift