zoukankan      html  css  js  c++  java
  • Windows Thrift安装及HelloWorld

     Thrift是一个facebook开源的高效RPC框架,其主要特点是跨语言及二进制高效传输(除了二进制,也支持json等常用序列化机制),官网地址:http://thrift.apache.org

    跨语言通常有二种做法,

    一是将其它语言转换成某种主流的通用语言,比如:delphi.net以前就是先将delphi转换成c#,然后再编译成IL,从而实现delphi在.net上的运行(好久没关注delphi了,不知道现在还是不是这种机制)

    二是先定义一种规范文件(可以简单的理解为『母版』),然后由特定的编译器,将『母版』直接编译成目标语言的源代码。

    thrift走的是第二条路,使用thrift框架时,先定义名为.thrift后缀的文件,然后由thrift编译器编译成指定语言的源文件,然后借助thrift提供的各种语言的实现lib库,完成rpc的调用。

    一、thrift编译器的安装 

    1.1、windows 安装

    http://thrift.apache.org/docs/install/windows 这是官网的windows安装指导说明,windows的安装其实最简单

    Thrift compiler for Windows (thrift-0.9.2.exe)

     thrift-0.9.2.tar.gz

    下载这二个文件即可,第1个是编译器,第2个压缩包里包括了种示例代码。把thrift-0.9.2.exe保存到某个目录,比如:c: hrift下,然后将thrift-0.9.2.exe改个简单的名字,比如:thrift.exe(这一步非必须),最后在环境变量的path路径里,把c: hrift加上,保证Command窗口下,键入thrift能找到该文件即可。

    1.2、centos 安装 

    http://thrift.apache.org/docs/install/centos 参考这个安装,上面的详细的命令,按上面的命令一步步来就行了,主要过程是先安装一堆依赖的工具,然后

    git clone https://git-wip-us.apache.org/repos/asf/thrift.git

    将thrift源代码拉到本地,再build,生成thrift编译器

    1.3、mac osx 安装

    http://thrift.apache.org/docs/install/os_x 参考这里,大概步骤跟centos差不多,相信大家都能搞定,唯一要注意的是,mac os上没有yum之类的工具,建议使用brew 工具安装

    二、thrift文件的定义

    从git拉回来的源代码tutorial目录下,有二个示例文件:shared.thrift及tutorial.thrift,大家可以打开看看,演示了主要用法,但我觉得还是有些小复杂,初学者一眼看上去有些乱,我按服务开发的常规场景,自己弄了二个小demo:

    首先定义要传输的dto对象

    dto.thrift

     
    namespace java yjmyzz.thrift.study.dto
    namespace csharp yjmyzz.thrift.study.dto
    
    //Person类
    struct Person {
      1: i16 age = 0,
      2: string name,
      3: bool sex,
      4: double salary,
      5: byte childrenCount
    }
    
    //查询参数
    struct QueryParameter{
     1: i16 ageStart,
     2: i16 ageEnd
    }
     

    这里定义了二个类,一个是Person类,一个是查询的参数对象类,最上面的namespace即为最终java, c#里的package及namespace

    再定义服务接口service.thrift

     
    namespace java yjmyzz.thrift.study.service
    namespace csharp yjmyzz.thrift.study.service
    
    include "dto.thrift"
    
    //服务
    service DemoService {
    
       //用于检测client-server之间通讯是否正常
       string ping(),
    
       list<dto.Person> getPersonList(1:dto.QueryParameter parameter)
    
    }
     

    实际开发中,建议大家使用intellij idea,其thrift插件可以支持高亮语法和代码智能提示,如下图:

    三、client及server端项目开发

    如果大家使用过hessian、dubbo之类的框架,相信对于服务开发这一类套路都很熟悉,通常会拆分成3部分,接口定义(也称服务&数据契约 contract)、服务生产方(即:server端)、服务消费方(即:client端),按这一思路,创建三个module,项目结构见下图:

    其中thrift-contract即为公用的接口部分,thrift-client为客户端,thrift-server为服务端,注意:dto.thrift及service.thrift这二个文件,我放在了thrift-contractsrc hrift这个目录下。

    3.1 生成目标语言源文件

    架势拉好了,开始干活,命令行下先进入thrift-contractsrc hrift所在目录,

    thrift -gen java dto.thrift

    thrift -gen java service.thrift

    这样就把二个thrift【母版】文件生成了对应的java代码,生成的源文件会存放在当前工作目录的gen-java下,如果把-gen java换成-gen csharp就会生成c#代码。

    上图是生成后的源代码结构,由于src hrift目录并不是maven工程约定的源代码目录,手动把gen-java下生成的整个目录,复制到src/main/java下即可。

    3.2 maven中pom.xml依赖荐的添加

     
     1     <dependencies>
     2         <dependency>
     3             <groupId>org.apache.thrift</groupId>
     4             <artifactId>libthrift</artifactId>
     5             <version>0.9.2</version>
     6         </dependency>
     7 
     8         <dependency>
     9             <groupId>org.slf4j</groupId>
    10             <artifactId>slf4j-log4j12</artifactId>
    11             <version>1.5.8</version>
    12         </dependency>
    13     </dependencies>
     

    libthrift这一项是必须要添加的,slf4j-log4j12对于接口定义来讲,可以不用(但最终在serverclient端运行时,这个包不可少)。然后就可以用 mvn clean install 来生成jar包并安装到本机maven仓库中了,注意这里有一个小问题:

    thrift生成的java源代码中,@Override这个注解有些地方添加得不对(比如:实现接口时,实现类中是不需要添加这一注解的),编译时如果出现错误,直接去掉即可,建议:将生成的java源文件,全局替换,把@Override全干掉。

    3.3 server端的接口实现

    thrift-contract只是生成了服务的接口定义,并未提供实现,下面是DemoService的实现

     
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    package yjmyzz.thrift.study;
     
    import org.apache.thrift.TException;
    import yjmyzz.thrift.study.dto.Person;
    import yjmyzz.thrift.study.dto.QueryParameter;
    import yjmyzz.thrift.study.service.DemoService;
     
    import java.util.ArrayList;
    import java.util.List;
     
     
    public class DemoServiceImpl implements DemoService.Iface {
     
     
        public String ping() throws TException {
            System.out.println("ping()");
            return "pong";
        }
     
        public List<Person> getPersonList(QueryParameter parameter) throws TException {
            //System.out.println(parameter.getAgeStart() + " - " + parameter.getAgeEnd());
     
            List<Person> list = new ArrayList<Person>(10);
            for (short i = 0; i < 10; i++) {
                Person p = new Person();
                p.setAge(i);
                p.setChildrenCount(Byte.valueOf(i + ""));
                p.setName("test" + i);
                p.setSalary(10000D);
                p.setSex(true);
                list.add(p);
            }
            return list;
        }
    }

     这里随便返回一堆数据,意思一下而已,注:server端的pom.xml中,记得添加接口层的依赖项引用 

     
     1     <dependencies>
     2 
     3         <dependency>
     4             <groupId>yjmyzz</groupId>
     5             <artifactId>thrift-contract</artifactId>
     6             <version>1.0</version>
     7         </dependency>
     8 
     9         <dependency>
    10             <groupId>org.apache.thrift</groupId>
    11             <artifactId>libthrift</artifactId>
    12             <version>0.9.2</version>
    13         </dependency>
    14 
    15         <dependency>
    16             <groupId>org.slf4j</groupId>
    17             <artifactId>slf4j-log4j12</artifactId>
    18             <version>1.5.8</version>
    19         </dependency>
    20     </dependencies>

    3.4 server的启动

     
     1 package yjmyzz.thrift.study;
     2 
     3 
     4 import org.apache.thrift.server.TServer;
     5 import org.apache.thrift.server.TServer.Args;
     6 import org.apache.thrift.server.TSimpleServer;
     7 import org.apache.thrift.transport.TServerSocket;
     8 import org.apache.thrift.transport.TServerTransport;
     9 import yjmyzz.thrift.study.service.DemoService;
    10 
    11 
    12 public class ThriftServer {
    13 
    14     public static DemoService.Iface service;
    15 
    16     public static DemoService.Processor processor;
    17 
    18     public static void main(String[] args) {
    19         try {
    20             service = new DemoServiceImpl();
    21             processor = new DemoService.Processor(service);
    22 
    23             Runnable simple = new Runnable() {
    24                 public void run() {
    25                     simple(processor);
    26                 }
    27             };
    28             new Thread(simple).start();
    29 
    30         } catch (Exception x) {
    31             x.printStackTrace();
    32         }
    33     }
    34 
    35     public static void simple(DemoService.Processor processor) {
    36         try {
    37             TServerTransport serverTransport = new TServerSocket(9090);
    38             TServer server = new TSimpleServer(new Args(serverTransport).processor(processor));
    39             System.out.println("Starting the simple server...");
    40             server.serve();
    41         } catch (Exception e) {
    42             e.printStackTrace();
    43         }
    44     }
    45 
    46 
    47 }
     

    这里监听9090端口,响应client的调用请求。 

    3.5 client调用示例

     
     1 package yjmyzz.thrift.study;
     2 
     3 import org.apache.thrift.TException;
     4 import org.apache.thrift.protocol.TBinaryProtocol;
     5 import org.apache.thrift.protocol.TProtocol;
     6 import org.apache.thrift.transport.TSocket;
     7 import org.apache.thrift.transport.TTransport;
     8 import yjmyzz.thrift.study.dto.QueryParameter;
     9 import yjmyzz.thrift.study.service.DemoService;
    10 
    11 public class ThriftClient {
    12 
    13     public static void main(String[] args) {
    14 
    15         try {
    16             TTransport transport;
    17             transport = new TSocket("localhost", 9090);
    18             transport.open();
    19 
    20             TProtocol protocol = new TBinaryProtocol(transport);
    21             DemoService.Client client = new DemoService.Client(protocol);
    22 
    23             System.out.println(client.ping());
    24 
    25             int max = 100000;
    26 
    27             Long start = System.currentTimeMillis();
    28 
    29             for (int i = 0; i < max; i++) {
    30                 call(client);
    31             }
    32 
    33             Long end = System.currentTimeMillis();
    34 
    35             Long elapse = end - start;
    36 
    37             int perform = Double.valueOf(max / (elapse / 1000d)).intValue();
    38 
    39             System.out.print("thrift " + max + " 次RPC调用,耗时:" + elapse + "毫秒,平均" + perform + "次/秒");
    40 
    41             transport.close();
    42 
    43         } catch (TException x) {
    44             x.printStackTrace();
    45         }
    46     }
    47 
    48     private static void call(DemoService.Client client) throws TException {
    49 
    50         //client.ping();
    51         //System.out.println("ping()=>" + client.ping());
    52 
    53         QueryParameter parameter = new QueryParameter();
    54         parameter.setAgeStart(Short.valueOf("5"));
    55         parameter.setAgeEnd(Short.valueOf("50"));
    56 
    57         client.getPersonList(parameter);
    58         //System.out.println(client.getPersonList(parameter));
    59     }
    60 }
     

    在我mac老爷本(2011年买的)上测试出来的结果,而且server使用的SimpleServer同步阻塞模式,如果采用多线程非阻塞模式,在服务器上性能相信至少还能翻N倍不成问题:

    thrift 100000 次RPC调用,耗时:7774毫秒,平均12863次/秒

    即使按这个结果来估算,1秒至少处理1w次,1小时3600秒就是3.6kw次,1天24小时,每天处理上亿次调用毫无压力,相信已经能满足很多公司的要求了。而且thrift出来很多年了,相对比较成熟,如果项目是异构系统,要兼容多种语言之间的相互调用,thrift是不错的选择。

    但最后也提醒一下,thrift虽然跨语言不假,但是在不同语言的实现上,性能相差甚远,上面的示例client、server都是采用java开发,如果把server换成c#,结果就惨不忍睹了(相差几个数量级),大家可以自行测试,建议实际项目中,至少server端使用java语言(或c++)开发。

    另外在使用上,有一些小限制:一个Server只能对应一个Service接口,也就是说,如果有多个服务,要么融合成一个大接口,要么启多个server(对应多个端口)

     参见:http://www.cnblogs.com/yjmyzz/p/thrift-hello-world.html

                http://www.cnblogs.com/yjmyzz/p/thrift-classname-independent.html

               http://www.cnblogs.com/tianhuilove/archive/2011/09/05/2167669.html

               http://www.cnblogs.com/yjmyzz/p/4823082.html

  • 相关阅读:
    日志记录到txt文件
    使用NuGet安装EntityFramework4.2
    Redis 安装与简单示例 <第一篇>
    时间加减时间段(年、月、日、分、秒)
    控件属性设置
    window.showModalDialog 与window.open传递参数的不同?
    如何进行js动态生成option?如何实现二级连动?
    System.Data.SqlClient.SqlError: 备份集中的数据库备份与现有的 'XXX' 数据库不同
    如何激发手机的高分辨率
    PHP--正则表达式和样式匹配--小记
  • 原文地址:https://www.cnblogs.com/moonandstar08/p/5161797.html
Copyright © 2011-2022 走看看