七叶笔记 » golang编程 » Apache Thrift Golang 实践篇

Apache Thrift Golang 实践篇

题外话

  首先对新东西在理论上宏观了解,随后抓紧时间实践一波,对初始形成的认识做一个切身体会和验证。然后再去关注理论细节,与实践中的具体步骤对号入座,明白当初为什么要这样做。最后在后续的实践中,持续有意识地去思考自己每一个“行为”所对应的理论支撑,不同的阶段会有不同的收获。总之理论和实践相辅相成,“理论指导实践,实践验证理论”,这个经典的螺旋上升运动是科学的。上来就直奔细枝末节会耗费大量精力且效果一般,大家不会通篇背诵新华字典之后再去写文章,一点点学习体会形成文字和大家分享~

了解 Thrift

Thrift 是什么

官方描述:The Apache Thrift software framework, for scalable cross-language services development, combines a software stack with a code generation engine to build services that work efficiently and seamlessly between C++, Java , Python , PHP, Ruby , Erlang , Perl, Haskell , C#, Cocoa , JavaScript, Node.js, Smalltalk, OCaml and Delphi and other languages.

提炼为以下几点:

  • 服务开发框架
  • 集成了代码生成引擎
  • 支持多语言开发

了解了定义描述,产生两个问题,留在学习过程中解答:

  1. 这套框架开发什么服务?
  2. 代码生成引擎生成什么?如何生成?

Thrift 做什么

简单回答第一个问题:

Thrift 是一个 RPC 服务框架,其实和众多 RPC 框架一样,Thrift 能够支持 RPC 服务的快速落地,同时生成配套的通信双方。

天下所有框架的目的是一样的,将一些繁琐的东西提前处理好,让使用者不必被底层细节所累。但是我们的学习还是要尽可能深入的~


Thrift 实践

Thrift 编译器安装

安装手册:

thrift 编译器是框架关键工具,由 C++ 开发支持多系统移植,但系统中必须提前安装依赖。

configure 脚本是源代码在不同操作系统上编译的关键。在 make 之前,configure 会检查自己所依赖的库,所以大可以先执行一下 ./configure 命令,检查一下系统是否符合安装要求,根据输出进行响应处理。

脚本执行成功之后在 –prefix 指定目录生成产出内容,一般是 makefile 文件,用于执行 make 命令编译。编译结束,产出安装文件,执行 make install 进行安装

收获:
通过 源码 编译过程可以发现,Thrift 之所以能够支持多种语言,是因为其提前内置了各语言库。由此当我们在 configure 过程中受阻,可以根据输出判断其对应语言是否必需,若为无关语言我们可以在命令参数中去掉相应安装,有的放矢。

 # 命令
./configure --with-xxx --without-xxx

# 相关 code 片段 以ruby为例
# thrift当前支持如下语言
if test "$enable_libs" = "no"; then
  have_libs="no"
  with_cpp="no"
  with_c_glib="no"
  with_cl="no"
  with_java="no"
  with_python="no"
  with_py3="no"
  with_ruby="no"
  with_haxe="no"
  with_netstd="no"
  with_perl="no"
  with_php="no"
  with_php_extension="no"
  with_dart="no"
  with_erlang="no"
  with_go="no"
  with_d="no"
  with_ nodejs ="no"
  with_nodets="no"
  with_lua="no"
  with_rs="no"
  with_ swift ="no"
fi

# 所有语言的判断逻辑都是相同的
AX_THRIFT_LIB(ruby, [Ruby], yes)
have_ruby=no
if test "$with_ruby" = "yes"; then
  AC_PATH_PROG([RUBY], [ruby])
  AC_PATH_PROG([BUNDLER], [bundle])
  if test "x$RUBY" != "x" -a "x$BUNDLER" != "x"; then
    have_ruby="yes"
  fi
fi
AM_CONDITIONAL(WITH_RUBY, [test "$have_ruby" = "yes"])
AM_CONDITIONAL(HAVE_BUNDLER, [test "x$BUNDLER" != "x"])

  

Thrift IDL

官网描述:The Thrift interface definition language ( IDL ) allows for the definition of Thrift Types. A Thrift IDL file is processed by the Thrift code generator to produce code for the various target languages to support the defined Structs and services in the IDL file.
链接:

关键信息:

  • 由 Thrift Type 定义,官方说明
  • 由 Thrift 代码生成器处理生成指定语言代码

Thrift Type:

  • 基础类型

布尔 类型 bool

字节类型 byte

有符号整形 i16, i32, i64

双精度浮点型 double

字符串 类型 string utf-8

  • 结构体 struct
  • 容器:容器中元素同样Thrift Type

列表 list

无序不重集合 set

映射表 map

  • 异常 exception :继承自目标语言自带异常
  • 服务 service:定义 RPC 服务端,内部包含一系列对外服务接口,
  • void

示例:

个人觉得这个示例文件更加直观

 /*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
# Thrift Tutorial
# Mark Slee (mcslee@facebook.com)
#
# This file aims to teach you how to use Thrift, in a .thrift file. Neato. The
# first thing to notice is that .thrift files support standard shell comments.
# This lets you make your thrift file executable and  include  your Thrift build
# step on the top line. And you can place comments like this anywhere you like.
#
# Before running this file, you will need to have installed the thrift compiler
# into /usr/local/bin.

/**
 * The first thing to know about are types. The available types in Thrift are:
 *
 *  bool         Boolean , one byte
 *  i8 (byte)   Signed 8-bit  integer 
 *  i16         Signed 16-bit integer
 *  i32         Signed 32-bit integer
 *  i64         Signed 64-bit integer
 *  double      64-bit floating point value
 *  string      String
 *  binary      Blob (byte array)
 *  map<t1,t2>  Map from one type to another
 *  list<t1>    Ordered list of one type
 *  set<t1>     Set of unique elements of one type
 *
 * Did you also notice that Thrift supports C style comments?
 */
// Just in case you were wondering... yes. We support simple C comments too.

/**
 * Thrift files can reference other Thrift files to include common struct
 * and service definitions. These are found using the current path, or by
 * searching relative to any paths specified with the -I compiler flag.
 *
 * Included objects are accessed using the name of the .thrift file as a
 * prefix. i.e. shared.SharedObject
 */include "shared.thrift"

/**
 * Thrift files can namespace, package, or prefix their output in various
 * target languages.
 */
namespace cl tutorial
namespace cpp tutorial
namespace d tutorial
namespace dart tutorial
namespace java tutorial
namespace php tutorial
namespace perl tutorial
namespace haxe tutorial
namespace netstd tutorial

/**
 * Thrift lets you do typedefs to get pretty names for your types. Standard
 * C style here.
 */typedef i32 MyInteger

/**
 * Thrift also lets you  define  constants for use across languages. Complex
 * types and structs are specified using  JSON  notation.
 */const i32 INT32CONSTANT = 9853
const map<string,string> MAPCONSTANT = {'hello':'world', 'goodnight':'moon'}

/**
 * You can define enums, which are just 32 bit integers. Values are optional
 * and start at 1 if not supplied, C style again.
 */ enum  Operation {
  ADD = 1,
  SUBTRACT = 2,
  MULTIPLY = 3,
  DIVIDE = 4
}

/**
 * Structs are the basic complex data structures. They are comprised of fields
 * which each have an integer identifier, a type, a symbolic name, and an
 * optional default value.
 *
 * Fields can be declared "optional", which ensures they will not be included
 * in the serialized output if they aren't set.  Note that this requires some
 * manual management in some languages.
 */struct Work {
  1:  i3 2 num1 = 0,
  2: i32 num2,
  3: Operation op,
  4: optional string comment,
}

/**
 * Structs can also be exceptions, if they are nasty.
 */exception InvalidOperation {
  1: i32 whatOp,
  2: string why
}

/**
 * Ahh, now onto the cool part, defining a service. Services just need a name
 * and can optionally inherit from another service using the extends keyword.
 */service Calculator extends shared.SharedService {

  /**
   * A method definition looks like C code. It has a return type, arguments,
   * and optionally a list of exceptions that it may throw. Note that argument
   * lists and exception lists are specified using the exact same syntax as
   * field lists in struct or exception definitions.
   */
   void ping(),

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

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

   /**
    * This method has a oneway modifier. That means the client only makes
    * a  request  and does not listen for any response at all. Oneway methods
    * must be void.
    */   oneway void zip()

}

/**
 * That just about covers the basics. Take a look in the test/ folder for more
 * detailed examples. After you run this file, your generated code shows up
 * in folders with names gen-<language>. The generated code isn't too scary
 * to look at. It even has pretty indentation.
 */
  

Thrift RPC 生成

Thrift 编译器生成实现 IDL 定义的功能齐全的客户端和服务器存根(stub)

Thrift 命令:

 Usage: thrift [options] file
Options:
  -version    Print the compiler version
  -o dir      Set the output directory for gen-* packages
               (default: current directory)
  -out dir    Set the ouput location for generated files.
               (no gen-* folder will be created)
  -I dir      Add a directory to the list of directories
                searched for include directives
  -nowarn     Suppress all compiler warnings (BAD!)
  -strict     Strict compiler warnings on
  -v[erbose]  Verbose mode
  -r[ecurse]  Also generate included files
  -debug      Parse debug trace to stdout
  --allow-neg-keys  Allow negative field keys (Used to preserve protocol
                compatibility with older .thrift files)
  --allow-64bit-consts  Do not print warnings about using 64-bit constants
  --gen STR   Generate code with a dynamically-registered generator.
                STR has the form language[:key1=val1[,key2[,key3=val3]]].
                Keys and values are options passed to the generator.
                Many options will not require values.
  

示例: thrift -r –gen <language> <Thrift filename>

thrift -r -out gen-go –gen go:package_prefix={go_module_name}/gen-go xxx.thrift

  • -r 生成 include 文件
  • 默认输出在 gen-* 路径下
  • 使用 -o -out 选项,设置输出路径,前者默认使用当前路径,后者使用指定路径
  • –gen language:key=value,key=value ,示例中指定了包前缀
  • .thrift 文件,定义 IDL

参考资料

相关文章