RPC服务框架探索之Thrift

前言
架构服务化后,需要实现一套方便调用各服务的框架,现在开源如日中天,优先会寻找开源实现,如果没有合适自家公司业务的,才会考虑从零开发,尤其是一切以KPI为准绳的公司,谁会跟钱过不去?N个月之前,公司大神就开始调研了,最后选中了Thrift这个RPC服务框架。使用不熟悉的技术,我会感到很恐惧,它就相当于一个黑盒,我对它一无所知,它是如何运转的?出了问题该如何解决?带着一丝不安,查阅了相关技术文档。

RPC
很早之前听说过soap,restful api,rpc之类的服务协议,一直都没有机会深入实践,对它们理解的不够深。它们的目的都是提供本地调用远程服务的能力,只是实现方式不同而已。RPC(remote procedure call)意思是远程过程调用,编码时可以把它当作本地方法一样调用,无需关心内部的实现细节,对于调用方很友好很简单。我查阅资料,发现RPC之类的东西很早很早以前就出现了,存在即是合理的,肯定有它的理由。跟本地调用相比有什么优点缺点呢?根据查阅的资料以及自己的理解总结如下:
优势
1 提高系统吞吐能力
2 业务服务解耦
3 更易构建服务分布式集群
4 基础服务重用更方便
劣势
1 因网络开销方法执行时间更长
2 系统更复杂对运维挑战很大
3 排错成本增加
4 数据序列化消耗CPU资源
现在是移动互联时代,数据无时无刻不在产生着,随着时间的推移,随着用户数的增加,随着更多业务的开展,随着功能迭代的频繁,只有业务服务化只有更易构建分布式集群的架构才能应对这些挑战,毕竟单台服务器的能力是有限的,即使是IOE这种高端设备。尤其是现在地下黑产如此猖獗的今天,时不时的遭受到类DDOS攻击,可以方便扩展节点的架构是多么重要,否则会死的很惨。
因此通过RPC协议实现微服务架构是利大于弊的。

Thrift
Thrift是RPC服务协议的一种实现,它是由Facebook开发,2007年开源并且2008年成为Apache开源项目。它的实现目标是支持多语言跨平台简单易使用高性能对业务开发透明屏蔽实现细节专注业务开发。大部分语言提供了类库,可以让开发人员只专注在业务接口实现部分。

实现原理
它由传输层,协议层,处理器,服务层所组成,每个部分不互相依赖,职责单一。
传输层:流协议传输数据,支持socket,http,文件等媒介
协议层:数据封包解包,支持binary,compact,json等
处理器:接口代理,请求转发给相应接口处理
服务层:组装传输层,协议层,处理器,提供RPC服务
客户端调用接口-》客户端数据封包-》传输层-》服端解包-》服端处理器-》服端接口处理。处理完成遵循同样的链路响应。

服端网络模型
简单说明,不做深入了解。
1 单进程
2 单进程多线程
3 单进程事件驱动

IDL
IDL(interface description language)接口描述语言,它包含简单数据类型定义,复杂数据类型结构体定义,复杂数据类型列表定义集合定义,异常类型定义,命名空间声明,接口定义规范等,通过这些规范的组合可以定义好任意复杂的接口,定义好之后,使用IDL编译器可以生成指定语言源码,传输层协议层处理器这些代码会自动生成,只需要专注业务接口具体实现即可。具体类型定义参考官方文档吧。

安装
安装很简单,不同的系统官方文档都有说明,不需要完全死板按照步骤执行,相关依赖如果存在可以跳过相应步骤。安装成功之后就可以使用thrift命令编译IDL文件了。

命令
定义好的IDL文件名以.thrift结尾,通过thrift编译。命令参数说明如下:

  1 Usage: thrift [options] file
  2 Options:
  3   -version    Print the compiler version
  4   -o dir      Set the output directory for gen-* packages
  5                (default: current directory)
  6   -out dir    Set the ouput location for generated files.
  7                (no gen-* folder will be created)
  8   -I dir      Add a directory to the list of directories
  9                 searched for include directives
 10   -nowarn     Suppress all compiler warnings (BAD!)
 11   -strict     Strict compiler warnings on
 12   -v[erbose]  Verbose mode
 13   -r[ecurse]  Also generate included files
 14   -debug      Parse debug trace to stdout
 15   --allow-neg-keys  Allow negative field keys (Used to preserve protocol
 16                 compatibility with older .thrift files)
 17   --allow-64bit-consts  Do not print warnings about using 64-bit constants
 18   --gen STR   Generate code with a dynamically-registered generator.
 19                 STR has the form language[:key1=val1[,key2[,key3=val3]]].
 20                 Keys and values are options passed to the generator.
 21                 Many options will not require values.
 22
 23 Options related to audit operation
 24    --audit OldFile   Old Thrift file to be audited with ‘file‘
 25   -Iold dir    Add a directory to the list of directories
 26                 searched for include directives for old thrift file
 27   -Inew dir    Add a directory to the list of directories
 28                 searched for include directives for new thrift file
 29
 30 Available generators (and options):
 31   as3 (AS3):
 32     bindable:        Add [bindable] metadata to all the struct classes.
 33   c_glib (C, using GLib):
 34   cocoa (Cocoa):
 35     log_unexpected:  Log every time an unexpected field ID or type is encountered.
 36     debug_descriptions:
 37                      Allow use of debugDescription so the app can add description via a cateogory/extension
 38     validate_required:
 39                      Throws exception if any required field is not set.
 40     async_clients:   Generate clients which invoke asynchronously via block syntax.
 41     pods:            Generate imports in Cocopods framework format.
 42     promise_kit:     Generate clients which invoke asynchronously via promises.
 43   cpp (C++):
 44     cob_style:       Generate "Continuation OBject"-style classes.
 45     no_client_completion:
 46                      Omit calls to completion__() in CobClient class.
 47     no_default_operators:
 48                      Omits generation of default operators ==, != and <
 49     templates:       Generate templatized reader/writer methods.
 50     pure_enums:      Generate pure enums instead of wrapper classes.
 51     include_prefix:  Use full include paths in generated files.
 52     moveable_types:  Generate move constructors and assignment operators.
 53   csharp (C#):
 54     async:           Adds Async support using Task.Run.
 55     wcf:             Adds bindings for WCF to generated classes.
 56     serial:          Add serialization support to generated classes.
 57     nullable:        Use nullable types for properties.
 58     hashcode:        Generate a hashcode and equals implementation for classes.
 59     union:           Use new union typing, which includes a static read function for union types.
 60   d (D):
 61   dart (Dart):
 62     library_name:    Optional override for library name.
 63     library_prefix:  Generate code that can be used within an existing library.
 64                      Use a dot-separated string, e.g. "my_parent_lib.src.gen"
 65     pubspec_lib:     Optional override for thrift lib dependency in pubspec.yaml,
 66                      e.g. "thrift: 0.x.x".  Use a pipe delimiter to separate lines,
 67                      e.g. "thrift:|  git:|    url: [email protected]"
 68   delphi (delphi):
 69     ansistr_binary:  Use AnsiString for binary datatype (default is TBytes).
 70     register_types:  Enable TypeRegistry, allows for creation of struct, union
 71                      and container instances by interface or TypeInfo()
 72     constprefix:     Name TConstants classes after IDL to reduce ambiguities
 73     events:          Enable and use processing events in the generated code.
 74     xmldoc:          Enable XMLDoc comments for Help Insight etc.
 75   erl (Erlang):
 76     legacynames: Output files retain naming conventions of Thrift 0.9.1 and earlier.
 77     maps:        Generate maps instead of dicts.
 78     otp16:       Generate non-namespaced dict and set instead of dict:dict and sets:set.
 79   go (Go):
 80     package_prefix=  Package prefix for generated files.
 81     thrift_import=   Override thrift package import path (default:git.apache.org/thrift.git/lib/go/thrift)
 82     package=         Package name (default: inferred from thrift file name)
 83     ignore_initialisms
 84                      Disable automatic spelling correction of initialisms (e.g. "URL")
 85     read_write_private
 86                      Make read/write methods private, default is public Read/Write
 87   gv (Graphviz):
 88     exceptions:      Whether to draw arrows from functions to exception.
 89   haxe (Haxe):
 90     callbacks        Use onError()/onSuccess() callbacks for service methods (like AS3)
 91     rtti             Enable @:rtti for generated classes and interfaces
 92     buildmacro=my.macros.Class.method(args)
 93                      Add @:build macro calls to generated classes and interfaces
 94   hs (Haskell):
 95   html (HTML):
 96     standalone:      Self-contained mode, includes all CSS in the HTML files.
 97                      Generates no style.css file, but HTML files will be larger.
 98     noescape:        Do not escape html in doc text.
 99   java (Java):
100     beans:           Members will be private, and setter methods will return void.
101     private-members: Members will be private, but setter methods will return ‘this‘ like usual.
102     nocamel:         Do not use CamelCase field accessors with beans.
103     fullcamel:       Convert underscored_accessor_or_service_names to camelCase.
104     android:         Generated structures are Parcelable.
105     android_legacy:  Do not use java.io.IOException(throwable) (available for Android 2.3 and above).
106     option_type:     Wrap optional fields in an Option type.
107     java5:           Generate Java 1.5 compliant code (includes android_legacy flag).
108     reuse-objects:   Data objects will not be allocated, but existing instances will be used (read and write).
109     sorted_containers:
110                      Use TreeSet/TreeMap instead of HashSet/HashMap as a implementation of set/map.
111     generated_annotations=[undated|suppress]:
112                      undated: suppress the date at @Generated annotations
113                      suppress: suppress @Generated annotations entirely
114   javame (Java ME):
115   js (Javascript):
116     jquery:          Generate jQuery compatible code.
117     node:            Generate node.js compatible code.
118     ts:              Generate TypeScript definition files.
119   json (JSON):
120     merge:           Generate output with included files merged
121   lua (Lua):
122     omit_requires:   Suppress generation of require ‘somefile‘.
123   ocaml (OCaml):
124   perl (Perl):
125   php (PHP):
126     inlined:         Generate PHP inlined files
127     server:          Generate PHP server stubs
128     oop:             Generate PHP with object oriented subclasses
129     rest:            Generate PHP REST processors
130     nsglobal=NAME:   Set global namespace
131     validate:        Generate PHP validator methods
132     json:            Generate JsonSerializable classes (requires PHP >= 5.4)
133   py (Python):
134     twisted:         Generate Twisted-friendly RPC services.
135     tornado:         Generate code for use with Tornado.
136     no_utf8strings:  Do not Encode/decode strings using utf8 in the generated code. Basically no effect for Python 3.
137     coding=CODING:   Add file encoding declare in generated file.
138     slots:           Generate code using slots for instance members.
139     dynamic:         Generate dynamic code, less code generated but slower.
140     dynbase=CLS      Derive generated classes from class CLS instead of TBase.
141     dynfrozen=CLS    Derive generated immutable classes from class CLS instead of TFrozenBase.
142     dynexc=CLS       Derive generated exceptions from CLS instead of TExceptionBase.
143     dynimport=‘from foo.bar import CLS‘
144                      Add an import line to generated code to find the dynbase class.
145     package_prefix=‘top.package.‘
146                      Package prefix for generated files.
147     old_style:       Deprecated. Generate old-style classes.
148   rb (Ruby):
149     rubygems:        Add a "require ‘rubygems‘" line to the top of each generated file.
150     namespaced:      Generate files in idiomatic namespaced directories.
151   st (Smalltalk):
152   swift (Swift):
153     log_unexpected:  Log every time an unexpected field ID or type is encountered.
154     debug_descriptions:
155                      Allow use of debugDescription so the app can add description via a cateogory/extension
156     async_clients:   Generate clients which invoke asynchronously via block syntax.
157     promise_kit:     Generate clients which invoke asynchronously via promises.
158   xml (XML):
159     merge:           Generate output with included files merged
160     no_default_ns:   Omit default xmlns and add idl: prefix to all elements
161     no_namespaces:   Do not add namespace definitions to the XML model
162   xsd (XSD):

实践
平常使用PHP开发,所以使用PHP实践下,对它有更深入的了解,一般服端开发使用编译型的语言,执行效率更高,以实现简单的NoSQL功能为例子(源码里有各种语言的实现例子)。
1 接口定义(nosql.thrift)

 1/*
 3  * thrift简单示例 模仿thrift源码教程
 4  * nosql数据库简单实现
 5  */
 6
 7 #由wadeyu创建 wadeyu.cnblogs.com
 8
 9 /**
10  * 命名空间
11  */
12 namespace cpp NoSql
13 namespace java NoSql
14 namespace php NoSql
15
16 /**
17  * 异常:无效参数
18  */
19 exception InvalidParametorException{
20 }
21
22 /**
23  * 定义服务
24  */
25 service NoSqlService{
26     /**
27      * 获取key的值
28      */
29     string get(1:string key) throws (1:InvalidParametorException ex),
30
31     /**
32      * 设置值
33      */
34     bool set_(1:string key, 2:string value) throws (1:InvalidParametorException ex),
35
36     /**
37      * 自增
38      */
39     i32 incr(1:string key) throws (1:InvalidParametorException ex),
40 }

2 编译(生成服端代码)

1 [[email protected] thriftdemo]$ thrift --gen php:server -out ./server ./meta/nosql.thrift

3 编写服端启动代码

 1 <?php
 2 /*
 3  * php简单服端脚本
 4  */
 5
 6 #author by wadeyu: wadeyu.cnblogs.com
 7
 8 define(‘BASE_DIR‘,dirname(__FILE__) . ‘/‘);
 9 define(‘VENDOR_DIR‘,BASE_DIR.‘vendor/‘);
10
11 use Server\NoSqlHandler;
12 use NoSql\NoSqlServiceProcessor;
13 use Thrift\Factory\TBinaryProtocolFactory;
14 use Thrift\Factory\TTransportFactory;
15 use Thrift\Server\TServerSocket;
16 use Thrift\Server\TSimpleServer;
17
18 $loader = include_once VENDOR_DIR.‘autoload.php‘;
19 $loader->addPsr4(‘Server\\‘,BASE_DIR.‘server/‘);
20
21 include_once BASE_DIR.‘server/NoSql/NoSqlService.php‘;
22 include_once BASE_DIR.‘server/NoSql/Types.php‘;
23
24 $serverTransport = new TServerSocket(‘localhost‘,9090);
25 $clientTransport = new TTransportFactory;
26 $binaryProtocol  = new TBinaryProtocolFactory;
27 $nosqlProcessor  = new NoSqlServiceProcessor( new NoSqlHandler );
28 $simpleServer    = new TSimpleServer(
29     $nosqlProcessor,
30     $serverTransport,
31     $clientTransport,
32     $clientTransport,
33     $binaryProtocol,
34     $binaryProtocol
35 );
36 echo "start listening:localhost:9090 \n";
37 $simpleServer->serve();

4 启动服务

[[email protected] thriftdemo]$ php phpserver.php
start listening:localhost:9090

5 编译(生成客户端代码)

[[email protected] thriftdemo]$ thrift --gen php -out ./client ./meta/nosql.thrift

6 客户端接口调用

 1 <?php
 2 /*
 3  * php简单客户端脚本
 4  */
 5
 6 #author by wadeyu: wadeyu.cnblogs.com
 7
 8 define(‘BASE_DIR‘,dirname(__FILE__) . ‘/‘);
 9 define(‘VENDOR_DIR‘,BASE_DIR.‘vendor/‘);
10
11 use Thrift\Protocol\TBinaryProtocol;
12 use Thrift\Transport\TSocket;
13 use NoSql\NoSqlServiceClient;
14
15 $loader = include_once VENDOR_DIR.‘autoload.php‘;
16
17 include_once BASE_DIR.‘client/NoSql/NoSqlService.php‘;
18 include_once BASE_DIR.‘client/NoSql/Types.php‘;
19
20 $transport = new TSocket(‘localhost‘,9090);
21 $protocol  = new TBinaryProtocol($transport);
22 $service   = new NoSqlServiceClient($protocol);
23 $startTime = microtime(true);
24 try{
25     $transport->open();
26     $key1 = ‘test1‘;
27     $ret = $service->get($key1);
28     var_dump($ret);
29     $ret = $service->set_($key1,‘test1‘);
30     var_dump($ret);
31     $key2 = ‘test2‘;
32     $ret = $service->incr($key2);
33     var_dump($ret);
34     $transport->close();
35 }catch(Exception $ex){
36     throw $ex;
37 }
38 var_dump(‘cost:‘.(microtime(true)-$startTime));
1 [[email protected] thriftdemo]$ php phpclient.php
2 string(4) "NULL"
3 bool(true)
4 int(1)
5 string(21) "cost:0.22478580474854"

示例源码下载
https://github.com/wadeyu/thriftdemo/archive/master.zip

后记
纸上得来终觉浅,得知此事要躬行。其实很早就开始写这篇文章了,自己很懒,拖了几个星期才完成,以后要改掉这个毛病了。

参考资料
【1】thrift官方文档

http://thrift.apache.org/docs/
【2】thrift安装

http://thrift.apache.org/docs/install/
【3】thrift IDL规范

http://thrift.apache.org/docs/idl

http://thrift.apache.org/docs/types
【4】thrift实现论文

http://thrift.apache.org/static/files/thrift-20070401.pdf

时间: 2024-10-20 17:24:21

RPC服务框架探索之Thrift的相关文章

Thrift 个人实战--Thrift RPC服务框架日志的优化

前言: Thrift作为Facebook开源的RPC框架, 通过IDL中间语言, 并借助代码生成引擎生成各种主流语言的rpc框架服务端/客户端代码. 不过Thrift的实现, 简单使用离实际生产环境还是有一定距离, 本系列将对Thrift作代码解读和框架扩充, 使得它更加贴近生产环境. 本文讲述RPC服务框架中, 日志的重要性, 以及logid的引入. 日志不仅包含丰富的数据(就看是否会挖掘), 而且还是线上服务问题追踪和排查错误最好的方式. 日志级别 采用大家喜闻乐见的log4j作为该RPC服

rpc服务框架thrift介绍

rpc服务框架目前主要有 thrift, grpc, dubbo, HSF等 这里主要介绍thrift框架 git地址  :https://github.com/apache/thrift/tree/0.9.1 1. 接口定义 tutorial.thrift include "shared.thrift" /** * Thrift files can namespace, package, or prefix their output in various * target langu

基于netty轻量的高性能分布式RPC服务框架forest&lt;下篇&gt;

基于netty轻量的高性能分布式RPC服务框架forest<上篇> 文章已经简单介绍了forest的快速入门,本文旨在介绍forest用户指南. 基本介绍 Forest是一套基于java开发的RPC框架,除了常规的点对点调用外,Motan还提供服务治理功能,包括服务节点的自动发现.摘除.高可用和负载均衡等. 架构概述 Forest中分为服务提供方(RPC Server),服务调用方(RPC Client)和服务注册中心(Registry)三个角色. Server提供服务,向Registry注册

RSF 分布式 RPC 服务框架的分层设计

RSF 是个什么东西? 一个高可用.高性能.轻量级的分布式服务框架.支持容灾.负载均衡.集群.一个典型的应用场景是,将同一个服务部署在多个Server上提供 request.response 消息通知.使用RSF可以点对点调用,也可以分布式调用.部署方式上:可以搭配注册中心,也可以独立使用. 渊源 RSF 的核心思想参考了淘宝HSF.Dubbo 等优秀框架.功能上大体相似,但是实现逻辑完全不同.因此没有什么历史包袱.总的来说对比淘宝HSF少了历史包袱,相比Dubbo更加轻量化.而且还支持了虚拟机

唯品会RPC服务框架与容器化演进--转

原文地址:http://mp.weixin.qq.com/s?__biz=MzAwMDU1MTE1OQ==&mid=405781868&idx=1&sn=cbb10d37e25c76a1845f593a222da3c9&scene=0#wechat_redirect 编者按:本文是邱戈川在 3 月 27 日数人云"百万并发"活动的演讲,授权「高可用架构」首发.转载请注明来自高可用架构公众号「ArchNotes」.   邱戈川,唯品会分布式架构平台产品经理

基于开源Dubbo分布式RPC服务框架的部署整合

一.前言 Dubbo 作为SOA服务化治理方案的核心框架,用于提高业务逻辑的复用.整合.集中管理,具有极高的可靠性(HA)和伸缩性,被应用于阿里巴巴各成员站点,同时在包括JD.当当在内的众多互联网项目中有着广泛应用.dubbo 通过高性能 RPC 实现服务的输出和输入功能,框架基于 Spring Framework 进行无缝集成,使用过程中基本看不到 Dubbo API的直接调用,Dubbo服务支持RMI.Hessian.Dubbo.WebService等众多通信协议,同时提供了对服务的监控和管

【Rpc】基于开源Dubbo分布式RPC服务框架的部署整合

一.前言 Dubbo 作为SOA服务化治理方案的核心框架,用于提高业务逻辑的复用.整合.集中管理,具有极高的可靠性(HA)和伸缩性,被应用于阿里巴巴各成员站点,同时在包括JD.当当在内的众多互联网项目中有着广泛应用.dubbo 通过高性能 RPC 实现服务的输出和输入功能,框架基于 Spring Framework 进行无缝集成,使用过程中基本看不到 Dubbo API的直接调用,Dubbo服务支持RMI.Hessian.Dubbo.WebService等众多通信协议,同时提供了对服务的监控和管

RPC 服务框架 Dubbo 将正式得到官方维护与支持

近日,Dubbo 项目官网更新了一则公告: 在项目 GitHub 主页的 issue 中,也有阿里巴巴的工程师确认了这一消息. 看来,Dubbo 确实重新开始得到官方的维护了.不过,目前还没发现项目的最新规划图,所以暂不了解 Dubbo 后续的发展方向如何.我们将持续保持关注. Dubbo |?d?b??| 是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案. 其核心部分包含: 远程通讯: 提供对多种基于长连接的NIO框架抽象封装,包括多种线程模型,序

RPC服务框架Dubbo学习

RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议.RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据.在OSI网络通信模型中,RPC跨越了传输层和应用层.RPC使得开发包括网络分布式多程序在内的应用程序更加容易. Dubbo是阿里巴巴的一个开源RPC框架,目前公司里全网都在用,官网的介绍和文档十分详细. https://github.com/aliba