文档章节

Thrift 指导文档 [0.9.2]

强子1985
 强子1985
发布于 2015/08/23 10:24
字数 1677
阅读 623
收藏 12

0 前言

Thrift 是一个软件框架(远程过程调用框架),用来进行可扩展且跨语言的服务的开发。它结合了功能强大的软件堆栈和代码生成引 擎,以构建在 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 这些编程语言间无缝结合的、高效的服务。

thrift最初由facebook开发,07年四月开放源码,08年5月进入apache孵化器,现在是 Apache 基金会的顶级项目

thrift允许你定义一个简单的定义文件中的数据类型和服务接口,以作为输入文件,编译器生成代码用来方便地生成RPC客户端和服务器通信的无缝跨编程语言。。

著名的 Key-Value 存储服务器 Cassandra 就是使用 Thrift 作为其客户端API的。

 

1 编译环境

参考 http://thrift.apache.org/docs/install/centos 

一步一步来就行了。 

看到如下的提示就OK了。

 

2 脚本文件

2.1 编写

文件清单:  Hello.thrift

namespace java service.demo

 service Hello{

  string helloString(1:string para)

  i32 helloInt(1:i32 para)

  bool helloBoolean(1:bool para)

  void helloVoid()

  string helloNull()

 }

 

说明:

定义了服务Hello5个方法。

方法格式: 返回类型  方法名     参数列表

参数格式:   参数序号  参数类型   参数名

 

2.2 编译

使用Thrift工具编译Hello.thrift,就可以生成对应的Hello.java文件,该文件包含了在 Hello.thrift 文件中描述的服务 Hello 的接口定义,即 Hello.Iface 接口,以及服务调用的底层通信细节,包括客户端的调用逻辑 Hello.Client 以及服务器端的处理逻辑 Hello.Processor,用于构建客户端和服务器端的功能。

 

具体编译过程:

 

可以看到,编译成功,生成了一个文件夹gen-java.

我们来看看这个文件夹下面有什么。

 

可以看到产生了一个文件

 

3 Thrift例子

3.1 新建工程

新建一个java project.

然后按照http://www.ibm.com/developerworks/cn/java/j-lo-apachethrift/

的做法,在工程里引入HelloServiceImpl.javaHelloServiceServer.javaHelloServiceClient.java

不要忘了要引入根据脚本生成的那个Hello.java.

这样,工程里就有4个文件。

 

3.2 引入thrift源码

此时,eclipse肯定报错,因为我们还没有引入Thrift的源码。

下载地址

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

解压缩后,源码位置在

 

将文件夹复制到eclipse里即可。

 

3.3 依赖包

然后加入所依赖的包

 

3.4 兼容性

最后还有最后一个问题,就是HelloServiceServer报错。

提示

 

 

这个构造方法不存在,修改成下面的

TThreadPoolServer.Args tArgs = new TThreadPoolServer.Args(serverTransport);

            tArgs.protocolFactory(proFactory);

            tArgs.processor(processor);

            TServer server = new TThreadPoolServer(tArgs);

 

3.5 运行

然后开始运行整个程序。

启动服务器:

 

 

再启动client

程序顺利执行,client的方法没有输出。

 

我们在client里添加代码如下

String str=client.helloString("hello,Thrift");

            System.out.println("resp:---"+str);

 

观察client输出

 

 至此,Thrift顺利完成运行过程。

下面我们需要来通过研究这个例子的源码来研究Thrift的运行原理。

4 异步IO改造

为了研究Thrift源码,上面的例子需要修改,因为上面的例子没有用到很过高级功能,所以我们需要改造成高级功能,这里参考了文章 http://www.ibm.com/developerworks/cn/java/j-lo-apachethrift/ 

 

HelloServiceAsyncServer.java修改后的源码如下所示: 

package service.server;

 

import org.apache.thrift.TProcessor;

import org.apache.thrift.protocol.TBinaryProtocol;

import org.apache.thrift.server.THsHaServer;

import org.apache.thrift.server.TServer;

import org.apache.thrift.server.TThreadedSelectorServer;

import org.apache.thrift.transport.TFramedTransport;

import org.apache.thrift.transport.TNonblockingServerSocket;

import org.apache.thrift.transport.TNonblockingServerTransport;

import org.apache.thrift.transport.TTransportException;

 

import service.demo.Hello;

import service.demo.HelloServiceImpl;

 

public class HelloServiceAsyncServer {

   

    public static void main(String[] args) {

        try {

          

            // TServerSocket serverTransport = new TServerSocket(7911);

            TNonblockingServerTransport serverTransport = new TNonblockingServerSocket(7911);

            TFramedTransport.Factory transportFactory=new TFramedTransport.Factory();

            //TNonblockingTransport.

            // 设置协议工厂为 TBinaryProtocol.Factory

            TBinaryProtocol.Factory protocolFactory = new TBinaryProtocol.Factory();

            // 关联处理器与 Hello 服务的实现

            TProcessor processor = new Hello.Processor(new HelloServiceImpl());

 

            TThreadedSelectorServer.Args tArgs = new TThreadedSelectorServer.Args(serverTransport);

            tArgs.transportFactory(transportFactory);

            tArgs.protocolFactory(protocolFactory);

            tArgs.processor(processor);

            THsHaServer a;

 

            // TServer server = new TThreadPoolServer(tArgs);

            TServer server = new TThreadedSelectorServer(tArgs);

            System.out.println("Start server on port 7911...");

            server.serve();

        } catch (TTransportException e) {

            e.printStackTrace();

        }

    }

}

 

 HelloServiceSyncClient.java修改后

package service.client;

 

import org.apache.thrift.protocol.TBinaryProtocol;

import org.apache.thrift.protocol.TProtocol;

import org.apache.thrift.transport.TFramedTransport;

import org.apache.thrift.transport.TSocket;

import org.apache.thrift.transport.TTransport;

 

import service.demo.Hello;

 

public class HelloServiceSyncClient {

 

    public static void main(String[] args) throws Exception {

 

        // 设置传输通道,对于非阻塞服务,需要使用TFramedTransport,它将数据分块发送

        TTransport transport = new TFramedTransport(new TSocket("192.168.56.102", 7911));

        transport.open(); 

        // 使用二进制协议

        TProtocol protocol = new TBinaryProtocol(transport); 

        // 创建Client

        Hello.Client client = new Hello.Client(protocol); 

        long start = System.currentTimeMillis();

        for (int i = 0; i < 1; i++) {

            System.out.println("client.helloBoolean(false)---"+client.helloBoolean(false));

            //System.out.println("client.helloInt(111)---"+client.helloInt(111));

            //client.helloNull();

            System.out.println("client.helloString(\"360buy\")---"+client.helloString("360buy"));

            client.helloVoid();

        }

        System.out.println("耗时:" + (System.currentTimeMillis() - start)); 

        // 关闭资源

        transport.close();

    }

}

  

Hello.java & HelloServiceImpl.java 内容保持不变。

读者可自行分析修改过的地方。

运行之,看看是否OK。 

 

5 调试环境Linux

Java提供了强大的jdb工具来调试源码,可以执行程序,进入函数,以及打印当前值。

 

6 原理分析

6.1 线程模型

Thrift的线程模型是怎样的,下面开始讲解

先看代码段1

  @Override

  protected boolean startThreads() {

    try {

      for (int i = 0; i < args.selectorThreads; ++i) {

        selectorThreads.add(new SelectorThread(args.acceptQueueSizePerThread));

      }

      acceptThread = new AcceptThread((TNonblockingServerTransport) serverTransport_,

        createSelectorThreadLoadBalancer(selectorThreads));

      for (SelectorThread thread : selectorThreads) {

        thread.start();

      }

      acceptThread.start();

      return true;

    } catch (IOException e) {

      LOGGER.error("Failed to start threads!", e);

      return false;

    }

  }

 

可以看到这里启动了若干线程。

 

再看代码段2

/**

   * Create the server with the specified Args configuration

   */

  public TThreadedSelectorServer(Args args) {

    super(args);

    args.validate();

    invoker = args.executorService == null ? createDefaultExecutor(args) : args.executorService;

    this.args = args;

  } 

  /**

   * Helper to create the invoker if one is not specified

   */

  protected static ExecutorService createDefaultExecutor(Args options) {

    return (options.workerThreads > 0) ? Executors.newFixedThreadPool(options.workerThreads) : null;

  }

 所以,总的线程图如下图所示:

 

 

 

6

3

Socket

6.2 处理模型

 

 

 

 

 

1)Accept线程通过accept获取一个client.

2)Accept线程通过一定的负载策略(比如轮询)发给某个Selector线程。

3)Selector线程读取新建的Client,注册它的read事件。

4)Selector线程轮询所有注册的Socket的读写事件,当读条件满足时,触发Client的读取事件,拿到一个完整的Frame,封装成Runnable对象,通过(4.1)抛给ExecutorService线程组。同时屏蔽此socketread事件。

5)ExecutorService执行完毕后,保存执行结果在此Runnable对象里,然后返回给Selector线程。

6)Selector线程检查自己的某个写就绪队列,读取,然后注册对应SocketChannelwrite事件。

7)当写条件满足时,会在4中触发写事件,然后将内容发给远程client,发送完毕后,会屏蔽socket的写事件,注册读事件。这样重新来一个新的循环。

 

 

7 客户端连接池

可以采用第三方的连接池组件.

http://www.cnblogs.com/lihaozy/archive/2013/04/22/3035113.html

http://www.cnblogs.com/51cto/archive/2010/08/18/thrift_connection_pool.html

8 集群

方案采用KeepAlive + HaProxy

 

9 序列化协议格式简介

 10 关于Thrift的优缺点讨论

http://www.zhihu.com/question/20189791

参考文档

1 http://www.ibm.com/developerworks/cn/java/j-lo-apachethrift/

2 http://dongxicheng.org/search-engine/thrift-guide/

3 http://m.blog.csdn.net/blog/tianwei7518/44115297 (线程模型选择)

4 http://blog.csdn.net/m13321169565/article/details/7836006

5 http://blog.csdn.net/azhao_dn/article/details/8898610 [到底选择哪种网络模型?看这篇文章就可以了,最终定论]

6 http://www.codelast.com/?p=4824

 

 

 

 

 

 

 

 

 

 

 

 

 

© 著作权归作者所有

共有 人打赏支持
强子1985

强子1985

粉丝 864
博文 996
码字总数 676795
作品 8
南京
架构师
LUA--thrift--lib库的创建生成

首选先参考这个作者些的: thrift是一个比较流行的rpc框架,很多公司都有大规模使用的经验,不过网上很少有关于thrift-lua的介绍和example apache的thrift-lua也是刚刚从fbthrift项目引入,...

senlin1202
2017/12/18
0
0
Thrift抛直接内存OOM一点解决思路

最近使用Thrift TThreadedSelectorServer服务方式,运行一段时间就会抛OutOfMemoryError: Direct buffer memory异常; 很可能是直接内存没有做垃圾回收; “垃圾收集进行时,虚拟机虽然会对D...

囚兔
2015/05/22
0
0
MapD 核心数据库--MapD Core

MapD Core MapD Core 是一个 in-memory、列存储,SQL 关系型数据库,从头开始设计,可在 GPU 上运行。 MapD 一个 SQL 数据库和可视化分析平台,基于 GPU 的并行功能交互查询和可视化大量数据...

匿名
2017/05/09
545
0
C3P0 0.9.2 发布,Java 数据库连接池

著名的 Java 数据库连接池 c3p0 发布了 0.9.2 正式版本,下载地址: c3p0-0.9.2 (二进制) c3p0-0.9.2 (源码) C3P0是一个开放源代码的JDBC连接池,Hibernate的发行包中默认使用此连接池。...

oschina
2013/02/09
2.8K
15
Apache MRQL 0.9.2-incubating 发布

Apache MRQL 0.9.2-incubating 发布,此版本现已提供在这里。 主要更新内容如下: 新特性 [MRQL-23] Add support for Yarn [MRQL-29] Support for Spark 0.9.0 Bugs 修复 [MRQL-22] The comp......

oschina
2014/06/27
231
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring MVC 通过@Value注解读取.properties配置内容

第一步: 在applicationContext.xml配置: <bean id="configProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> <property name="locations">......

wangyanbao
12分钟前
1
0
Rancher 2.1全面发布,优化Kubernetes集群运维

GitLab支持、CICD优化、项目配额管理、驱散容器功能等等,Rancher 2.1给你带来一大票惊喜新功能!还有备着【千元大奖】的用户体验计划等你来参与! Rancher 2.1已于近日全面发布! Rancher ...

RancherLabs
18分钟前
1
0
如何优雅的给淘客/京东及拼多多的代理(会员)发工资(佣金)

前段时间有一些做淘客和京东推广的朋友问我能不能开发一个代付系统,这样他们可以用来给代理和网站会员发工资,他们现在还是用的人工手动打款,不仅效率慢,而且还容易出错,我一想,嗯,不难...

千龍
23分钟前
1
0
try-catch-finally

try-catch-finally 一.执行顺序 try-catch-finally 包含的代码块,当 try 里面的代码出现异常的时候,会进入 catch 中,finally 代码块则在最后被执行,即 无论是否出现异常,finally 里面的...

tsmyk0715
29分钟前
2
0
【编程架构实战】——Java并发包基石-AQS详解

目录 1 基本实现原理 1.1 如何使用 1.2 设计思想 2 自定义同步器 2.1 同步器代码实现 2.2 同步器代码测试 3 源码分析 3.1 Node结点 3.2 独占式 3.3 共享式 4 总结   Java并发包(JUC)中提...

java知识分子
29分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部