posts - 167,  comments - 30,  trackbacks - 0

                     Thrift框架調研

          簡介

          Thrift是一種開源的跨語言的RPC服務框架。Thrift最初由facebook公司開發(fā)的,在2007年facebook將其提交apache基金會開源了。對于當時的facebook來說創(chuàng)造thrift是為了解決facebook系統(tǒng)中各系統(tǒng)間大數(shù)據(jù)量的傳輸通信以及系統(tǒng)之間語言環(huán)境不同需要跨平臺的特性。所以thrift可以支持多種程序語言,支持的語言如下: 


          在多種不同的語言之間通信thrift可以作為二進制的高性能的通訊中間件,支持數(shù)據(jù)(對象)序列化和多種類型的RPC服務。Thrift是IDL(interface definition language)描述性語言的一個具體實現(xiàn),Thrift適用于程序對程序靜態(tài)的數(shù)據(jù)交換,需要先確定好他的數(shù)據(jù)結構,他是完全靜態(tài)化的,當數(shù)據(jù)結構發(fā)生變化時,必須重新編輯IDL文件,代碼生成,再編譯載入的流程,跟其他IDL工具相比較可以視為是Thrift的弱項,Thrift適用于搭建大型數(shù)據(jù)交換及存儲的通用工具,對于大型系統(tǒng)中的子系統(tǒng)間數(shù)據(jù)傳輸相對于JSON和xml無論在性能、傳輸大小上有明顯的優(yōu)勢。

           

          基礎架構

          如下圖所示是thrift的協(xié)議棧整體的架構,thrift是一個客戶端和服務器端的架構體系(c/s),在最上層是用戶自行實現(xiàn)的業(yè)務邏輯代碼。    第二層是由thrift編譯器自動生成的代碼,主要用于結構化數(shù)據(jù)的解析,發(fā)送和接收。TServer主要任務是高效的接受客戶端請求,并將請求轉發(fā)給Processor處理。Processor負責對客戶端的請求做出響應,包括RPC請求轉發(fā),調用參數(shù)解析和用戶邏輯調用,返回值寫回等處理。從TProtocol以下部分是thirft的傳輸協(xié)議和底層I/O通信。TProtocol是用于數(shù)據(jù)類型解析的,將結構化數(shù)據(jù)轉化為字節(jié)流給TTransport進行傳輸。TTransport是與底層數(shù)據(jù)傳輸密切相關的傳輸層,負責以字節(jié)流方式接收和發(fā)送消息體,不關注是什么數(shù)據(jù)類型。底層IO負責實際的數(shù)據(jù)傳輸,包括socket、文件和壓縮數(shù)據(jù)流等。

          協(xié)議層TProtocol:

          在傳輸協(xié)議上總體上劃分為文本(text)和二進制(binary)傳輸協(xié)議, 為節(jié)約帶寬,提供傳輸效率,一般情況下使用二進制類型的傳輸協(xié)議為多數(shù)。

             1>TBinaryProtocol – 二進制編碼格式進行數(shù)據(jù)傳輸。 

             2>TCompactProtocol – 高效的編碼方式,使用類似于protobuffer的Variable-Length Quantity (VLQ) 編碼(可以節(jié)省傳輸空間,使數(shù)據(jù)的傳輸效率更高)對數(shù)據(jù)進行壓縮。 關于VLQ了解更多(http://en.wikipedia.org/wiki/Variable-length_quantity

             3>TJSONProtocol – 使用JSON的數(shù)據(jù)編碼協(xié)議進行數(shù)據(jù)傳輸。 

             4>TSimpleJSONProtocol – 這種節(jié)約只提供JSON只寫的協(xié)議,適用于通過腳本語言解析    

             5>TDebugProtocol – 在開發(fā)的過程中幫助開發(fā)人員調試用的,以文本的形式展現(xiàn)方便閱讀。

           

          傳輸層TTransport

              1>TSocket- 使用阻塞式I/O進行傳輸,也是最常見的模式。 

              2>TFramedTransport- 使用非阻塞方式,按塊的大小,進行傳輸,類似于Java中的NIO。                

              3>TFileTransport- 顧名思義按照文件的方式進程傳輸,雖然這種方式不提供Java的實現(xiàn),但是實現(xiàn)起來非常簡單。 

              4>TMemoryTransport- 使用內(nèi)存I/O,就好比Java中的ByteArrayOutputStream實現(xiàn)。 

              5>TZlibTransport- 使用執(zhí)行zlib壓縮,不提供Java的實現(xiàn)。

              6>TNonblockingTransport-使用非阻塞方式,用于構建異步客戶端。



            服務端類型 :

              1>TSimpleServer -  單線程服務器端使用標準的阻塞式I/O。     

              2>TThreadPoolServer -  多線程服務器端使用標準的阻塞式I/O。 

              3>TNonblockingServer – 多線程服務器端使用非阻塞式I/O,并且實現(xiàn)了Java中的NIO通道。



          數(shù)據(jù)類型

          Thrift 腳本可定義的數(shù)據(jù)類型包括以下幾種類型:

          • 基本類型:
            • bool:布爾值,true 或 false,對應 Java 的 boolean
            • byte:8 位有符號整數(shù),對應 Java 的 byte
            • i16:16 位有符號整數(shù),對應 Java 的 short
            • i32:32 位有符號整數(shù),對應 Java 的 int
            • i64:64 位有符號整數(shù),對應 Java 的 long
            • double:64 位浮點數(shù),對應 Java 的 double
            • string:未知編碼文本或二進制字符串,對應 Java 的 String
          • 結構體類型:
            • struct:定義公共的對象,類似于 C 語言中的結構體定義,在 Java 中是一個 JavaBean
          • 容器類型:
            • list:對應 Java 的 ArrayList
            • set:對應 Java 的 HashSet
            • map:對應 Java 的 HashMap
          • 異常類型:
            • exception:對應 Java 的 Exception
          • 服務類型:service:對應服務的類

          安裝使用

          在Windows下安裝前需要很多依賴包的安裝,比較麻煩。下面介紹了在Linux下的源碼安裝,直接wget或手動下載最tar.gz安裝包編譯安裝:

          tar -xvf thrift-0.9.1.tar.gz

          cd thrift-0.9.1

          ./configure

          make 

          make install

          使用命令thrift -version,顯示Thrift version 0.9.1 則表示安裝成功。

          我們使用到了java,所以通過ant方式構建thrift相關lib包,進入$THRIFT_HOME/lib/java目錄下,在ant編譯libthrift出現(xiàn)了如下問題

          Buildfile: /letv/apps_install/thrift-0.9.1/lib/java/build.xml 

          setup.init: 

          mvn.ant.tasks.check: 

          proxy: 

          mvn.ant.tasks.download: 
          [get] Getting: http://repo1.maven.org/maven2/org/apache/maven/maven-ant-tasks/2.1.3/maven-ant-tasks-2.1.3.jar 
          [get] To: /letv/apps_install/thrift-0.9.1/lib/java/build/tools/maven-ant-tasks-2.1.3.jar 
          [get] Not modified - so not downloaded 

          mvn.init: 
          Unable to obtain resource from /letv/apps_install/thrift-0.9.1/lib/java/build/tools/maven-ant-tasks-2.1.3.jar: java.util.zip.ZipException: error in opening zip file
          [typedef] Unable to obtain resource from /letv/apps_install/thrift-0.9.1/lib/java/build/tools/maven-ant-tasks-2.1.3.jar: 
          [typedef] java.util.zip.ZipException: error in opening zip file 
          [typedef] at java.util.zip.ZipFile.open(Native Method) 
          [typedef] at java.util.zip.ZipFile.<init>(ZipFile.java:214) 
          [typedef] at java.util.zip.ZipFile.<init>(ZipFile.java:144) 
          [typedef] at java.util.jar.JarFile.<init>(JarFile.java:153) 
          [typedef] at java.util.jar.JarFile.<init>(JarFile.java:117) 
          [typedef] at org.apache.tools.ant.AntClassLoader.getResourceURL(AntClassLoader.java:1014) 
          [typedef] at org.apache.tools.ant.AntClassLoader$ResourceEnumeration.findNextResource(AntClassLoader.java:150) 
          [typedef] at org.apache.tools.ant.AntClassLoader$ResourceEnumeration.<init>(AntClassLoader.java:111) 
          [typedef] at org.apache.tools.ant.AntClassLoader.findResources(AntClassLoader.java:954) 
          [typedef] at org.apache.tools.ant.AntClassLoader.getNamedResources(AntClassLoader.java:923) 
          [typedef] at org.apache.tools.ant.loader.AntClassLoader5.getResources(AntClassLoader5.java:58) 
          [typedef] at org.apache.tools.ant.taskdefs.Definer.resourceToURLs(Definer.java:360) 
          [typedef] at org.apache.tools.ant.taskdefs.Definer.execute(Definer.java:246) 
          [typedef] at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:292) 
          [typedef] at sun.reflect.GeneratedMethodAccessor4.invoke(Unknown Source) 
          [typedef] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
          [typedef] at java.lang.reflect.Method.invoke(Method.java:601) 
          [typedef] at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106) 
          [typedef] at org.apache.tools.ant.Task.perform(Task.java:348) 
          [typedef] at org.apache.tools.ant.Target.execute(Target.java:435) 
          [typedef] at org.apache.tools.ant.Target.performTasks(Target.java:456) 
          [typedef] at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1393) 
          [typedef] at org.apache.tools.ant.Project.executeTarget(Project.java:1364) 
          [typedef] at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41) 
          [typedef] at org.apache.tools.ant.Project.executeTargets(Project.java:1248) 
          [typedef] at org.apache.tools.ant.Main.runBuild(Main.java:851) 
          [typedef] at org.apache.tools.ant.Main.startAnt(Main.java:235) 
          [typedef] at org.apache.tools.ant.launch.Launcher.run(Launcher.java:280) 
          [typedef] at org.apache.tools.ant.launch.Launcher.main(Launcher.java:109) 
          [typedef] Could not load definitions from resource org/apache/maven/artifact/ant/antlib.xml. It could not be found. 

          BUILD FAILED 
          /letv/apps_install/thrift-0.9.1/lib/java/build.xml:279: Problem: failed to create task or type antlib:org.apache.maven.artifact.ant:remoteRepository 
          Cause: The name is undefined. 
          Action: Check the spelling. 
          Action: Check that any custom tasks/types have been declared. 
          Action: Check that any <presetdef>/<macrodef> declarations have taken place. 
          No types or tasks have been defined in this namespace yet 

          This appears to be an antlib declaration. 
          Action: Check that the implementing library exists in one of: 
          -/letv/apps_install/apache-ant-1.9.4/lib 
          -/root/.ant/lib 
          -a directory added on the command line with the -lib argument 


          Total time: 2 seconds

          解決方法:ant通過yum方式安裝,默認版本1.7.1,自行安裝最新版本1.9.4,成功編譯后在當前目錄生成了build文件夾,包括libthrift-0.9.1.jar以及依賴的lib:

          commons-codec-1.6.jar
          commons-lang3-3.1.jar
          commons-logging-1.1.1.jar
          httpclient-4.2.5.jar
          httpcore-4.2.4.jar
          junit-4.4.jar
          log4j-1.2.14.jar
          servlet-api-2.5.jar
          slf4j-api-1.5.8.jar
          slf4j-log4j12-1.5.8.jar

          u 開發(fā)流程及代碼示例

          1,編寫IDL文件helloService.thrift,如下:

          /**

           * Hello world Testing

           *

           */

          namespace java com.le.mms

          service HelloService {

              i32 sayInt(1:i32 param)

              string sayString(1:string param)

              bool sayBoolean(1:bool param)

              void sayVoid()

          }

          2. 使用thrift編譯器生成所需語言的代碼

          thrift --gen java helloService.thrift

          在當前目錄下生成gen-java目錄,里面生成了HelloService.java文件。

          Thrift --gen py helloService.thrift 可以生成python相關代碼。

           

          3. 新建Java工程或maven工程,java工程引入ant生成的lib,maven工程pom.xml中引入依賴。

             <dependency>

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

                <artifactId>libthrift</artifactId>

                <version>0.9.1</version>

              </dependency>

          自動會將依賴的lib下載下來。

          4. 編寫HelloServiceImpl.java業(yè)務實現(xiàn)類. 需要實現(xiàn)HelloService.Iface接口,由thrift自動生成的代碼。 

          package com.le.mms.thrift; 

          import org.apache.thrift.TException;

          public class HelloServiceImpl implements HelloService.Iface{

              @Override

              public int sayInt(int param) throws TException {

                  System.out.println("say int :" + param);

                  return param;

              }

              @Override

              public String sayString(String param) throws TException {

                  System.out.println("say string :" + param);

                  return param;

              }

              @Override

              public boolean sayBoolean(boolean param) throws TException {

                  System.out.println("say boolean :" + param);

                  return param;

              }

              @Override

              public void sayVoid() throws TException {

                  System.out.println("say void ...");

              }

          }

           

          5. 編寫thrift-java服務器端,監(jiān)聽端口9090

          package com.le.mms.thrift.server;

          import org.apache.thrift.protocol.TBinaryProtocol;

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

          import org.apache.thrift.server.TServer;

          import org.apache.thrift.server.TSimpleServer;

          import org.apache.thrift.transport.TServerSocket;

          import org.apache.thrift.transport.TTransportException;

          import com.le.mms.thrift.HelloService;

          import com.le.mms.thrift.HelloServiceImpl;

          import com.le.mms.thrift.HelloService.Processor;

          /**

           * 啟動thrift的java服務器端

           *

           * @author david

           *

           */

          public class HelloServiceServer {

             

              public static void main(String[] args) {

                  try {

                      // 設置服務器端口

                      TServerSocket serverTransport = new TServerSocket(9090);

                      // 設置二進制協(xié)議工廠

                      Factory protocolFactory = new TBinaryProtocol.Factory();

                      //處理器關聯(lián)業(yè)務實現(xiàn)

                      Processor<HelloService.Iface> processor = new HelloService.Processor<HelloService.Iface>(new HelloServiceImpl());

                      // 1. 使用單線程標準阻塞I/O模型

                      TServer.Args simpleArgs = new TServer.Args(serverTransport);

                      simpleArgs.processor(processor);

                      simpleArgs.protocolFactory(protocolFactory);

                      TServer server = new TSimpleServer(simpleArgs);

                      // 2. 使用線程池服務模型

          //            TThreadPoolServer.Args poolArgs = new TThreadPoolServer.Args(serverTransport);

          //            poolArgs.processor(processor);

          //            poolArgs.protocolFactory(protocolFactory);

          //            TServer poolServer = new TThreadPoolServer(poolArgs);

          //            poolServer.serve();

                      System.out.println("開啟thrift服務器,監(jiān)聽端口:9090");

                      server.serve();

                  } catch (TTransportException e) {

                      e.printStackTrace();

                  }

              }

          }

           

          6.編寫thrift-java客戶端,發(fā)出請求。

          package com.le.mms.thrift.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 com.le.mms.thrift.HelloService; 

          /**

           * 調用thrift的java客戶端

           *

           * @author david

           *

           */

          public class HelloServiceClient {

             

              public static void main(String[] args) {

                  try {

                      // 設置調用的服務地址-端口

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

                      //  使用二進制協(xié)議

                      TProtocol protocol = new TBinaryProtocol(transport);

                      // 使用的接口

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

                      //打開socket

                      transport.open();

                      client.sayBoolean(true);

                      client.sayString("Hello world");

                      client.sayInt(20141111);

                      client.sayVoid();

                      transport.close();

                  } catch (TTransportException e) {

                      e.printStackTrace();

                  } catch (TException te) {

                      te.printStackTrace();

                  }

              }

          }

          以上編寫完了server和client端代碼,運行server開啟監(jiān)聽。然后運行client就能夠與server端進行rpc調用方式的通訊了。


          posted on 2014-12-03 23:56 David1228 閱讀(28344) 評論(0)  編輯  收藏 所屬分類: JAVAJ2EE

          <2014年12月>
          30123456
          78910111213
          14151617181920
          21222324252627
          28293031123
          45678910

          常用鏈接

          留言簿(4)

          隨筆分類

          隨筆檔案

          文章檔案

          新聞分類

          新聞檔案

          相冊

          收藏夾

          Java

          Linux知識相關

          Spring相關

          云計算/Linux/虛擬化技術/

          友情博客

          多線程并發(fā)編程

          開源技術

          持久層技術相關

          搜索

          •  

          積分與排名

          • 積分 - 359229
          • 排名 - 154

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 腾冲县| 台湾省| 饶平县| 平江县| 丽水市| 广丰县| 叙永县| 饶平县| 古浪县| 沂源县| 昂仁县| 黑水县| 平顺县| 南宫市| 偏关县| 社旗县| 汤原县| 册亨县| 西平县| 东乡| 阳江市| 顺昌县| 岳普湖县| 交城县| 翼城县| 武鸣县| 东光县| 当阳市| 武乡县| 聊城市| 盘山县| 惠东县| 吴旗县| 盱眙县| 湘潭市| 安仁县| 丰都县| 金山区| 柳河县| 文化| 定边县|