koala 学习笔记
相关技术栈:linux、golang
编写IDL
在业务项目目录下创建helloworld目录,进入该目录,然后创建编辑hello.thrift,该文件用来生成基本框架。输入以下内容:
1 2 3 4 5 6 7
| struct Result { 1: string response, }
service HelloService { Result HelloWorld(1:string name); }
|
生成框架代码
键入如下命令生成框架代码,请下载最新版本的thrift工具
1
| /path/to/soa_tools/thrift --gen go --packagePath micode.be.xiaomi.com/systech/helloworld hello.thrift
|
编译执行
执行 ./build.sh 进行编译,编译成功后,生成的程序在bin目录下。
自动构建
启动自动构建程序(auto_build.sh),自动构建程序会实时检测项目目录下源码的是否变更,如果有变更将自动进行编译、重启程序。
了解框架代码结构
生成的框架代码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| . ├── auto_build.sh //自动构建脚本 ├── bin │ └── HelloService ├── build.sh //编译脚本 ├── config │ ├── scm_config.ini │ ├── scm_config.ini.online.env //线上配置 │ └── scm_config.ini.test.env //测试环境配置 ├── hello.thrift //接口描述文件 ├── package.sh //编译打包脚本,使用请参考:http://mis.n.mi.com/koala/publish/package.html ├── README ├── run //启动脚本 ├── run.sh //带supervise的启动脚本 ├── framework //框架基础代码(无需更改) │ └── app │ ├── app.go │ ├── config.go │ ├── generate.go │ ├── global.go │ ├── initDb.go │ ├── initRabbitmq.go │ ├── initRedis.go │ ├── initRedisMock.go │ ├── initSqlMock.go │ ├── manager.go │ ├── plugin.go │ ├── register.go │ ├── rpc.go │ └── user_config.go ├── hello //网络相关基础代码,无需更改 │ ├── constants.go │ ├── helloservice.go │ ├── helloservice_host_wrapper.go │ ├── hello_service-remote │ │ └── hello_service-remote.go │ ├── helloservice_wrapper.go │ └── ttypes.go ├── main │ ├── HelloService.go │ ├── HelloWorld_handler.go //HelloWorld的入口文件,需要业务实现 │ ├── hook.go //框架各个阶段的回调接口,可以实现自定义功能 │ └── main.go └── model //业务model层 └── supervise └── supervise └── glide.yaml // 依赖说明文件 └── glide.lock // 依赖版本锁文件
|
对于 thrift IDL 中定义的每一个接口,会在 main 目录单独一个代码文件,并在接口名后面加上_handler后缀。 例如,对于 hello.thrift 定义的 HelloWorld 接口,生成的实现文件为 main/HelloWorld_handler.go。
实现 HelloWorld 接口
打开 main/HelloWorld_handler.go文件,框架生成的源代码如下:
1 2 3 4 5 6 7 8 9 10 11 12
| package main
import ( "micode.be.xiaomi.com/systech/helloworld/hello" "micode.be.xiaomi.com/systech/soa/context" )
func (p *HelloServiceHandler) HelloWorld(ctx *context.XContext, name string) (r *hello.Result_, errRet error) {
return }
|
该接口返回一个hello.Result结构,以及若有错误产生,返回一个errRet。
我们记得,hello.Result_结构体的定义如下:
1 2 3
| type Result_ struct { Response string `thrift:"response,1" json:"response"` }
|
当处理正常时,返回一个Response字符串。因此,我们的HelloWorld接口非常简单,实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| package main
import ( "micode.be.xiaomi.com/systech/helloworld/hello" "micode.be.xiaomi.com/systech/soa/context" "fmt" )
func (p *HelloServiceHandler) HelloWorld(context *context.XContext, name string) (r *hello.Result_, err error) {
r = &hello.Result_{} r.Response = fmt.Sprintf("hello world,%s", name)
return }
|
配置组名和服务名
启动服务之前必须先在 config/scm_config.ini 中配置组名和服务名。
打开 config/scm_config.ini,在group和service两个字段,填入相应的信息。如下所示:
1 2 3 4 5 6 7 8 9
| ;基础配置 [xbase] config_type=local config_addr=http://etcd.test.mi.com ;项目所在的小组名,一定要配置,不配置将会panic,详情请参见mis.n.mi.com group=systech ;项目的服务名,一定要配置,不配置将会panic,详情请参见mis.n.mi.com service=hello ....
|
(注)服务名:服务开发完了之后,通过SOA平台进行注册,注册服务的时候会分配一个唯一的服务名。
启动服务HelloService
使用如下命令进行启动:
调用和测试
生成SDK
通过以下命令,生成Golang的SDK:
1
| /path/to/soa_tools/thrift --gen go --packagePath micode.be.xiaomi.com/your/project ./hello.thrift
|
生成的SDK在当前目录sdk/v3/目录下。
如果基于 koala v3 开发的项目需要生成 sdk 给 koala v1 或 v2 的项目使用,请使用命令:
1 2
| /path/to/soa_tools/thrift --gen go --v1 ./hello.thrift /path/to/soa_tools/thrift --gen go --v2 ./hello.thrift
|
生成的 SDK 在 sdk/v1/ sdk/v2 目录下。
编写测试代码
golang版rpc包括两种调用方式:
- 通过IP调用:一般在开发过程,为了简化调用流程,我们可以直接指定后端服务ip和port进行调用。 在项目目录下(位置任意,只要import了…/helloworld/sdk/v3/hello包即可)新建main.go文件,编辑以下代码:
1 2 3 4 5 6 7 8 9 10 11
| package main
import ( "fmt" "micode.be.xiaomi.com/systech/helloworld/sdk/v3/hello" )
func main() { client:=hello.NewHelloServiceClientHostWrapper("127.0.0.1",12508,"xxx") fmt.Println(client.HelloWorld("xiaoming")) }
|
由于我们代码依赖koala基础库,为了简化编译步骤,我们采用脚本进行编译运行,在当前目录下 打开run.sh,输入以下内容:
1 2 3 4 5
| #!/bin/bash
curdir=`pwd` glide init && glide up go run $curdir/main.go
|
运行run.sh,即可看到程序运行结果。
- 通过服务名调用:在测试或线上环境中,我们需要在SOA平台上进行订阅xm_ip_service,然后通过服务名进行调用。 调用代码如下,保存为main.go:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| package main
import( "fmt" "micode.be.xiaomi.com/your/project/sdk/v3/ip" "micode.be.xiaomi.com/systech/soa/xrpc" "micode.be.xiaomi.com/systech/soa/thrift" )
func init() {
1. 测试环境为http: 1. 线上环境为http: _, err := xrpc.NewXRpcDefault("misite", "xm_ip_service_client", "http://etcd.test.mi.com") if (err != nil) { fmt.Println(err) } }
func main() {
context := thrift.NewXContext("xm_ip_service_client", 1000, 0)
client := ip.NewIPServiceClientWrapper2("xm_ip_service", context)
ipList := make([]string, 2) ipList = append(ipList, "100.200.39.4") fmt.Println(client.QueryGeoInfoByIP(ipList)) }
|
运行测试程序
正常情况下,将会返回类似如下结果:
1
| Result_({Response:hello world,liuxing1}) <nil>
|