正文讲解php通过sql查询hadoop中的数据,对初稿的修改

序言:由于近期在看storm Topology提交进程的源代码,写好的topology
jar文件是经过Thrift 宝马7系PC的花样提交给nimbus的。故驾驭下Thrift的基本原理。

正文讲解php通过sql查询hadoop中的数据。首要选择的技术是:php通过thrift向hive提交sql查询,hive将sql查询转换到hadoop职责,等到hadoop执行完结后,再次回到1个结实uri,然后大家只须求读取那些uri中的内容。

村办学习参考所用,勿喷!

参考:http://dongxicheng.org/search-engine/thrift-rpc/

Thrift的诞生是为了消除区别语言之间的拜访的问题,能够支撑多样程序语言,如c++、php、java、python等。Thrift是由facebook开发的轻量级跨语言的服务框架,现在壹度移交到Apache基金会下。和它相仿的有google出的protocol buffer和ice。Thrift的一大优势是永葆的言语很丰裕,它应用本身的IDL语言来服务接口和数据调换的格式。

 

1,环境:Ubuntu12.04   thrift-0.9.2。安装:

Hive是足以采纳类似sql的语言访问HBase。而HBase是三个开源的nosql产品,它达成了google bigtable杂谈的一个开源产品,和hadoop、hdfs1起,能够用来储存和处理海量column family数据。

初稿地址:http://www.ibm.com/developerworks/cn/java/j-lo-apachethrift/index.html

壹下载安装包并解压,要是解压到/usr/lcoal/thrift-0.九.2/

Thrift的官方网站:http://thrift.apache.org/

 

二安装重视

一.劳动器端下载安装thrift

在hadoop和hbase都曾经设置好的集群上安装thrift。
(1)下载:wget
http://mirror.bjtu.edu.cn/apache//thrift/0.8.0/thrift-0.8.0.tar.gz,下载thrift客户端源码包。

(2)解压:tar -xzf thrift-0.8.0.tar.gz
(3)编写翻译安装:假诺是源码编写翻译的,首先要求执行./bootstrap.sh创造./configure文件;
接下去执行./configure;
再执行make && make install
(4)启动:./bin/hbase-daemon.sh start thrift
Thrift暗中同意监听的端口是9090。
参考链接:http://blog.csdn.net/hguisu/article/details/7298456

对原来的小说的改动:

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

二.创建.thrift文件

Thrift编写翻译器安装好之后,要求创设三个thrift文件。该文件为一个接口定义文件,需求定义thrift的花色(types)和劳务(services)。该文件中定义的劳务(services)是由劳动器端完结的,并由客户端举办调用。Thrift编写翻译器的成效是将您写的thrift文件生成为客户端接口源码,该接口源码是由差别的客户端库和您写的服务来扭转的。为了通过thrift文件发出分歧语言的接口源码,大家须求周转:

thrift –gen <language> <Thrift filename>

1.原稿的劳动器端代码的BUG,不论是0.八.0照旧0.6.一版本的thrift,例如以下的创办server的不二诀窍都难堪(正确结果看校勘后的文中代码):

三,在/usr/lcoal/thrift-0.9.2/运维如下命令:

三.thrift文件讲述

支撑的变量类型

类型           描述     bool            #true, false     byte            #8位的有符号整数     i16             #16位的有符号整数     i32             #32位的有符号整数     i64             #64位的有符号整数     double          #64位的浮点数     string          #UTF-8编码的字符串     binary          #字符数组     struct          #结构体     list<type>        #有序的元素列表,类似于STL的vector     set<type>     #无序的不重复元素集,类似于STL的set     map<type1,type2>  #key-value型的映射,类似于STL的map     exception       #是一个继承于本地语言的exception基类     service         #服务包含多个函数接口(纯虚函数)
TServer server = new TThreadPoolServer(processor, serverTransport, proFactory); 

./configure && make && make install

肆.从服务端到客户端怎么样开发

贰.日增了maven的创设格局。

奇怪的是这里报了个错误:

1.简单的helloworld程序

此间运用python做服务端,php做客户端,当然也能够使用c++来做服务端。上边开端介绍开发流程。

(一)首先大家在服务器端写个helloworld.thrift文件,如下所示:

service HelloWorld{      string ping(1: string name),      string getpng(),   }

(二)在劳动器端编写翻译helloworld.thrift

编写翻译helloworld.thrift文件,会生出服务器端和客户端相应语言的接口源码。
/usr/local/thrift/bin/thrift -r –gen py helloworld.thrift  
/usr/local/thrift/bin/thrift -r –gen php helloworld.thrift  
#会在当前目录下生成 gen-* 目录。
发出的gen-py目录放在服务器上,产生的gen-php目录放在客户端上。
(叁)编写服务器端代码

    import sys       sys.path.append('./gen-py')               from helloworld import HelloWorld       from helloworld.ttypes import *               from thrift.transport import TSocket       from thrift.transport import TTransport       from thrift.protocol import TBinaryProtocol       from thrift.server import TServer               class HellowordHandler:           def __init__ (self):               pass                   def ping (self, name):               print name + ' from server.'               return "%s from server." % name           def getpng (self):               f = open("./logo.png", "rb")               c = f.read()               f.close()               return c       handler = HellowordHandler()       processor = HelloWorld.Processor(handler)       transport = TSocket.TServerSocket(9090)       tfactory = TTransport.TBufferedTransportFactory()       pfactory = TBinaryProtocol.TBinaryProtocolFactory()               server = TServer.TSimpleServer(processor, transport, tfactory, pfactory)               # You could do one of these for a multithreaded server       #server = TServer.TThreadedServer(processor, transport, tfactory, pfactory)       #server = TServer.TThreadPoolServer(processor, transport, tfactory, pfactory)               print 'Starting the server...'       server.serve()       print 'done.'  

(四)编写客户端代码

先将gen-php目录拷贝到客户端上。

<?php   try{       //包含thrift客户端库文件       $GLOBALS['THRIFT_ROOT'] = './php/src';        require_once $GLOBALS['THRIFT_ROOT'].'/Thrift.php';       require_once $GLOBALS['THRIFT_ROOT'].'/protocol/TBinaryProtocol.php';       require_once $GLOBALS['THRIFT_ROOT'].'/transport/TSocket.php';       require_once $GLOBALS['THRIFT_ROOT'].'/transport/THttpClient.php';       require_once $GLOBALS['THRIFT_ROOT'].'/transport/TBufferedTransport.php';        error_reporting(E_NONE);        //包含helloworld接口文件     $GEN_DIR = './gen-php';       require_once $GEN_DIR.'/helloworld/HelloWorld.php';        error_reporting(E_ALL);           $socket = new TSocket('*.*.*.*', 9090);       $transport = new TBufferedTransport($socket, 1024, 1024);       $protocol = new TBinaryProtocol($transport);       $client = new HelloWorldClient($protocol);            $transport->open();           $a = $client->ping('xyq ');       echo $a;           $transport->close();           }catch(TException $tx){           print 'TException: '.$tx->getMessage()."/n";       }       ?>

末尾交给一篇参考链接:http://blog.csdn.net/heiyeshuwu/article/details/5982222

3.校订运营server时候的”Failedto load class
org.slf4j.impl.StaticLoggerBinder”的BUG,参考地址:http://www.slf4j.org/codes.html#StaticLoggerBinder

thrift-t_gv_generator.o: file not recognized: File truncated
collect2: ld returned 1 exit status
make[3]: *** [thrift] 错误 1
make[3]:正在离开目录 `/usr/local/thrift-0.9.2/compiler/cpp'

2.thrift官网上提交的事例

Apache
thrift能够让你在二个简练的.thrift文件中,定义数据类型和劳务接口。将该.thrift文件作为输入文件,通过编写翻译器编写翻译产生服务端和客户端源码,从而创设了奇骏PC客户端和服务器端之间的跨语言编制程序。
上面直接付出关键代码。

(一)thrift定义文件

/*定义的接口数据类型*/ struct UserProfile {         1: i32 uid,         2: string name,         3: string blurb } /*定义的接口函数*/ service UserStorage {         void store(1: UserProfile user),         UserProfile retrieve(1: i32 uid) }

(2)客户端python实现

  # Make an object   up = UserProfile(uid=1,       name="Test User",       blurb="Thrift is great")     # Talk to a server via TCP sockets, using a binary protocol   transport = TSocket.TSocket("localhost", 9090)   transport.open()   protocol = TBinaryProtocol.TBinaryProtocol(transport)    # Use the service we already defined   service = UserStorage.Client(protocol)   service.store(up)    # Retrieve something as well   up2 = service.retrieve(2)

(三)服务器端c++完毕

class UserStorageHandler : virtual public UserStorageIf {    public:     UserStorageHandler() {       // Your initialization goes here     }      void store(const UserProfile& user) {       // Your implementation goes here       printf("store\n");     }      void retrieve(UserProfile& _return, const int32_t uid) {       // Your implementation goes here       printf("retrieve\n");     }   };    int main(int argc, char **argv) {     int port = 9090;     shared_ptr<UserStorageHandler> handler(new UserStorageHandler());     shared_ptr<TProcessor> processor(new UserStorageProcessor(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(); }

四.附属类小部件为maven创设的工程代码

找到出错的公文,发现它的高低为0,然后直接把它移除,再另行运转第 三步中的命令。安装成功。

三.实战经历

(一).thrift接口文件

文件名称叫hive.thrift,如下所示:

namespace java com.gj.data.hive.thrift  /**  * 向HADOOP提交HIVE任务类。典型的用法是提交任务,轮询任务是否完成,取得任务的结果URI,读取结果文件。  *这里展示的是客户端为java语言时的用法。  *           long taskId = client.submitTask("abc@gj.com", "web", "select * from table1 where dt = '2013-04-10' limit 10;");  *           if (taskId <=0) {  *               System.out.println("error submit");  *               return;  *           }               //轮询任务是否完成  *           int count = 50;  *           while(count >= 0) {  *               try {  *                   Thread.sleep(30 * 1000);  *               } catch (InterruptedException ex) {}  *               if (client.isTaskFinished(taskId)) {  *                   System.out.println(client.getResultURI(taskId));  *                   break;  *               }   *               count --;  *          }  */  service Hive {      /** 提交任务      * user - 用户名,工作邮箱,如abc@xxx.com      * env - 提交的环境。目前支持两个环境: mobile - 移动端, web - 主站。      * sql - 提交的sql语句。      * 返回值:成功提交返回大于0的任务id值,此id用于后续查询。失败返回0或-1.      */     i64 submitTask(1:string user, 2:string env, 3:string sql);          /** 查看任务是否完成      *  taskId - 任务号      * 返回值:完成返回true,未完成返回false      */     bool isTaskFinished(1:i64 taskId);          /** 取得任务结果的URI,可以用此URI获得结果数据      *  taskId - 任务号      * 返回值:任务有结果,返回URI,否则返回空字符串      */         string getResultURI(1:i64 taskId);          /** 取得用户的所有任务列表      *  user - 用户名,完整的ganji邮箱      * 返回值:任务号列表,如果没有任务,返回空      */     list<i64> getTasksByUserName(1:string user); }

(二).生成php与hbase的接口文件(服务器端达成)

/usr/local/thrift/bin/thrift –gen php hive.thrift
下一场会在gen-php目录下生成了Hive.php和Hive_types.php文件。
然后把Hive.php和Hive_types.php文件拷贝到:客户端php开发的目录下。

(3).配置php客户端

php作为客户端应用thrift时,供给进行如下配置。

(a)准备thrift php客户端基础类

那几个基础类能够从thrift的源码包中找到。在thriftsrc/lib/php/src下,1班有如下目录和文书:ext/,protocol/,transport/目录,和thrift.php、autoload.php文件。大家把这么些目录和文书拷贝到客户端的/server/www/thrift_part/thrift-0.5.0/目录下。

(b)配置php的thrift扩张,使其辅助thrift

假使php想要使用thrift,还须求安装php的thrift扩充。
正如所示:
第一下载相应的php的thrift扩张,举行解压;
进去源码下的ext/thrift_protocol;
/usr/local/php/bin/phpize
./configure –with-php-config=/usr/local/php/bin/php-config
–enable-thrift_protocol
make
make install
下一场把转变的thrift_protocol.so文件配置到php.ini一碗水端平启apache服务。

(四).php客户端的实现

文件名称叫:updateHiveData.php

<?php     $GLOBALS['THRIFT_ROOT'] = '/server/www/third_part/thrift-0.5.0';          require_once $GLOBALS['THRIFT_ROOT'].'/Thrift.php';     require_once $GLOBALS['THRIFT_ROOT'].'/packages/scribe/scribe.php';     require_once $GLOBALS['THRIFT_ROOT'].'/protocol/TBinaryProtocol.php';     require_once $GLOBALS['THRIFT_ROOT'].'/transport/TSocket.php';     require_once $GLOBALS['THRIFT_ROOT'].'/transport/THttpClient.php';     require_once $GLOBALS['THRIFT_ROOT'].'/transport/TFramedTransport.php';     require_once $GLOBALS['THRIFT_ROOT'].'/transport/TBufferedTransport.php';      //生成的文件     require_once dirname(__FILE__) . '/Hive.php';     //require_once dirname(__FILE__) .'/hive_types.php';          ERROR_REPORTING(E_ALL);     INI_SET('DISPLAY_ERRORS','ON');         $socket = new TSocket('hive.corp.gj.com',13080);     $socket->setDebug(TRUE);           // 设置接收超时(毫秒)     $socket->setSendTimeout(10000);     $socket->setRecvTimeout(10000);          //$transport = new TBufferedTransport($socket, 1024, 1024);     $transport = new TFramedTransport($socket);     $protocol = new TBinaryProtocol($transport);     $client = new HiveClient($protocol);          try{         $transport->open();     }catch(TException $tx){         echo $tx->getMessage();     }           //获取各个类目某一天的 PV UV     $taskId = $client->submitTask('xxx@xxx.com','web',"select regexp_extract(gjch, '^/([^/]+)', 1), count(*), count(distinct uuid) from table1 where dt = '2013-04-22' and gjch regexp '[^@]*/detail' GROUP BY regexp_extract(gjch, '^/([^/]+)', 1);");          if($taskId <= 0){  echo 'error submit';         exit;     }     echo $taskId . "\n";         $count = 50;     while($count > 0){         try{             //sleep以秒为单位,这里3分钟轮询一次             sleep(3*60);         }catch(TException $tx){}    if($client->isTaskFinished($taskId)){             //echo $client->getResultURI($taskId);             $url = $client->getResultURI($taskId);             //echo $url;          $handle = fopen($url,"rb");             $content = stream_get_contents($handle);             echo $content;             fclose($handle);              break;         }         $count--;     }        $transport->close(); ?>

鉴于服务器端不是自作者负责,所以立即只根据thrift定义文件,落成了php客户端。运转结果如下:

图片 1

当中那里url是$client->getResultUEscortI取得的结果,网页内容是以此uri对应的始末。

 

四,Using Thrift with Java..在JAVA中使用Thrift,那里供给Java Thrift
库。该java Thrift库的编写翻译非凡简单:

五.thrift类说明

TSocket:选用TCP socket进行多少传输;
Transport类(传输层):
担负数据传输,介绍多少个常用类:
TBufferedTransport:对有些Transport对象操作的数目进行buffer,即从buffer中读取数据举办传输,也许将数据直接写入buffer;
TFramedTransport:同TBufferdTransport类型,也会对数据开始展览buffer,同时它协助定长数据发送和接受;
TFileTransport:文件(日志)传输类,允许client将文件传给server,语序server将面临的多寡写到文件中;

Protocol类(协议):
担负数据编码,主要有以下多少个常用类:
TBinaryProtocol:二进制编码;
TJSONProtocol:JSON编码。

版权表明:本文为博主原创文章,未经博主允许不得转发。


前言:

参考:http://thrift.apache.org/lib/java。。。

        近日风行的劳务调用方式有广大种,例如基于
SOAP 音信格式的 Web Service,基于 JSON 音讯格式的 RESTful
服务等。当中所用到的数额传输方式包罗 XML,JSON 等,但是 XML
相对体积太大,传输功效低,JSON
体积较小,新颖,但还不够完美。本文将介绍由 推特开发的远程服务调用框架 Apache
Thrift,它采取接口描述语言定义并成立服务,协理可扩展的跨语言服务付出,所包含的代码生成引擎能够在三种语言中,如
C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa,
Smalltalk 等创造高效的、无缝的劳动,其传输数据接纳二进制格式,相对 XML
和 JSON
体积更加小,对于高并发、大数据量和多语言的条件更有优势。本文将详细介绍
Thrift
的施用,并且提供丰富的实例代码加以表达表明,协助使用者飞速构建服务。

在/usr/lcoal/thrift-0.九.2/lib/java/ 下运营 ant
即可,生成了叁个libthrift-0.9.2.jar文件,就足以把该jar包导入到java工程中作为Thrift
for java的依赖性包了。

 

补充一下:在由Thrift IDL语言定义好**.thrift 文件,运行 thrift –gen
java **.thrift
就能够转移对应的JAVA文件。把该JAVA文件导入到JAVA工程中,还必要slf四j-api-一.5.八.jar
、slf四j-log四j12-1.五.8.jar 、log四j-一.二.14.jar

3个粗略的 Thrift
实例

伍,Thrift for java 之 eclipse编制程序实例

       
本文首先介绍多个简约的 Thrift 达成实例,使读者能够神速直观地打听怎么是
Thrift 以及哪些行使 Thrift 创设服务。

参考:http://blog.csdn.net/jun55xiu/article/details/8988429

始建二个回顾的劳务 Hello。首先依据Thrift 的语法规范编写脚本文件 Hello.thrift,代码如下:

1定义好thrift文件--Hello.thrift 并转移对应的java代码

清单 1. Hello.thrift

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() 

 }
service Hello{
    string helloString(1:string para)
    i32 helloInt(1:i32 para)
}

内部定义了服务 Hello
的八个艺术,每一个方法包蕴1个格局名,参数列表和重临类型。种种参数包蕴参数序号,参数类型以及参数名。
Thrift 是对 IDL(Interface Definition Language)
描述性语言的壹种具体落到实处。因而,以上的劳动描述文件使用 IDL
语法编写。使用 Thrift 工具编写翻译 Hello.thrift,就会转移对应的 Hello.java
文件。该手提袋罗了在 Hello.thrift 文件中讲述的劳动 Hello 的接口定义,即
Hello.Iface 接口,以及服务调用的平底通讯细节,包罗客户端的调用逻辑
Hello.Client 以及劳动器端的拍卖逻辑
Hello.Processor,用于构建客户端和劳动器端的意义。

变动的java部分代码如下:

制造HelloServiceImpl.java 文件并落到实处 Hello.java 文件中的 Hello.Iface
接口,代码如下:

public class Hello {

  public interface Iface {

    public String helloString(String para) throws org.apache.thrift.TException;

    public int helloInt(int para) throws org.apache.thrift.TException;

  }

  public interface AsyncIface {

    public void helloString(String para, org.apache.thrift.async.AsyncMethodCallback resultHandler) throws org.apache.thrift.TException;

清单 2. HelloServiceImpl.java

2编辑HelloServiceImpl接口达成thrift文件中定义的服务

package service.demo;



import org.apache.thrift.TException;



public class HelloServiceImpl implements Hello.Iface {

    @Override

    public boolean helloBoolean(boolean para) throws TException {

        return para;

    }



    @Override

    public int helloInt(int para) throws TException {

        try {

            Thread.sleep(20000);

        } catch (InterruptedException e) {

            e.printStackTrace();

        }

        return para;

    }



    @Override

    public String helloNull() throws TException {

        return null;

    }



    @Override

    public String helloString(String para) throws TException {

        return para;

    }



    @Override

    public void helloVoid() throws TException {

        System.out.println("Hello World");

    }

}
import org.apache.thrift.TException;

public class HelloServiceImpl implements Hello.Iface{
    public String helloString(String para) throws TException {
        return para;
    }
    public int helloInt(int para) throws TException {
        try{
            Thread.sleep(2000);
        }catch(InterruptedException e){
            e.printStackTrace();
        }
        return para;
    }
}

创设服务器端完成代码,将 Hello瑟维斯Impl
作为具体的微处理器传递给 Thrift 服务器,代码如下:

3编纂服务器端程序,部分代码如下:

清单 3. HelloServiceServer.java

TServerSocket serverTransport = new TServerSocket(7911);//设置服务器端口
            Factory proFactory = new TBinaryProtocol.Factory();//设置协议工厂
            TProcessor processor = new Hello.Processor<Hello.Iface>(new HelloServiceImpl());//关联处理器与Hello.thrift文件中定义的服务的实现
            TServer.Args tArgs = new TServer.Args(serverTransport);
            tArgs.processor(processor);
            tArgs.protocolFactory(proFactory);

            TServer server = new TSimpleServer(tArgs);
            System.out.println("Start server on port 7911");
            server.serve();
package service.server;



import org.apache.thrift.TProcessor;

import org.apache.thrift.protocol.TBinaryProtocol;

import org.apache.thrift.protocol.TBinaryProtocol.Factory;

import org.apache.thrift.server.TServer;

import org.apache.thrift.server.TThreadPoolServer;

import org.apache.thrift.transport.TServerSocket;

import org.apache.thrift.transport.TTransportException;

import service.demo.Hello;

import service.demo.HelloServiceImpl;



public class HelloServiceServer {

    /**

     * 启动 Thrift 服务器

     * 

     * @param args

     */

    @SuppressWarnings({ "rawtypes", "unchecked", "unused" })

    public static void main(String[] args) {

        try {

            // 设置服务端口为 7911

            TServerSocket serverTransport = new TServerSocket(7911);

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

            Factory proFactory = new TBinaryProtocol.Factory();

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

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

            TThreadPoolServer.Args argss = new TThreadPoolServer.Args(

                    serverTransport);

            // 默认情况就是TBinaryProtocol.Factory

            // argss.inputProtocolFactory(proFactory);

            // argss.outputProtocolFactory(proFactory);

            argss = argss.processor(processor);

            TServer server = new TThreadPoolServer(argss);

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

            server.serve();



        } catch (TTransportException e) {

            e.printStackTrace();

        }

    }

}

肆编纂客户端程序

始建客户端完毕代码,调用 Hello.client
访问服务端的逻辑达成,代码如下:

TTransport transport = new TSocket("localhost",7911);//建立连接
            transport.open();
            TProtocol protocol = new TBinaryProtocol(transport);
            Hello.Client client = new Hello.Client(protocol);//生成客户端实例对象
            client.helloString("Hello World");//调用定义好的服务
            client.helloInt(88);//调用定义好的服务

清单 4. HelloServiceClient.java

 

package service.client; 

 import org.apache.thrift.TException; 

 import org.apache.thrift.protocol.TBinaryProtocol; 

 import org.apache.thrift.protocol.TProtocol; 

 import org.apache.thrift.transport.TSocket; 

 import org.apache.thrift.transport.TTransport; 

 import org.apache.thrift.transport.TTransportException; 

 import service.demo.Hello; 



 public class HelloServiceClient { 

 /** 

     * 调用 Hello 服务

     * @param args 

     */ 

    public static void main(String[] args) { 

        try { 

            // 设置调用的服务地址为本地,端口为 7911 

            TTransport transport = new TSocket("localhost", 7911); 

            transport.open(); 

            // 设置传输协议为 TBinaryProtocol 

            TProtocol protocol = new TBinaryProtocol(transport); 

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

            // 调用服务的 helloVoid 方法

            client.helloVoid(); 

            transport.close(); 

        } catch (TTransportException e) { 

            e.printStackTrace(); 

        } catch (TException e) { 

            e.printStackTrace(); 

        } 

    } 

 } 

 ⑤总结:

代码编写完后运营服务器,再开发银行客户端调用劳动
Hello 的方法 helloVoid,在劳务器端的控制台窗口输出“Hello
World”(helloVoid
方法完结在控制台打印字符串,没有重回值,所以客户端调用艺术后没有重回值输出,读者能够友善尝尝任何有重临值方法的调用,其结果可以打字与印刷在客户端的控制台窗口
)。

1,使用IDL语言写好接口定义thrift文件,该文件指明了劳务器端提供的各类服务。2,通过thrift
–gen java/c++/py/… <thrift file> 生成相应语言的代码。

 

叁,用户实现具体的服务--服务器端程序、客户端程序。。。客户端调用服务,服务器端提供劳动。

Thrift
架构

4,至于整个传输进程则被Thrift封装起来了--protocol
定义数据传输格式,transport 定义数据传输方式。

Thrift
包罗二个1体化的堆栈结构用于创设客户端和劳务器端。下图描绘了 Thrift
的完整架构。

 

图 1. 架构图
图片 2 

如图所示,图紫藤色色部分是用户完成的政工逻辑,灰黄部分是依照Thrift
定义的服务接口描述文件生成的客户端和劳务器端代码框架,水绿部分是依据Thrift 文件生成代码达成多少的读写操作。深草绿部分以下是 Thrift
的传导系统、协议以及底层 I/O 通信,使用 Thrift
能够很方便的概念二个劳动并且选用差异的传导协议和传输层而不用重新生成代码。

Thrift
服务器包罗用于绑定协议和传输层的基础架构,它提供阻塞、非阻塞、单线程和四线程的情势运营在服务器上,能够同盟服务器
/ 容器一起运营,能够和水保的 J二EE 服务器 /Web 容器无缝的构成。

服务端和客户端具体的调用流程如下:

图 二. Server
端运转、服务时序图(**
查阅大图)**
图片 3 

该图所示是 HelloServiceServer
运维的历程以及服务被客户端调用时,服务器的响应进度。从图中大家能够看来,程序调用了
TThreadPoolServer 的 serve 方法后,server 进入阻塞监听状态,其阻塞在
TServerSocket 的 accept
方法上。当接收到来自客户端的新闻后,服务器发起2个新线程处理那些新闻请求,原线程再一次进入阻塞状态。在新线程中,服务器通过
TBinaryProtocol 协议读取音信内容,调用 HelloServiceImpl 的 helloVoid
方法,并将结果写入 helloVoid_result 中传回客户端。

图 三. Client
端调用服务时序图(**
翻看大图)**
图片 4 

该图所示是 HelloServiceClient
调用服务的长河以及收受到劳动器端的返回值后处理结果的进程。从图中大家得以看来,程序调用了
Hello.Client 的 helloVoid 方法,在 helloVoid 方法中,通过
send_helloVoid 方法发送对服务的调用请求,通过 recv_helloVoid
方法接收服务处理请求后赶回的结果。

 

数据类型

Thrift
脚本可定义的数据类型包蕴以下两种档次:

  • 骨干项目:

    • bool:布尔值,true 或
      false,对应 Java 的 boolean
    • byte:八 位有号子整数,对应
      Java 的 byte
    • i16:16 位有号子整数,对应
      Java 的 short
    • i3二:3贰 位有记号整数,对应
      Java 的 int
    • i6四:6四 位有记号整数,对应
      Java 的 long
    • double:6肆 位浮点数,对应 Java
      的 double
    • string:未知编码文本或二进制字符串,对应
      Java 的 String

  • 布局体类型:
    • struct:定义公共的靶子,类似于
      C 语言中的结构体定义,在 Java 中是多少个 JavaBean
  • 容器类型:
    • list:对应 Java 的
      ArrayList
    • set:对应 Java 的
      HashSet
    • map:对应 Java 的
      HashMap
  • 很是类型:
    • exception:对应 Java 的
      Exception
  • 服务类型:
    • service:对应服务的类

 

协议

Thrift
能够让用户挑选客户端与服务端之间传输通讯协议的档次,在传输协议上海市总体划分为文本
(text) 和2进制 (binary)
传输协议,为节约带宽,升高传输功能,一般景观下行使贰进制类型的传输协议为多数,有时还会利用基于文本类型的商议,那亟需基于项目
/ 产品中的实际要求。常用协议有以下两种:

  • TBinaryProtocol ——
    二进制编码格式进行数据传输

    行使格局如清单 三 和清单 四所示。

  • TCompactProtocol ——
    高效用的、密集的2进制编码格式进行数量传输

    创设 TCompactProtocol
    协议的服务器和客户端只需替换清单 叁 和清单 四 中 TBinaryProtocol
    协议部分即可,替换到如下代码:

    清单 5. 使用 TCompactProtocol 协议塑造的 HelloServiceServer.java

     TCompactProtocol.Factory proFactory = new TCompactProtocol.Factory();

**清单 6. 使用 TCompactProtocol 协议的 HelloServiceClient.java**


     TCompactProtocol protocol = new TCompactProtocol(transport); 
  • TJSONProtocol —— 使用 JSON
    的数据编码协议进行多少传输

    创设 TJSONProtocol
    协议的服务器和客户端只需替换清单 三 和清单 肆 中 TBinaryProtocol
    协议部分即可,替换到如下代码:

**清单 7. 使用 TJSONProtocol 协议构建的 HelloServiceServer.java**


    TJSONProtocol.Factory proFactory = new TJSONProtocol.Factory(); 

**清单 8. 使用 TJSONProtocol 协议的 HelloServiceClient.java**



    TJSONProtocol protocol = new TJSONProtocol(transport); 
  • TSimpleJSONProtocol —— 只提供 JSON
    只写的商议,适用于通过脚本语言解析

 

传输层

常用的传输层有以下三种:

  • TSocket —— 使用阻塞式 I/O
    举办传输,是最普遍的情势

    使用办法如清单 四 所示。

  • TFramedTransport ——
    使用非阻塞情势,按块的高低实行传输,类似于 Java 中的 NIO

若使用 TFramedTransport
传输层,其服务器必须修改为非阻塞的服务类型,客户端只需替换清单 4 中
TTransport 部分,代码如下,清单 9 中 TNonblockingServerTransport
类是构建非阻塞 socket 的抽象类,TNonblockingServerSocket 类继承
TNonblockingServerTransport


**清单 9. 使用 TFramedTransport 传输层构建的
HelloServiceServer.java**


     TNonblockingServerTransport serverTransport; 

     serverTransport = new TNonblockingServerSocket(10005); 

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

     TServer server = new TNonblockingServer(processor, serverTransport); 

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

     server.serve(); 

**清单 10. 使用 TFramedTransport 传输层的 HelloServiceClient.java**


     TTransport transport = new TFramedTransport(new TSocket("localhost", 10005)); 
  • TNonblockingTransport ——
    使用非阻塞格局,用于营造异步客户端

    利用办法请参见 Thrift
    异步客户端营造

 

劳动端类型

大面积的劳务端类型有以下三种:

  • TSimpleServer ——
    单线程服务器端使用规范的阻塞式 I/O

    代码如下:

**清单 11. 使用 TSimpleServer 服务端构建的 HelloServiceServer.java**

     TServerSocket serverTransport = new TServerSocket(7911); 

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

     TServer server = new TSimpleServer(processor, serverTransport); 

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

     server.serve(); 

客户端的构建方式可参考清单
4。
  • TThreadPoolServer ——
    二十四线程服务器端使用正式的阻塞式 I/O

    采用方式如清单 3 所示。

  • TNonblockingServer ——
    十二线程服务器端使用非阻塞式 I/O

    运用办法请参考 Thrift
    异步客户端营造

 

Thrift
异步客户端构建

Thrift
提供非阻塞的调用方式,可构建异步客户端。在那种办法中,Thrift
提供了新的类 TAsyncClientManager
用于管理客户端的乞请,在二个线程上追踪请求和响应,同时经过接口
AsyncClient 传递标准的参数和 callback 对象,服务调用完结后,callback
提供了拍卖调用结果和很是的艺术。

首先我们看 callback 的兑现:

清单 12.CallBack 的实现:MethodCallback.java

 package service.callback; 

 import org.apache.thrift.async.AsyncMethodCallback; 



 public class MethodCallback implements AsyncMethodCallback { 

    Object response = null; 



    public Object getResult() { 

        // 返回结果值

        return this.response; 

    } 



    // 处理服务返回的结果值

    @Override 

    public void onComplete(Object response) { 

        this.response = response; 

    } 

    // 处理调用服务过程中出现的异常

    @Override 

    public void onError(Throwable throwable) { 



    } 

 } 

如代码所示,onComplete
方法接收服务处理后的结果,此处我们将结果 response 直接赋值给 callback
的私房属性 response。onError
方法接收服务处理进度中抛出的老大,此处未对十分实行处理。

制造非阻塞服务器端完毕代码,将
HelloServiceImpl 作为具体的微型总结机传递给异步 Thrift
服务器,代码如下:

清单 13.HelloServiceAsyncServer.java

package service.server;



import org.apache.thrift.server.TNonblockingServer;

import org.apache.thrift.server.TServer;

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 {

    /**

     * 启动 Thrift 异步服务器

     * 

     * @param args

     */

    @SuppressWarnings({ "unchecked", "rawtypes" })

    public static void main(String[] args) {

        TNonblockingServerTransport serverTransport;

        try {

            serverTransport = new TNonblockingServerSocket(10005);

            Hello.Processor processor = new Hello.Processor(

                    new HelloServiceImpl());

            // TServer server = new TNonblockingServer(processor,

            // serverTransport);

            TNonblockingServer.Args argss = new TNonblockingServer.Args(

                    serverTransport);

            argss.processor(processor);

            TServer server = new TNonblockingServer(argss);

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

            server.serve();

        } catch (TTransportException e) {

            e.printStackTrace();

        }

    }

}

Hello瑟维斯AsyncServer 通过
java.nio.channels.ServerSocketChannel
创制非阻塞的服务器端等待客户端的连日。

创立异步客户端达成代码,调用
Hello.AsyncClient 访问服务端的逻辑完毕,将 MethodCallback
对象作为参数字传送入调用方法中,代码如下:

清单 14.HelloServiceAsyncClient.java

package service.client;



import java.io.IOException;

import org.apache.thrift.async.TAsyncClientManager;

import org.apache.thrift.protocol.TBinaryProtocol;

import org.apache.thrift.protocol.TProtocolFactory;

import org.apache.thrift.transport.TNonblockingSocket;

import org.apache.thrift.transport.TNonblockingTransport;

import service.callback.MethodCallback;

import service.demo.Hello;



public class HelloServiceAsyncClient {

    /**

     *  调用 Hello 服务

     * 

     * @param args

     */

    @SuppressWarnings("unchecked")

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

        try {

            TAsyncClientManager clientManager = new TAsyncClientManager();

            TNonblockingTransport transport = new TNonblockingSocket(

                    "localhost", 10005);

            TProtocolFactory protocol = new TBinaryProtocol.Factory();

            Hello.AsyncClient asyncClient = new Hello.AsyncClient(protocol,

                    clientManager, transport);

            System.out.println("Client calls .....");

            MethodCallback callBack = new MethodCallback();

            asyncClient.helloString("Hello World", callBack);

            Object res = callBack.getResult();

            while (res == null) {

                res = callBack.getResult();

            }

            System.out.println(((Hello.AsyncClient.helloString_call) res)

                    .getResult());

        } catch (IOException e) {

            e.printStackTrace();

        }

    }

}

HelloServiceAsyncClient 通过
java.nio.channels.Socketchannel
创造异步客户端与服务器建立连接。在本文中异步客户端通过以下的循环代码完成了一同效果,读者可去除那有的代码后再运维比较。

清单 一五. 异步客户端完结同台效果代码段

Object res = callBack.getResult();

// 等待服务调用后的返回结果

while (res == null) {

   res = callBack.getResult();

}

 

由此与清单 九 和清单 拾的代码相比较,咱们能够创设二个 TNonblockingServer
服务类型的服务端,在客户端营造多少个 TFramedTransport
传输层的壹块客户端和2个 TNonblockingTransport
传输层的异步客户端,那么三个劳动就足以因此2个 socket
端口提供二种差异的调用格局。有趣味的读者能够品味一下。

 

大规模难点

NULL 问题

作者们在对劳务的有些方法调用时,有时会油不过生该格局返回null 值的情形,在 Thrift 中,直接调用3个重返 null 值的方法会抛出
TApplicationException 十分。在清单 二 中,HelloServiceImpl 里达成了
helloNull 方法,再次回到 null 值,我们在 HelloServiceClient.java
中投入调用该格局的代码,出现如下图所示的极度:

图 4. TApplicationException 异常
图片 5 

为了处理回来 null
值境况,我们要捕获该尤其,并展开相应的拍卖,具体客户端代码完结如下:

清单 1陆. 处理服务重回值为 null 的代码

package service.client; 

 import org.apache.thrift.TApplicationException; 

 import org.apache.thrift.TException; 

 import org.apache.thrift.protocol.TBinaryProtocol; 

 import org.apache.thrift.protocol.TProtocol; 

 import org.apache.thrift.transport.TSocket; 

 import org.apache.thrift.transport.TTransport; 

 import org.apache.thrift.transport.TTransportException; 

 import service.demo.Hello; 



 public class HelloServiceClient { 

    /** 

     * 调用 Hello 服务,并处理 null 值问题

     * @param args 

     */ 

    public static void main(String[] args) { 

        try { 

            TTransport transport = new TSocket("localhost", 7911); 

            transport.open(); 

            TProtocol protocol = new TBinaryProtocol(transport); 

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

            System.out.println(client.helloNull()); 

            transport.close(); 

        } catch (TTransportException e) { 

            e.printStackTrace(); 

        } catch (TException e) { 

            if (e instanceof TApplicationException 

                    && ((TApplicationException) e).getType() ==   

                                 TApplicationException.MISSING_RESULT) { 

                System.out.println("The result of helloNull function is NULL"); 

            } 

        } 

    } 

 } 

调用 helloNull 方法后,会抛出
TApplicationException 至极,并且万分类别为
MISSING_RESULT,本段代码展现,捕获该特别后,直接在控制台打字与印刷“The result
of helloNull function is NULL”新闻。

 

设置配备

MAVEN安装配置:

一.创立maven工程,pom.xml内容如下:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>



    <groupId>demo</groupId>

    <artifactId>thrift-demo</artifactId>

    <version>0.0.1-SNAPSHOT</version>

    <packaging>jar</packaging>



    <name>thrift-demo</name>

    <url>http://maven.apache.org</url>



    <properties>

        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

    </properties>



    <dependencies>

        <dependency>

            <groupId>junit</groupId>

            <artifactId>junit</artifactId>

            <version>4.8.1</version>

            <scope>test</scope>

        </dependency>



        <dependency>

            <groupId>org.apache.thrift</groupId>

            <artifactId>libthrift</artifactId>

            <version>0.8.0</version>

        </dependency>

        <dependency>

            <groupId>org.slf4j</groupId>

            <artifactId>slf4j-nop</artifactId>

            <version>1.5.8</version>

            <type>jar</type>

            <scope>compile</scope>

        </dependency>

    </dependencies>

</project>

 二.下载
thrift 编写翻译工具,该工具可将 thrift 脚本文件编写翻译成 java
文件,下载地址:http://mirror.bit.edu.cn/apache//thrift/0.8.0/thrift-0.8.0.exe(该文件为编写翻译工具,不是安装文件)

 3.创立Hello.thrift 脚本文件,具体代码如上一章节所述,进入 thrift-0.八.0.exe
所在目录,执行命令”thrift-0.捌.0.exe -gen java
x:\Hello.thrift”,在现阶段运作盘符下,可尽收眼底 gen-java
目录,进入目录可看到变化的 Java 代码。更加多 thrift 的通令内容,请参见
thrift 自带的 help 命令

四.编克服务端和客户端代码,达成thrift 的安装和陈设

手动安装:

Apache Thrift
的官方网址为:http://thrift.apache.org/tutorial/,具体安装步骤如下:

  1. 下载 thrift
    源文件(http://svn.apache.org/repos/asf/thrift/tags/thrift-0.6.1/
  2. 将 thrift 源文件导入 eclipse,进入
    /lib/java 目录,使用 ant 编写翻译 build.xml 获得libthrift-0.陆.一-snapshot.jar

  3. libthrift-0.陆.一-snapshot.jar、slf四j-api-壹.五.八.jar、slf四j-log4j1贰-1.伍.八.jar
    和 log肆j-1.贰.1四.jar 导入 eclipse 开发条件
  4. 下载 thrift 编写翻译工具,该工具可将
    thrift 脚本文件编写翻译成 java
    文件,下载地址:http://apache.etoak.com//thrift/0.6.0/thrift-0.6.1.exe

  5. 创造 Hello.thrift
    脚本文件,具体代码如上1章节所述,进入 thrift-0.陆.1.exe
    所在目录,执行命令”thrift-0.六.1.exe -gen java
    x:\Hello.thrift”,在现阶段运作盘符下,可尽收眼底 gen-java
    目录,进入目录可观望变化的 Java 代码。越多 thrift 的下令内容,请参见
    thrift 自带的 help 命令

  6. 编辑服务端和客户端代码,落成thrift 的装置和布局

依据 Apache Thrift
框架生成的服务包括客户端和劳务器端,具体的布署格局如下所示:

图 5. 部署图
图片 6 

从图中大家得以旁观,客户端和劳务器端安排时,须求使用公共的
jar 包和 java 文件,如图“Common file”区域,当中 Hello.java 由
Hello.thrift 编写翻译而来。在劳务器端,服务必须贯彻 Hello.Iface
接口,同时要包括服务器的启航代码
HelloServiceServer.java。在客户端,包含客户端调用劳动的代码
HelloServiceClient.java。客户端和服务器通过 Hello.java 提供的 API
完毕长途服务调用。

 

总结

正文介绍了 Apache Thrift
的设置配备和架构,并通过大批量实例介绍了在不相同情形下怎么样使用 Apache Thrift
来创设服务,同时重点介绍了 Thrift
异步客户端的营造,希望能给读者带来一些救助。

参考资料

学习

相关文章