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.
提炼为以下几点:
- 服务开发框架
- 集成了代码生成引擎
- 支持多语言开发
了解了定义描述,产生两个问题,留在学习过程中解答:
- 这套框架开发什么服务?
- 代码生成引擎生成什么?如何生成?
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.
链接:https://thrift.apache.org/docs/idl
关键信息:
- 由 Thrift Type 定义,官方说明 https://thrift.apache.org/docs/types
- 由 Thrift 代码生成器处理生成指定语言代码
Thrift Type:
- 基础类型
- 布尔类型 bool
- 字节类型 byte
- 有符号整形 i16, i32, i64
- 双精度浮点型 double
- 字符串类型 string utf-8
- 结构体 struct
- 容器:容器中元素同样Thrift Type
- 列表 list
- 无序不重集合 set
- 映射表 map
- 异常 exception:继承自目标语言自带异常
- 服务 service:定义 RPC 服务端
- 内部包含一系列对外服务接口,
- void
示例:
https://github.com/apache/thrift/blob/master/tutorial/tutorial.thrift
个人觉得这个示例文件更加直观
/*
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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: i32 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 xxxxx.thrift
-r
生成 include 文件- 默认输出在
gen-*
路径下 - 使用
-o
-out
选项,设置输出路径,前者默认使用当前路径,后者使用指定路径 --gen language:key=value,key=value
,示例中指定了包前缀- .thrift 文件,定义 IDL