rpc框架之thrift教程1 - 安装 及 hello world

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:\thrift下,然后将thrift-0.9.2.exe改个简单的名字,比如:thrift.exe(这一步非必须),最后在环境变量的path路径里,把c:\thrift加上,保证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-contract\src\thrift这个目录下。

3.1 生成目标语言源文件

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

thrift -gen java dto.thrift

thrift -gen java service.thrift

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

上图是生成后的源代码结构,由于src\thrift目录并不是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对于接口定义来讲,可以不用(但最终在server\client端运行时,这个包不可少)。然后就可以用 mvn clean install 来生成jar包并安装到本机maven仓库中了,注意这里有一个小问题:

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

3.3 server端的接口实现

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

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++)开发。

时间: 2024-08-29 02:49:18

rpc框架之thrift教程1 - 安装 及 hello world的相关文章

rpc框架之thrift教程2 - 基本概念

thrift的基本构架: 上图源自:http://jnb.ociweb.com/jnb/jnbJun2009.html 底层Underlying I/O以上的部分,都是由thrift编译器生成的代码,其中: Your Code 这是根据thrift文件中定义的dto及service接口方法 FooService.Client及FooService.Processer是thrift生成的用于客户端及服务端的标准代码 Foo.read/write 参数对象及结果对象在传输时,最终需要在client.

rpc框架之 thrift连接池实现

接前一篇rpc框架之HA/负载均衡构架设计 继续,写了一个简单的thrift 连接池: 先做点准备工作: package yjmyzz; public class ServerInfo { public String getHost() { return host; } public void setHost(String host) { this.host = host; } public int getPort() { return port; } public void setPort(i

RPC框架之Thrift

目前流行的服务调用方式有很多种,例如基于SOAP消息格式的 Web Service,基于 JSON 消息格式的 RESTful 服务等.其中所用到的数据传输方式包括 XML,JSON 等,然而 XML 相对体积太大,传输效率低,JSON 体积较小,新颖,但还不够完善. 本文将介绍由 Facebook 开发的远程服务调用框架 Apache Thrift,它采用接口描述语言定义并创建服务,支持可扩展的跨语言服务开发,所包含的代码生成引擎可以在多种语言中,如 C++, Java, Python, PH

RPC框架之Thrift分析(转)

一.简介 1.Thrift是Facebook开发的跨语言的RPC服务框架.随后贡献给Apache开源组织.成为RPC服务的主流框架. 2.特点: 优点: 跨语言,支持java.c/c++.python等多种编程语言 IDL定义接口函数和数据类型 支持二进制传输,效率高 支持多种工作模型,单线程模型.线程池模型.非阻塞模型 缺点: 文档不多 各版本不兼容,升级不方便 二.分析 Thrift分为服务端(server)和客户端(Client)两个对应的部分.代码分层设计,分为Transport(传输层

rpc框架之avro教程1-hello world

avro是hadoop的一个子项目,提供的功能与thrift.Protocol Buffer类似,都支持二进制高效序列化,也自带RPC机制,但是avro使用起来更简单,无需象thrift那样生成目标语言源代码,目前支持的语言有java.c#.php.c++等(详情见:https://cwiki.apache.org/confluence/display/AVRO/Supported+Languages),hadoop生态圈中的hive.pig已经在使用avro pom.xml 1 <?xml v

Apache thrift - 使用,内部实现及构建一个可扩展的RPC框架

本文首先介绍了什么是Apache Thrift,接着介绍了Thrift的安装部署及如何利用Thrift来实现一个简单的RPC应用,并简单的探究了一下Thrift的内部实现原理,最后给出一个基于Thrift的可扩展的分布式RPC调用框架,在中小型项目中是一个常见的SOA实践. Thrift介绍 Apache Thrift是Facebook 开发的远程服务调用框架,它采用接口描述语言(IDL)定义并创建服务,支持可扩展的跨语言服务开发,所包含的代码生成引擎可以在多种语言中,如 C++, Java,

微博轻量级RPC框架Motan正式开源:支撑千亿调用

支撑微博千亿调用的轻量级 RPC 框架 Motan 正式开源了,项目地址为https://github.com/weibocom/motan. 微博轻量级RPC框架Motan正式开源 Motan 是微博技术团队研发的基于 Java 的轻量级 RPC 框架,已在微博内部大规模应用多年,每天稳定支撑微博上亿次的内部调用.Motan 基于微博的高并发和高负载场景优化,成为一套简单.易用.高可用的 RPC 服务框架. Motan 功能特点:简单.易用.高可用 无侵入集成.简单易用,通过 Spring 配

一个简单的&quot;RPC框架&quot;代码分析

0,服务接口定义---Echo.java /* * 定义了服务器提供的服务类型 */ public interface Echo { public String echo(String string); } 一,客户端代码分析--实现类:MainClient.java 客户端实现包括:获得一个代理对象,并使用该代理对象调用服务器的服务.获取代理对象时,需要指定被代理的类(相当于服务器端提供的服务名),Server IP,Port. Echo echo = RPC.getProxy(Echo.cl

RPC框架实践之:Apache Thrift

一.概述 RPC(Remote Procedure Call)即 远程过程调用,说的这么抽象,其实简化理解就是一个节点如何请求另一节点所提供的服务.在文章 微服务调用链追踪中心搭建 一文中模拟出来的调用链:ServiceA ---> ServiceB ---> ServiceC 就是一个远程调用的例子,只不过这篇文章里是通过RestTemplate这种 同步调用方式,利用的是HTTP协议在应用层完成的,这种方法虽然奏效,但有时效率并不高.而RPC可以不依赖于应用层协议,可以直接基于TCP进行远