Thrift 简单介绍

前言

最近小组组织了分享活动,记录下

正文

1. 什么是Thrift

Thrift的起源

Thrift是一种接口描述语言和二进制通讯协议,它被用来定义和创建跨语言的服务。它被当作一个远程过程调用(RPC)框架来使用,是由Facebook为“大规模跨语言服务开发”而开发的。它通过一个代码生成引擎联合了一个软件栈,来创建不同程度的、无缝的跨平台高效服务,可以使用C#、C++(基于POSIX兼容系统)Cappuccino、Cocoa、Delphi、Erlang、Go、Haskell、Java、Node.js、OCaml、Perl、PHP、Python、Ruby和Smalltalk编程语言开发。 2007由Facebook开源,2008年5月进入Apache孵化器, 2010年10月成为Apache的顶级项目。

什么是RPC

远程过程调用(Remote Procedure Call,缩写为 RPC)是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编程。 比如 Java RMI(远程方法调用(Remote
Method Invocation)。能够让在某个java虚拟机上的对象像调用本地对象一样调用另一个java虚拟机中的对象上的方法)。

rpc.PNG

从上图可以看出, RPC 本身是 client-server模型,也是一种 request-response 协议。
有些实现扩展了远程调用的模型,实现了双向的服务调用,但是不管怎样,调用过程还是由一个客户端发起,服务器端提供响应,基本模型没有变化。
服务的调用过程为:

  1. client调用client stub,这是一次本地过程调用
  2. client stub将参数打包成一个消息,然后发送这个消息。打包过程也叫做 marshalling
  3. client所在的系统将消息发送给server
  4. server的的系统将收到的包传给server stub
  5. server stub解包得到参数。 解包也被称作 unmarshalling
  6. 最后server stub调用服务过程. 返回结果按照相反的步骤传给client

其他RPC框架

目前的 RPC 框架大致有两种不同的侧重方向,一种偏重于服务治理,另一种偏重于跨语言调用。

  1. 服务治理型的 RPC 框架有Dubbo、Motan 等,这类的 RPC 框架的特点是功能丰富,提供高性能的远程调用以及服务发现和治理功能,适用于大型服务的微服务化拆分以及管理,对于特定语言(Java)的项目可以十分友好的透明化接入。但缺点是语言耦合度较高,跨语言支持难度较大。
  2. 跨语言调用型的 RPC 框架有 Thrift、gRPC 等,这一类的 RPC 框架重点关注于服务的跨语言调用,能够支持大部分的语言进行语言无关的调用,非常适合于为不同语言提供通用远程服务的场景。但这类框架没有服务发现相关机制,实际使用时一般需要代理层进行请求转发和负载均衡策略控制

RPC VS RESTFUL

RPC 的消息传输可以通过 TCP、UDP 或者 HTTP等。RPC 通过 HTTP 传输消息的时候和 RESTful的架构是类似的,但是也有不同。

  1. 从使用方面来看,RPC 的客户端和服务器端师紧耦合的。RESTful基于 http的语义操作资源,参数的顺序一般没有关系,也很容易的通过代理转换链接和资源位置,从这一点上来说,RESTful 更灵活。而且它们操作的对象不一样。 RPC 操作的是方法对象。 RESTful 操作的是资源(resource),而不是方法。
  2. 从性能角度看,使用Http时,Http本身提供了丰富的状态功能与扩展功能,但也正由于Http提供的功能过多,导致在网络传输时,需要携带的信息更多,从性能角度上讲,较为低效。而RPC服务网络传输上仅传输与业务内容相关的数据,传输数据更小,性能更高。

Thrift的协议栈结构

thrift.PNG

Thrift是一种C/S的架构体系.在最上层是用户自行实现的业务逻辑代码.第二层是由Thrift编译器自动生成的代码,主要用于结构化数据的解析,发送和接收。TServer主要任务是高效的接受客户端请求,并将请求转发Processor处理。Processor负责对客户端的请求做出响应,包括RPC请求转发,调用参数解析和用户逻辑调用,返回值写回等处理。从TProtocol以下部分是thirft的传输协议和底层I/O通信。TProtocol是用于数据类型解析的,将结构化数据转化为字节流给TTransport进行传输。TTransport是与底层数据传输密切相关的传输层,负责以字节流方式接收和发送消息体,不关注是什么数据类型。底层IO负责实际的数据传输,包括socket、文件和压缩数据流等。

数据类型
  1. Base Types:基本类型
  2. Struct:结构体类型
  3. Container:容器类型,即List、Set、Map
  4. Exception:异常类型
  5. Service: 定义对象的接口,和一系列方法
协议

Thrift可以让你选择客户端与服务端之间传输通信协议的类别,在传输协议上总体上划分为文本(text)和二进制(binary)传输协议, 为节约带宽,提供传输效率,一般情况下使用二进制类型的传输协议为多数,但有时会还是会使用基于文本类型的协议,这需要根据项目/产品中的实际需求:

  1. TBinaryProtocol – 二进制编码格式进行数据传输。
  2. TCompactProtocol – 这种协议非常有效的,使用Variable-Length Quantity (VLQ) 编码对数据进行压缩。
  3. TJSONProtocol – 使用JSON的数据编码协议进行数据传输。
  4. TSimpleJSONProtocol – 这种节约只提供JSON只写的协议,适用于通过脚本语言解析。
  5. TDebugProtocol – 在开发的过程中帮助开发人员调试用的,以文本的形式展现方便阅读。
传输层
  1. TSocket- 使用堵塞式I/O进行传输,也是最常见的模式。
  2. TFramedTransport- 使用非阻塞方式,按块的大小,进行传输,类似于Java中的NIO。
  3. TFileTransport- 顾名思义按照文件的方式进程传输,虽然这种方式不提供Java的实现,但是实现起来非常简单。
  4. TMemoryTransport- 使用内存I/O,就好比Java中的ByteArrayOutputStream实现。
  5. TZlibTransport- 使用执行zlib压缩,不提供Java的实现。
服务端类型
  1. TSimpleServer - 单线程服务器端使用标准的堵塞式I/O。
  2. TThreadPoolServer - 多线程服务器端使用标准的堵塞式I/O。
  3. TNonblockingServer – 多线程服务器端使用非堵塞式I/O,并且实现了Java中的NIO通道。

2. 为什么要用Thrift

应用

  1. Facebook的开源的日志收集系统(scribe: https://github.com/facebook/scribe)
  2. 淘宝的实时数据传输平台(TimeTunnel http://code.taobao.org/p/TimeTunnel/wiki/index)
  3. Evernote开放接口(https://github.com/evernote/evernote-thrift)
  4. Quora(http://www.quora.com/Apache-Thrift)
  5. HBase( http://abloz.com/hbase/book.html#thrift )

优缺点

  1. 支持非常多的语言绑定。
  2. thrift文件生成目标代码,简单易用。
  3. 数据结构与传输表现的分离,支持多种消息格式。
  4. 包含完整的客户端/服务端堆栈,可快速实现RPC。
  5. 支持同步和异步通信。
  6. 和protobuf(谷歌的一种灵活高效的独立于语言平台的结构化数据表示方法)一样不支持动态特性

3. 如何使用Thrift

Thrift的简单demo

先配置好Thrift的环境,写一个hello.thrift,内容如下

namespace java service.demo
service Hello{
    string helloWorld(1:string para)
}

执行如下命令生成java代码

thrift -r -gen java Hello.thrift

生成gen-java文件夹,将里面的Hello.java copy到工程里面
pom.xml文件添加依赖

<dependencies>
<dependency>
    <groupId>org.apache.thrift</groupId>
    <artifactId>libthrift</artifactId>
    <version>0.10.0</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.5</version>
</dependency>
</dependencies>

实现类

package service.demo;

import org.apache.thrift.TException;

/**
 * 1.服务实现类
 *
 * @author micheal
 * @create 2018-03-26 11:03
 **/
public class HelloServiceImpl implements Hello.Iface{
    @Override
    public String helloWorld(String para) throws TException {
        return para+":helloWorld";
    }
}

服务类

package service.demo;

import com.sun.org.apache.xpath.internal.SourceTree;
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;

/**
 * 2.服务端
 *
 * @author micheal
 * @create 2018-03-26 11:04
 **/
public class HelloServiceServer {
    public static void main(String[] args) throws TTransportException {
        System.out.println("服务端开启......");
        TProcessor tProcessor=new Hello.Processor<Hello.Iface>(new HelloServiceImpl());
        TServerSocket serverSocket = new TServerSocket(8999);
        TServer.Args tArgs = new TServer.Args(serverSocket);
        tArgs.processor(tProcessor);
        tArgs.protocolFactory(new TBinaryProtocol.Factory());
        TServer server = new TSimpleServer(tArgs);
        server.serve();
    }
}

客户端

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;

/**
 * 3.客户端
 *
 * @author micheal
 * @create 2018-03-26 11:44
 **/
public class HelloServiceClient {
    public static void main(String[] args) throws TException {
        System.out.println("客户端启动.....");
        TTransport transport =new TSocket("localhost", 8999, 30000);
        // 协议要和服务端一致
        TProtocol protocol = new TBinaryProtocol(transport);
        Hello.Client client = new Hello.Client(protocol);
        transport.open();
        String result = client.helloWorld("TOM");
        System.out.println(result);
    }
}

先启动服务端,然后启动客户端
运行结果

客户端启动.....
Received 1
TOM:helloWorld

总结

本次简单的介绍,大概的了解下RPC框架的原理以及Thrift的协议栈,下面将进行具体介绍

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容