文档章节

Thrift 指导文档 [0.9.2]

强子哥哥
 强子哥哥
发布于 2015/08/23 10:24
字数 1677
阅读 582
收藏 12
点赞 0
评论 0

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

 

 

 

 

 

 

 

 

 

 

 

 

 

© 著作权归作者所有

共有 人打赏支持
强子哥哥

强子哥哥

粉丝 856
博文 551
码字总数 647493
作品 8
南京
架构师
Thrift抛直接内存OOM一点解决思路

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

囚兔 ⋅ 2015/05/22 ⋅ 0

LUA--thrift--lib库的创建生成

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

senlin1202 ⋅ 2017/12/18 ⋅ 0

Node 与 Thrift

背景:公司要用Node与其他语言(Java)写的服务通信。 1,服务端 helloServer.js var thrift = require('thrift');var helloService = require('./HelloService');var server = thrift.creat......

我擦_得弄个昵称 ⋅ 2015/04/16 ⋅ 0

MapD 核心数据库--MapD Core

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

匿名 ⋅ 2017/05/09 ⋅ 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 ⋅ 15

C3P0 目前最新版本 0.9.2-pre5

C3P0 一直有在更新,最新一次是节前 9月29日 提交的 0.9.2 Pre5 版本,下载地址: http://sourceforge.net/projects/c3p0/files/c3p0-bin/c3p0-0.9.2-pre5/ 改进记录: c3p0-0.9.2-pre5 -- S...

oschina ⋅ 2012/10/11 ⋅ 6

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 ⋅ 0

Appweb v5.4.6/6.0.2/4.7.4 发布

Appweb v5.4.6/6.0.2/4.7.4 发布,其中6.0.2是个小的分支发布,更新内容如下: 建议: Essential Upgrade -- All users strongly advised to upgrade Recommended Upgrade -- Upgrade recomm......

oschina ⋅ 2015/08/14 ⋅ 0

PoDoFo 0.9.2 发布,C++ 的 PDF 类库

PoDoFo 0.9.2 修复了堆损害、对象流等方面的问题,基于 OpenSSL 的新的加密方法支持。 PoDoFo 是一个用来操作 PDF 文件格式的 C++ 类库。它还包含一些小工具用来解析、修改和创建 PDF 文档。...

oschina ⋅ 2013/02/24 ⋅ 4

比较跨语言通讯框架:Apache Thrift和Google Protobuf

前两天想在微博上发表一个观点:在现在的技术体系中,能用于描述通讯协议的方式很多,xml,json,protobuf,thrift,如果在有如此众多选择的基础上,在设计系统时,还自造协议,自己设计协议类...

摆渡者 ⋅ 2014/07/12 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Spring | IOC AOP 注解 简单使用

写在前面的话 很久没更新笔记了,有人会抱怨:小冯啊,你是不是在偷懒啊,没有学习了。老哥,真的冤枉:我觉得我自己很菜,还在努力学习呢,正在学习Vue.js做管理系统呢。即便这样,我还是不...

Wenyi_Feng ⋅ 今天 ⋅ 0

博客迁移到 https://www.jianshu.com/u/aa501451a235

博客迁移到 https://www.jianshu.com/u/aa501451a235 本博客不再更新

为为02 ⋅ 今天 ⋅ 0

win10怎么彻底关闭自动更新

win10自带的更新每天都很多,每一次下载都要占用大量网络,而且安装要等得时间也蛮久的。 工具/原料 Win10 方法/步骤 单击左下角开始菜单点击设置图标进入设置界面 在设置窗口中输入“服务”...

阿K1225 ⋅ 今天 ⋅ 0

Elasticsearch 6.3.0 SQL功能使用案例分享

The best elasticsearch highlevel java rest api-----bboss Elasticsearch 6.3.0 官方新推出的SQL检索插件非常不错,本文一个实际案例来介绍其使用方法。 1.代码中的sql检索 @Testpu...

bboss ⋅ 今天 ⋅ 0

informix数据库在linux中的安装以及用java/c/c++访问

一、安装前准备 安装JDK(略) 到IBM官网上下载informix软件:iif.12.10.FC9DE.linux-x86_64.tar放在某个大家都可以访问的目录比如:/mypkg,并解压到该目录下。 我也放到了百度云和天翼云上...

wangxuwei ⋅ 今天 ⋅ 0

PHP语言系统ZBLOG或许无法重现月光博客的闪耀历史[图]

最近在写博客,希望通过自己努力打造一个优秀的教育类主题博客,名动江湖,但是问题来了,现在写博客还有前途吗?面对强大的自媒体站点围剿,还有信心和可能型吗? 至于程序部分,我选择了P...

原创小博客 ⋅ 今天 ⋅ 0

IntelliJ IDEA 2018.1新特性

工欲善其事必先利其器,如果有一款IDE可以让你更高效地专注于开发以及源码阅读,为什么不试一试? 本文转载自:netty技术内幕 3月27日,jetbrains正式发布期待已久的IntelliJ IDEA 2018.1,再...

Romane ⋅ 今天 ⋅ 0

浅谈设计模式之工厂模式

工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 在工厂模式中,我们在创建对象时不会对客户端暴露创建逻...

佛系程序猿灬 ⋅ 今天 ⋅ 0

Dockerfile基础命令总结

FROM 指定使用的基础base image FROM scratch # 制作base image ,不使用任何基础imageFROM centos # 使用base imageFROM ubuntu:14.04 尽量使用官方的base image,为了安全 LABEL 描述作...

ExtreU ⋅ 昨天 ⋅ 0

存储,对比私有云和公有云的不同

导读 说起公共存储,很难不与后网络公司时代的选择性外包联系起来,但尽管如此,它还是具备着简单和固有的可用性。公共存储的名字听起来也缺乏专有性,很像是把东西直接堆放在那里而不会得到...

问题终结者 ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部