Apache thrift - 使用,内部实现及构建一个可扩展的RPC框架

Posted 三丰SanFeng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Apache thrift - 使用,内部实现及构建一个可扩展的RPC框架相关的知识,希望对你有一定的参考价值。

本文首先介绍了什么是Apache Thrift,接着介绍了Thrift的安装部署及如何利用Thrift来实现一个简单的RPC应用,并简单的探究了一下Thrift的内部实现原理,最后给出一个基于Thrift的可扩展的分布式RPC调用框架,在中小型项目中是一个常见的SOA实践。

Thrift介绍

Apache ThriftFacebook 开发的远程服务调用框架,它采用接口描述语言(IDL)定义并创建服务,支持可扩展的跨语言服务开发,所包含的代码生成引擎可以在多种语言中,如 C++, Java, Python, php, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk 等创建高效的、无缝的服务,其传输数据采用二进制格式,相对 XML JSON 体积更小,对于高并发、大数据量和多语言的环境更有优势。本文将详细介绍 Thrift 的使用,并简要分析Thrift的底层运行原理,最后给出一个基于Thrift的可扩展分布式RPC框架。

Thrift安装部署

首先安装make toolsbison

yum -y install automake gcc gcc-c++

wget http://ftp.gnu.org/gnu/bison/bison-2.5.1.tar.gz

tar -zxvf bison-2.5.1.tar.gz

cd bison-2.5.1

./configure --prefix=/usr/local/

make;make install

然后安装thrift底层依赖库和boost

yum -y install libevent2-devel zlib-devel openssl-devel

wget http://sourceforge.net/projects/boost/files/boost/1.55.0/boost_1_55_0.tar.gz

tar -zxvf boost_1_55_0.tar.gz

cd boost_1_55_0

./bootstrap.sh

./b2 install

安装Thrift

Wget http://www.apache.org/dyn/closer.cgi?path=/thrift/0.9.3/thrift-0.9.3.tar.gz

cd thrift-0.9.3

./configure;make;make install

Thrift cpp源码类介绍

Thrift代码包(位于thrift-0.9.3/lib/cpp/src)有以下几个目录:

concurrency:并发和时钟管理方面的库

processorProcessor相关类

protocolProtocal相关类

transporttransport相关类

serverserver相关类

async:异步rpc相关类

Thrift实现实例

这里介绍一个简单的 Thrift 实现实例,使读者能够快速直观地了解什么是 Thrift 以及如何使用 Thrift 构建服务。

创建一个简单的服务Log

首先根据 Thrift 的语法规范编写脚本文件 log.thrift,代码如下:

struct LogInfo {
1: required string name,
2: optional string content,
}

service LogSender {
void SendLog(1:list<LogInfo> loglist);
string GetLog(1:string logname);
}

其中定义了服务 Log 的两个方法,每个方法包含一个方法名,参数列表和返回类型。每个参数包括参数序号,参数类型以及参数名。 Thrift 是对 IDL(Interface Definition Language) 描述性语言的一种具体实现。因此,以上的服务描述文件使用 IDL 语法编写。使用 Thrift 工具编译 log.thrift,就会生成相应的 LogSender.cpp 文件。该文件包含了在 log.thrift 文件中描述的服务Log的接口定义以及服务调用的底层通信细节,用于构建客户端和服务器端的功能。

调用thrift命令生成代码,命令为thrift --gen <language> <Thrift filename>

[[email protected] log_thrift]# thrift -gen cpp log.thrift

[[email protected] log_thrift]# tree gen-cpp/

gen-cpp/

── log_constants.cpp

── log_constants.h

── LogSender.cpp

── LogSender.h

── LogSender_server.skeleton.cpp

── log_types.cpp

└── log_types.h

Thrift文件与生成的代码对应关系

每个thrift文件会产生四个文件,分别为:${thrift_name}_constants.h${thrift_name}_constants.cpp${thrift_name}_types.h${thrift_name}_types.cpp

对于含有servicethrift文件,会额外生成两个文件,分别为:${service_name}.h${service_name}.cpp

对于含有servicethrift文件,会生成一个可用的server桩:${service_name}_server.skeleton.cpp

 

一个阻塞式服务器实现server.cpp

#include "gen-cpp/LogSender.h"
#include <map>
#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;
std::map<std::string, std::string> logMap;

class LogSenderHandler : virtual public LogSenderIf {
 public:
  LogSenderHandler() {
    // Your initialization goes here
  }

  void SendLog(const std::vector<LogInfo> & loglist) {
    // Your implementation goes here
    sleep(5);
    time_t now = time(NULL);
    printf("SendLog, now = %s\n", ctime(&now));
    for (size_t i = 0; i < loglist.size(); ++i)
    {
      if (logMap.find(loglist[i].name) == logMap.end())
      {
        printf("name=[%s], content=[%s]\n", loglist[i].name.c_str(), loglist[i].content.c_str());
        logMap.insert(std::make_pair(loglist[i].name, loglist[i].content));
      }
    }
  }

  void GetLog(std::string& _return, const std::string& logname) {
    // Your implementation goes here
    std::map<std::string,std::string>::iterator iter = logMap.find(logname);
    if (iter != logMap.end())
    {
      _return = iter->second;
    }
    else
    {
      _return = "Not Found!";
    }
  }

};

int main(int argc, char **argv) 
{
  int port = 9090;
  shared_ptr<LogSenderHandler> handler(new LogSenderHandler());
  shared_ptr<TProcessor> processor(new LogSenderProcessor(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);
  server.serve();
  return 0;
}

阻塞式服务器对应客户端实现client.cpp

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>以上是关于Apache thrift - 使用,内部实现及构建一个可扩展的RPC框架的主要内容,如果未能解决你的问题,请参考以下文章

使用 Apache Thrift 的 Java 编译错误

Apache Thrift:简单的使用demo

使用 Apache Thrift 实现具有 HTTP 协议的服务器/客户端

Apache Thrift学习之二(基础及原理)

Thrift总结介绍

Java分布式RPC通信框架Apache Thrift 使用总结