• Thrift 开发简记


    目标

    需支持种类繁多的数据类型、跨语言、跨平台、高性能、兼容性且可扩展

    • 数据类型系统
    • 传输层 Transport
    • 编码/解码层(或序列化/反序列化,协议层) Protocol
    • 版本系统 支持可插拔、兼容的数据的机制
    • 处理器 生成代码和RPC调用 Processor

    特性和非特性

    特性

    • 中间语言描述文件
    • 多语言支持
    • 命名空间
    • 类型和复合类型、容器
    • 服务、服务继承
    • 异常
    • 异步

    非特性

    • 非自包含结构体
    • 结构体继承
    • 多态
    • 重载
    • 多型容器
    • null类型返回值

    IDL中间描述语言

    • 基本的数据类型(bool/byte/i16/i32/i64/double/binary/string)
    • 复合类型(list, set, map<t1,t2>)
    • 枚举类型(enum)
    • 结构体(struct)
    • 命名空间(namespace)
    • typedef 重声明类型
    • 注释
    • 常量const修饰
    • 异常exception,语义和功能含义上类似于struct,只是关键字不同而已
    • include外部thrift文件
    • service服务(service)以及服务继承:
      1. 注意一个service生成一个为server的服务接口和为客户端的stubs存根(桩);
      2. oneway修饰的接口函数表示客户端仅请求,不需要等待响应,且该oneway修饰的方式返回值只能为void;
      3. service服务支持继承,但结构体不支持。

    基本概念

    Thrift 分层结构堆栈

    	+-------------------------------------------+
    	| Server                                    |
    	| (single-threaded, event-driven etc)       |
    	+-------------------------------------------+
    	| Processor                                 |
    	| (compiler generated, RPC)                 |
    	+-------------------------------------------+
    	| Protocol                                  |
    	| (JSON, compact etc)                       |
    	+-------------------------------------------+
    	| Transport                                 |
    	| (raw TCP, HTTP,File etc)                 |
    	+-------------------------------------------+
    

    Transport传输(抽象层)

    • 生成的代码使用传输层来实现数据转移,一般基于TCP/IP协议栈实现通信,也可用其他如共享内存、磁盘文件等;
    • 提供了简单的读、写抽象操作,以解耦序列化/反序列化操作(I/O层抽象(如虚函数查找)以及实际的I/O系统操作的权衡考虑);
    • 提供接口一般有:open、isOpen、close、read、write、flush;
    • 此外除了以上接口,还thrift提供了ServerTransport接口用以接收或创建原始的传输对象;
    • 该ServerTransport主要用于服务器端为incoming连接对象来创建一个新的传输对象,其提供的接口有open、listen、accept、close;
    • 此外开发者也可基于提供的抽象接口实现自定义的传输层实现。

    Protocol协议(编码/解码层、抽象层)

    • 其抽象了用以将一个内存数据结构转为流或帧的数据格式,Protocol将数据类型的编码或解码过程;
    • 因此Protocol需要负责实现双向的解码/编码,以实现序列化和反序列化;
    • 已提供的可用的:JSON、XML、plain text、compact binart等;
    • 提供的接口比较多:成对的writeMessageBegin、writeMessageEnd、writeMapBegin、writeMapEnd,以及读对应的读操作等顾名思义的接口名称;
    • Thrift的Protocol主要是面向流的设计,其不需要任何显式的框架,也不需要知道字符串长度、列表项数等。

    Processor处理器(RPC实现部分)

    • 其封装了从输入流读取数据和写入数据至输出流;
    • 其中Protocol协议对象代表了此处的输入输出流;
    • 已提供的接口:process;
    • 特定服务的处理器实现已由编译器生成;
    • Processor本质上读取数据是由input protocol获取,委托处理给用户实现的handler处理器处理;
    • 其通过output protocol写响应数据流。

    Server服务器

    Server拥有以下的一些特性描述:

    • 创建一个Transport传输对象;
    • 为该Transport对象创建input/output的Protocols;
    • 基于该input/output创建一个Processor处理器对象;
    • 等待incoming 连接并把它们交给Processor处理器。

    编译器生成代码

    thrift.exe -r --gen cpp example.thrift
    (说明:example IDL文件包含名为Twitter的service)

    生成文件:

    
    |-- example_constants.cpp
    	|-- example_constants.h
    	|-- example_types.cpp
    	|-- example_types.h
    	|-- Twitter.cpp
    	|-- Twitter.h
    	`-- Twitter_server.skeleton.cpp
    
    

    文件说明:

    • example_constants.h/cpp:为IDL文件中的常量,所有的常量被包装为一个类内里,且生成一个该类的全局对象。

    • example_types.h/cpp:为IDL文件中的声明的类型。

    • 其中枚举被结构体包装;

    • 结构体被包装为类;

    • 异常exception被包装为类;

    • typedef的还是被typedef;

    • 另外还有一些operator<<输出流辅助重载函数,以及swap交互函数等。

    • Twitter_server.skeleton.cpp:一个生成的以TSimpleServer的server端的实现骨架示例程序代码。其中服务器端可继承实现TwitterIf相关接口处理程序,实现具体的服务处理。

    基本代码:

    
    ::apache::thrift::stdcxx::shared_ptr<TwitterHandler> handler(new TwitterHandler());
    ::apache::thrift::stdcxx::shared_ptr<TProcessor> processor(new TwitterProcessor(handler));
    ::apache::thrift::stdcxx::shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
    ::apache::thrift::stdcxx::shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());
    ::apache::thrift::stdcxx::shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());
    
    TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
    server.serve();
    
    

    描述:

    • 主要的一个具体的处理程序handler(TwitterHandler);

    • 一个processor(TwitterProcessor);

    • 一个serverTransport;

    • 另外的transportFactory以及protocolFactory,甚至TSimpleServer也可换用其他的方式。

    • Twitter.h/cpp:生成的服务接口
      基本上IDL中一个service一个对应的.h/cpp对;
      接口中的各函数返回值和参数的均包装为类,包括void、bool等基本类型;
      以上生成的文件,除了Twitter_server.skeleton.cpp,均可为客户端和服务端共享;

    • 如上说明:

    • 服务端一般实现TwitterIf接口或者说一个继承该TwitterIf接口的handler;

    • 客户端一般可直接使用Twitter.h中的TwitterClient;

    • 当然客户端还需要配置对应protocol对象和transport对象以及实际的transport包装的通信方式,如socket;

    • 基本上均可分层次使用不同的protocol对象和transport对象以及底层通信。

    另外重要的:

    • client端能够主动与server端通信,但server端不能主动与client端通信而只能被动地对client端的请求作出应答;
    • 要想实现服务器向客户端推送数据的双向通信,则可;
    • 方法1:客户端轮询,让服务器返回数据,延迟大而且浪费资源开销大;
    • 方法2:也即是让客户端也成为服务器,让服务器也扮演客户端的角色,不过此方式需要在通信双方之间建立两个通信通道,开启两个端口,比较繁琐,但是也很普遍;
    • 方法3:采用socket或其他的双向传输方式支持来实现。

    最佳实践

    • 当需要修改thrift的IDL文件时:

      1. 不要修改已存在的数值id值;
      2. 任何你新添加的fields应该为optional的,避免新旧版本不兼容;
      3. 应该为新添加的fields设置合理的默认值;
      4. 非必需的字段可以删除,只要不再使用该数值id号以及后来的新加的fields不要再用该id;
      5. 改变一个默认值是可以的,因为默认值一般是不会被传输的,因此如果一个特别的字段没有被设置值,那么程序会看到自己端的默认值为其定义,而发送者的默认值有可能与接受者的默认值不同。
    • 版本系统问题(添加域是optional且有默认值时,否则可能会不一致):

    • 添加域:

      • 旧客户端、新服务端,客户端发给服务端时,服务端针对没有的域使用默认的值。

      • 新客户端、旧服务端,客户端发给服务端时,服务端对于无法识别的域则直接忽略丢弃。

    • 移除域:

      • 旧客户端、新服务端,客户端发给服务端时,服务端针对没有的域时直接忽略。

      • 新客户端、旧服务端,客户端发给服务端时,服务端可能存在不一致的风险问题。

  • 相关阅读:
    mysql重启.....
    tomcat双向认证
    tomcat单向认证
    tomcat ssi使用
    各种排序
    字符转换
    threeSum问题
    求出0~999之间的所有“水仙花数”并输出
    动态规划
    迷惑一天的代码
  • 原文地址:https://www.cnblogs.com/haomiao/p/11646779.html
Copyright © 2020-2023  润新知