• Thrift原理与使用实例


    一 Thrift框架介绍

    1 前言

    Thrift是一个跨语言的服务部署框架,最初由Faceboo开发并进入Apache开源项目。

    Thrift特征如下:

    1)Thrift有自己的跨机器通信框架,并提供一套库

    2)Thrift是一个代码生成器,按照它的规则,可以生成多种编程语言的通信过程代码

    Thrift通过中间语言(IDL, 接口定义语言)来定义RPC的接口和数据类型,然后通过一个编译器生成不同语言的代码(目前支持C++,Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk和OCaml),并由生成的代码负责RPC协议层和传输层的实现。

    2 架构

    1).thrift文件定义数据结构和服务接口

    2)代码生成器生成若干符合约定通信格式的代码

    3)thrift应用框架:包括thrift自身提供的库函数

    4)第三方库:按照运行的模式,生成的代码中可能需要调用第三方库

    image

    Thrift实际上是实现了C/S模式,代码生成工具通过接口定义文件,生成服务器端和客户端代码(可以为不同语言),从而实现服务端和客户端跨语言的支持。

    用户在Thirft描述文件中声明自己的服务,这些服务经过编译后会生成相应语言的代码文件,然后用户实现服务(客户端调用服务,服务器端提服务)便可以了。

    protocol协议层:定义数据传输格式,可以为二进制或者XML等

    transport传输层:定义数据传输方式,可以为TCP/IP传输,内存共享或者文件共享

    3、 支持的数据传输格式、数据传输方式和服务模型

    1)支持的传输格式:是对传输协议的封装,传输采用二进制、XML或text来表示信息

    TBinaryProtocol – 二进制格式.

    TCompactProtocol – 压缩格式

    TJSONProtocol – JSON格式

    TSimpleJSONProtocol –提供JSON只写协议, 生成的文件很容易通过脚本语言解析。

    TDebugProtocol – 使用易懂的可读的文本格式,以便于debug

    (2) 支持的数据传输方式:信息的传输渠道以及读写方式

    TSocket -阻塞式socker

    TFileTransport – 以文件形式进行传输。

    TMemoryTransport – 将内存用于I/O. java实现时内部实际使用了简单的ByteArrayOutputStream。

    TFramedTransport – 以frame为单位进行传输,非阻塞式服务中使用。

    TBufferedTransport - 

    TZlibTransport – 使用zlib进行压缩, 与其他传输方式联合使用。当前无java实现。

    (3)支持的服务模型

    TSimpleServer – 简单的单线程服务模型,常用于测试

    TThreadPoolServer – 多线程服务模型,使用标准的阻塞式IO。

    TNonblockingServer – 多线程服务模型,使用非阻塞式IO(需使用TFramedTransport数据传输方式)

    4 利用Thrift部署服务

    主要流程:

    (1)编写服务说明,保存到.thrift文件

       主要包括变量声明、数据结构struct声明、服务service接口声明

       一般将服务放到一个.thrift文件中,服务的编写语法与C语言语法基本一致

      

      下面分析Thrift的tutorial中带的例子tutorial.thrift

      包含头文件:

      include “shared.thrift”

      指定目标语言

      namespace cpp tutorial

      定义变量:

      const i32 INT32CONSTANT = 9853

      定义结构体:

      struct Work

      {

         1: i32 num1 = 0,

         2: i32 num2,

         3: Operation op,

         4: optional string comment,

       }
      定义服务:

      service Calculator extends shared.SharedService

      {

        void ping(),

        i32 add(1:i32 num1, 2:i32 num2),

        i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch),

        oneway void zip()

      }

    (2)根据需要,编译.thrift文件,生成相应语言的源代码

       生成C++代码:./thrift --gen cpp tutorial.thrift,结果代码存放在gen-cpp目录下

         生成java代码:./thrift --gen java tutorial.thrift,结果代码存放在gen-java目录下

    (3)根据实际需要,编写client端和server端代码

      client端和sever端代码要调用编译.thrift生成的中间文件。

      下面分析cpp文件下面的CppClient.cpp和CppServer.cpp代码

      image

      在client端,用户自定义CalculatorClient类型的对象(用户在.thrift文件中声明的服务名称是Calculator, 则生成的中间代码中的主类为CalculatorClient)

      该对象中封装了各种服务,可以直接调用(如client.ping()), 然后thrift会通过封装的rpc调用server端同名的函数。

      在server端,需要实现在.thrift文件中声明的服务中的所有功能,以便处理client发过来的请求。

    二 Thrift使用指南

    1 语法参考

     1.1 types

      Thrift类型系统包括预定义基本类型,用户自定义结构体,容器类型,异常和服务定义

     1.2 注释

     1.3 命名空间

     1.4 文件包含

     1.5 常量

     1.6 定义服务:

      Service支持继承,一个service可使用extends关键字继承另一个service

    2 产生代码

      Thrift的网络栈如下:

      image

      Transport

      TransPort层提供了简单的网络读写抽象层。

      Transport接口提供的方法:open、close、read、write、flush

      除了以上几个接口,Thrift使用ServerTransport接口接受或者创建原始transport对象

      ServerTransport用在server端,为到来的连接创建Transport对象:open、listen、accept、close

      Protocol

      Protocol抽象层定义了一种将内存中数据结构映射成可传输格式的机制

      Protocol的实现要给出编码机制并负责对数据进行序列化

      Protocol提供的接口如下:

      writeMessageBegin(name, type, seq)

      writeMessageEnd()

      writeStructBegin(name)

      writeStructEnd()

      writeFieldBegin(name, type, id)

      writeFieldEnd()

      writeFieldStop()

      writeMapBegin(ktype, vtype, size)

      writeMapEnd()

      writeListBegin(etype, size)

      writeListEnd()

      writeSetBegin(etype, size)

      writeSetEnd()

      writeBool(bool)

      writeByte(byte)

      writeI16(i16)

      writeI32(i32)

      writeI64(i64)

      writeDouble(double)

      writeString(string)

      name, type, seq = readMessageBegin()

      readMessageEnd()

      name = readStructBegin()

      readStructEnd()

      name, type, id = readFieldBegin()

      readFieldEnd()

      k, v, size = readMapBegin()

      readMapEnd()

      etype, size = readListBegin()

      readListEnd()

      etype, size = readSetBegin()

      readSetEnd()

      bool = readBool()

      byte = readByte()

      i16 = readI16()

      i32 = readI32()

      i64 = readI64()

      double = readDouble()

      string = readString()

      Processor

      Processor封装了从输入数据流中读数据和向数据数据流中写数据的操作。读写数据流用Protocol对象表示

      Processor的结构体非常简单:

      interface TProcessor 

      {

        bool process(TProtocol in, TProtocol out) throws TException

      }

      与服务相关的processor实现由编译器产生。

      Processor主要工作流程如下:从连接中读取数据(使用输入protocol),将处理授权给handler(由用户实现),最后将结果写到连接上(使用输出protocol)。

      Server

      Server将以上所有特性集成在一起:

      (1)  创建一个transport对象

      (2)  为transport对象创建输入输出protocol

      (3)  基于输入输出protocol创建processor

      (4)  等待连接请求并将之交给processor处理

      

    综合:

    http://blog.csdn.net/guxch/article/details/12157151

    http://blog.sina.com.cn/s/blog_72995dcc0101gn82.html

  • 相关阅读:
    VIM文本替换命令
    VIM格式化代码(How to format code with VIM)
    字符串匹配的Boyer-Moore算法
    Java中数组的遍历
    UVa10723
    uva242,Stamps and Envelope Size
    UVa1630,Folding
    uva1629,Cake Slicing,记忆化搜索
    uva 10118,记忆化搜索
    uva10003
  • 原文地址:https://www.cnblogs.com/buptlyn/p/4459577.html
Copyright © 2020-2023  润新知