前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java学习笔记(十)——Thrift入门及一些基础知识介绍

Java学习笔记(十)——Thrift入门及一些基础知识介绍

作者头像
Bug生活2048
发布2018-10-09 12:03:32
9530
发布2018-10-09 12:03:32
举报
文章被收录于专栏:Bug生活2048

公司跨项目协作,一些部门服务框架底层封装了thrift提供服务,于是对thrift简单做了一些了解。

关于thrift

Facebook公布的一款开源跨语言的RPC框架。

什么是RPC框架呢?RPC全称为Remote Procedure Call,意为远程过程调用。

其实简单来说有两个系统,一个系统想调用另一个系统,但两个系统不在同一个进程,需要通过网络来传输,而网络传输需要涉及Socket,序列化反序列化,网络I/O等一系列的事项,牛掰的程序员将这一过程封装起来做成了一个框架,就是RPC框架,而thrift是其中一种。

thrift通过一个中间语言IDL(接口定义语言)来定义RPC的数据类型和接口,这些内容写在以.thrift结尾的文件中,然后通过特殊的编译器来生成不同语言的代码,以满足不同需要的开发者,比如java开发者,就可以生成java代码,c++ 开发者可以生成c++ 代码,生成的代码中不但包含目标语言的接口定义,方法,数据类型,还包含有RPC协议层和传输层的实现代码。

thrift的协议栈结构

安装thrift

安装前的小插曲

一开始打算用Homebrew装的,想象Homebrew好久没更新了,首先更新了一把brew update,结果mac居然报了下面的错误:

invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at:

google了一下发现是因为macOS本身升级造成的,需要安装下Command line tools,调用下命令即可,但是非常慢,装了几十分钟。

xcode-select --install

当我解决了这个问题之后,发现用brew装只能装最新版本的,但由于提供方目前使用的是0.9.3的版本,为了保证一致,所以打算跟他们一样,所以放弃了使用brew使用。

mac下正式安装

首先到官网下载对应版本的安装包,选择对应的版本就可以了。

下载下来之后,解压后进入到目录进行如下操作:

代码语言:javascript
复制
#Step 1
./configure --prefix=/usr/local/ --with-boost=/usr/local --with-libevent=/usr/local --without-ruby --without-perl --without-php --without-nodejs

#Step 2
make

#Step 3
make install 

在执行第一步的时候发现报错了,错误如下:

configure: error: Bison version 2.5 or higher must be installed on the system!

原因是mac上预安装bison版本过低,需要升级下bison,直接通过homebrew安装即可:

brew install bison

安装后还需要替换一下路径,默认安装的路径是在:

/usr/local/opt/bison/bin/bison

而系统自带时的路径是在:

/Library/Developer/CommandLineTools/usr/bin/

将原来的bison重命名下,然后将新的bison复制进去:

mv bison bison_copy cp /usr/local/opt/bison/bin/bison /Library/Developer/CommandLineTools/usr/bin/

这样重复上面的步骤即可,安装后可以查看下版本,如果正常展示就说明安装成功了:

thrift -version

数据类型及关键字

基本类型

thrift不支持无符号的类型,无符号类型可以简单理解为不能表示负数,只能表示正数的类型,像java的基本数据类型都是有符号的类型。

代码语言:javascript
复制
byte:有符号字节
i32:32位有符号整数,此外还有i16,i64
double:64位浮点数
string:二进制字符串
bool 布尔值 true或false
结构体类型(struct)

类似于c语言的结构体定义,在java中会被转化为javabean类。

代码语言:javascript
复制
struct DemoModel {
  1: i32 id;
  2: string name;
  3: double number;
  4: bool flag;
}
服务类型(service)

service:对应服务的接口,内部可定义各种方法,相当于java中创建interface一样,创建的service经过代码生成命令会生成客户端,服务端的框架代码。

代码语言:javascript
复制
service DemoService{
  string demoString(1:string s);
  i32 demoInt(1:i32 i);
  bool demoBoolean(1:bool b);
  void demoVoid();
  string demoNull();
}
异常类型(Exception)
代码语言:javascript
复制
exception RequestException {

  1:i32 code;

  2:string msg;

}
容器类型

集合中的元素可以是除了service之外的任意类型。

代码语言:javascript
复制
list<T>:有序列表,元素可重复

set<T>:无需集合,元素不可重复

map<K,V>:键值对集合
枚举类型
代码语言:javascript
复制
enum StatusEnum{

  Success,

  Error

}
命名空间(namespace)

可以理解成java中的packet,用于避免一些代码冲突,每种语言都有属于自己的命名空间的方式,比如java语言,就可以使用java语言的格式。

namespace java com.demo.project

其他常用的
代码语言:javascript
复制
required string name1: 必选参数
optional string name2: 可选参数
const string strDemo = "demo": 定义常量
include "demo.thrift" 引入文件

Thrift支持的传输协议

Thrift支持多种传输协议,我们可以根据自己的需要来选择合适的类型,总体上来说,分为文本传输和二进制传输,由于二进制传输在传输速率和节省带宽上有优势,所以大部分情况下使用二进制传输是比较好的选择。

代码语言:javascript
复制
TBinaryProtocol:使用二进制编码格式传输,是thrift的默认传输协议

TCompactProtocol:使用压缩格式传输

TJSONProtocol :使用JSON格式传输

TDebugProtocol : 使用易懂可读的文本格式进行传输,以便于debug

TSimpleJSONProtocol : 提供JSON只写的协议,适用于通过脚本语言解析

Thrift支持的传输模式

Thrift封装了一层传输层来支持底层的网络通信,在Thrift中称为Transport,不仅提供open,close,flush等方法,还有一些read/write方法。

代码语言:javascript
复制
TSocket:阻塞式IO的Transport实现,用在客户端.

TServerSocket:非阻塞式Socket,用于服务器端,用于监听TSocket.

TNonblockingSocket:非阻塞式IO的实现

TMemoryInputTransport: 封装了一个字节数组byte[]来做输入流的封装

TFramedTransport: 同样使用非阻塞方式,按块的大小进行传输,输入流封装了TMemoryInputTransport 

Thrift支持的服务模型

TSimpleServer

这种工作模式只有一个线程,循环监听传过来的请求并对其进行处理,处理完才能接受下一个请求,是一种阻塞式IO的实现,因为效率比较低,实际线上环境一般用不到.一般用于开发时候演示工作流程时使用。

TNonblockingServer

这种模式与TsimpleServer最大的区别就是使用NIO,也就是非阻塞是IO的方式实现IO的多路复用,它可以同时监听多个socket的变化,但因为业务处理上还是单线程模式,所以在一些业务处理比较复杂耗时的时候效率还是不高,因为多个请求任务依然需要排队一个一个进行处理。

TThreadPoolServer

这种模式引入了线程池,主线程只负责accept,即监听Socket,当有新的请求(客户端Socket)来时,就会在线程池里起一个线程来处理业务逻辑,这样在并发量比较大的时候(但不超过线程池的数量)每个请求都能及时被处理,效率比较高,但一旦并发量很大的时候(超过线程池数量),后面来的请求也只能排队等待。

TThreadedSelectorServer

这是一种多线程半同步半异步的服务模型,是Thrift提供的最复杂最高级的服务模型,内部有一个专门负责处理监听Socket的线程,有多个专门处理业务中网络IO的线程,有一个专门负责决定将新Socket连接分配给哪一个线程处理的起负载均衡作用的线程,还有一个工作线程池.这种模型既可以响应大量并发连接的请求又可以快速对网络IO进行读写,能适配很多场景,因此是一种使用比较高频的服务模。

java实现

通过一个小demo来了解下thrift和具体的编码实现。

首先我们创建个thrift文件,简单定义了一个方法:

代码语言:javascript
复制
namespace java service.demo
service Hello{
    string helloString(1:string para)
}

创建好Hello.thrift后通过终端生成java的代码:

thrift -r -gen java Hello.thrift

发现在当前目录下多了一个gen-java的目录,里面的有一个Hello.java的文件.这个java文件包含Hello服务的接口定义Hello.Iface,以及服务调用的底层通信细节,包括客户端的调用逻辑Hello.Client以及服务端的处理逻辑Hello.Processor

接着可以引入jar包,然后将生成的代码复制到项目中:

代码语言:javascript
复制
<dependency>
     <groupId>org.apache.thrift</groupId>
     <artifactId>libthrift</artifactId>
     <version>0.9.3</version>
</dependency>

然后创建HelloServiceImpl实现Hello.Iface接口:

代码语言:javascript
复制
package service.demo;
import org.apache.thrift.TException;

public class HelloServiceImpl implements Hello.Iface {
    public String helloString(String para) throws TException {
        return "result:"+para;
    }
}

接着创建服务端实现代码HelloServiceServer,把HelloServiceImpl作为一个具体的处理器传递给Thrift服务器:

代码语言:javascript
复制
package service.demo;
import org.apache.thrift.TProcessor;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.server.TServer;
import org.apache.thrift.server.TSimpleServer;
import org.apache.thrift.transport.TServerSocket;
import org.apache.thrift.transport.TTransportException;


public class HelloServiceServer {
    public static void main(String[] args) {
        try {
            System.out.println("服务端开启....");
            TProcessor tprocessor = new Hello.Processor<Hello.Iface>(new HelloServiceImpl());
            // 简单的单线程服务模型
            TServerSocket serverTransport = new TServerSocket(9898);
            TServer.Args tArgs = new TServer.Args(serverTransport);
            tArgs.processor(tprocessor);
            tArgs.protocolFactory(new TBinaryProtocol.Factory());
            TServer server = new TSimpleServer(tArgs);
            server.serve();
            }catch (TTransportException e) {
            e.printStackTrace();
        }
    }
}

最后创建客户端实现代码HelloServiceClient,调用Hello.client访问服务端的逻辑实现

代码语言:javascript
复制
package service.demo;

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;


public class HelloServiceClient {

    public static void main(String[] args) {
        System.out.println("客户端启动....");
        TTransport transport = null;
        try {
            transport = new TSocket("localhost", 9898, 30000);
            // 协议要和服务端一致
            TProtocol protocol = new TBinaryProtocol(transport);
            Hello.Client client = new Hello.Client(protocol);
            transport.open();
            String result = client.helloString("哈哈");
            System.out.println(result);
        } catch (TTransportException e) {
            e.printStackTrace();
        } catch (TException e) {
            e.printStackTrace();
        } finally {
            if (null != transport) {
                transport.close();
            }
        }
    }
}

启动服务端和客户端就能看到效果啦。

总结

简单了解了thrift之后就开始代码变现了,有空还是需要深入了解下的。

另外看到一篇thrift与http性能对比的文章(小测thrift和http在node.js中的性能对比),发现thrift性能还是可以的,毕竟现在大多情况下我们的服务还是使用http通过json传输的。如果对于性能有高要求的业务场景,可以考虑thrift的。

相关阅读

Spring Boot学习笔记(一)环境搭建

Spring Boot学习笔记(二)Windows下IDEA 配置Maven

Spring Boot学习笔记(三)IDEA 下配置Git

Spring Boot学习笔记(四)构建RESTful API标准工程实例

Spring Boot学习笔记(五)整合MyBatis实现数据库访问

Spring Boot学习笔记(六)结合MyBatis实现较为复杂的RESTful API

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-09-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Bug生活2048 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 关于thrift
  • 安装thrift
    • 安装前的小插曲
      • mac下正式安装
      • 数据类型及关键字
        • 基本类型
          • 结构体类型(struct)
            • 服务类型(service)
              • 异常类型(Exception)
                • 容器类型
                  • 枚举类型
                    • 命名空间(namespace)
                      • 其他常用的
                      • Thrift支持的传输协议
                      • Thrift支持的传输模式
                      • Thrift支持的服务模型
                        • TSimpleServer
                          • TNonblockingServer
                            • TThreadPoolServer
                              • TThreadedSelectorServer
                              • java实现
                              • 总结
                              相关产品与服务
                              云服务器
                              云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
                              领券
                              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档