使用 dubbogo-cli 工具

1. 安装

dubbogo-cli 是 Apach/dubbo-go 生态的子项目,为开发者提供便利的应用模板创建、工具安装、接口调试等功能,以提高用户的研发效率。

执行以下指令安装dubbogo-cli 至 $GOPATH/bin

  1. go install github.com/dubbogo/dubbogo-cli@latest

2. 功能概览

dubbogo-cli 支持以下能力

  • 应用模板创建

    1. dubbogo-cli newApp .

    在当前目录下创建应用模板

  • Demo 创建

    1. dubbogo-cli newDemo .

    在当前目录下创建 RPC 示例,包含一个客户端和一个服务端

  • 编译、调试工具安装

    1. dubbogo-cli install all

    一键安装以下等工具至 $GOPATH/bin

    • protoc-gen-go-triple

      用于 triple 协议接口编译

    • imports-formatter

      用于整理代码 import 块。

      import-formatte README

  • 查看 dubbo-go 应用注册信息

    • 查看 Zookeeper 上面的注册信息, 获取接口及方法列表

      1. $ dubbogo-cli show --r zookeeper --h 127.0.0.1:2181
      2. interface: com.dubbogo.pixiu.UserService
      3. methods: [CreateUser,GetUserByCode,GetUserByName,GetUserByNameAndAge,GetUserTimeout,UpdateUser,UpdateUserByName]
    • 查看 Nacos 上面的注册信息 【功能开发中】

    • 查看 Istio 的注册信息【功能开发中】

  • 调试 Dubbo 协议接口

  • 调试 Triple 协议接口

3. 功能详解

3.1 Demo 应用介绍

3.1.1 Demo 创建

  1. dubbogo-cli newDemo .

在当前目录下创建Demo, 包含客户端和服务端,该 Demo 展示了基于一套接口,完成一次 RPC 调用。

该Demo 使用直连模式,无需依赖注册中心,server端暴露服务到本地20000端口,客户端发起调用。

  1. .
  2. ├── api
  3. ├── samples_api.pb.go
  4. ├── samples_api.proto
  5. └── samples_api_triple.pb.go
  6. ├── go-client
  7. ├── cmd
  8. └── client.go
  9. └── conf
  10. └── dubbogo.yaml
  11. ├── go-server
  12. ├── cmd
  13. └── server.go
  14. └── conf
  15. └── dubbogo.yaml
  16. └── go.mod

3.1.2 运行Demo

开启服务端

  1. $ cd go-server/cmd
  2. $ go run .

另一个终端开启客户端

  1. $ go mod tidy
  2. $ cd go-client/cmd
  3. $ go run .

可看到打印日志

  1. INFO cmd/client.go:49 client response result: name:"Hello laurence" id:"12345" age:21

3.2 应用模板介绍

3.2.1 应用模板创建

  1. dubbogo-cli newApp .

在当前目录下创建应用模板:

  1. .
  2. ├── Makefile
  3. ├── api
  4. ├── api.pb.go
  5. ├── api.proto
  6. └── api_triple.pb.go
  7. ├── build
  8. └── Dockerfile
  9. ├── chart
  10. ├── app
  11. ├── Chart.yaml
  12. ├── templates
  13. ├── _helpers.tpl
  14. ├── deployment.yaml
  15. ├── service.yaml
  16. └── serviceaccount.yaml
  17. └── values.yaml
  18. └── nacos_env
  19. ├── Chart.yaml
  20. ├── templates
  21. ├── _helpers.tpl
  22. ├── deployment.yaml
  23. └── service.yaml
  24. └── values.yaml
  25. ├── cmd
  26. └── app.go
  27. ├── conf
  28. └── dubbogo.yaml
  29. ├── go.mod
  30. ├── go.sum
  31. └── pkg
  32. └── service
  33. └── service.go

3.2.2 应用模板介绍

生成项目包括几个目录:

  • api:放置接口文件:proto文件和生成的.pb.go文件

  • build:放置镜像构建相关文件

  • chart:放置发布用 chart 仓库、基础环境chart 仓库:nacos、mesh(开发中)

  • cmd:程序入口

  • conf:框架配置

  • pkg/service:RPC 服务实现

  • Makefile:

    • 镜像、helm部署名:
      • IMAGE = $(your_repo)/$(namespace)/$(image_name) TAG = 1.0.0
  • HELM_INSTALL_NAME = dubbo-go-app,helm 安装名,用于 helm install/uninstall 命令。

    • 提供脚本,例如:
      • make build # 打包镜像并推送
  • make buildx-publish # arm架构本地打包amd64镜像并推送,依赖 docker buildx

  • make deploy # 通过 helm 发布应用

  • make remove # 删除已经发布的 helm 应用

  • make proto-gen # api下生成 pb.go 文件

使用应用模板的开发流程

依赖环境:make、go、helm、kubectl、docker

  1. 通过 dubbogo-cli 生成模板
  2. 修改api/api.proto
  3. make proto-gen
  4. 开发接口
  5. 修改 makefile 内 IMAGE 镜像名和 HELM_INSTALL_NAME 发布名
  6. 打镜像并推送
  7. 修改chart/app/values 内与部署相关的value配置, 重点关注镜像部分。
  1. image:
  2. repository: $(your_repo)/$(namespace)/$(image_name)
  3. pullPolicy: Always
  4. tag: "1.0.0"
  1. make deploy, 使用 helm 发布应用。

3.3 以 gRPC 协议调试 dubbo-go 应用

3.3.1 简介

grpc_cli 工具是 gRPC 生态用于调试服务的工具,在 server 开启反射服务的前提下,可以获取到服务的 proto 文件、服务名、方法名、参数列表,以及发起 gRPC 调用。

Triple 协议兼容 gRPC 生态,并默认开启 gRPC 反射服务,因此可以直接使用 grpc_cli 调试 triple 服务。

3.3.2 安装grpc_cli

后续将由 dubbogo-cli 安装,目前需要用户手动安装

参考grpc_cli 文档

3.3.3 使用 grpc_cli 对 Triple 服务进行调试

  1. 查看 triple 服务的接口定义
  1. $ grpc_cli ls localhost:20001 -l
  2. filename: helloworld.proto
  3. package: org.apache.dubbo.quickstart.samples;
  4. service UserProvider {
  5. rpc SayHello(org.apache.dubbo.quickstart.samples.HelloRequest) returns (org.apache.dubbo.quickstart.samples.User) {}
  6. rpc SayHelloStream(stream org.apache.dubbo.quickstart.samples.HelloRequest) returns (stream org.apache.dubbo.quickstart.samples.User) {}
  7. }
  1. 查看请求参数类型

例如开发者期望测试上述端口的 SayHello 方法,尝试获取HelloRequest的具体定义,需要执行r如下指令,可查看到对应参数的定义。

  1. $ grpc_cli type localhost:20001 org.apache.dubbo.quickstart.samples.HelloRequest
  2. message HelloRequest {
  3. string name = 1 [json_name = "name"];
  4. }
  1. 请求接口

已经知道了请求参数的具体类型,可以发起调用来测试对应服务。查看返回值是否符合预期。

  1. $ grpc_cli call localhost:20001 SayHello "name: 'laurence'"
  2. connecting to localhost:20001
  3. name: "Hello laurence"
  4. id: "12345"
  5. age: 21
  6. Received trailing metadata from server:
  7. accept-encoding : identity,gzip
  8. adaptive-service.inflight : 0
  9. adaptive-service.remaining : 50
  10. grpc-accept-encoding : identity,deflate,gzip
  11. Rpc succeeded with OK status

3.4 以 Dubbo 协议调试dubbo-go 应用

3.4.1 开启 Dubbo 服务端

示例:user.go:

  1. func (u *UserProvider) GetUser(ctx context.Context, userStruct *CallUserStruct) (*User, error) {
  2. fmt.Printf("=======================\nreq:%#v\n", userStruct)
  3. rsp := User{"A002", "Alex Stocks", 18, userStruct.SubInfo}
  4. fmt.Printf("=======================\nrsp:%#v\n", rsp)
  5. return &rsp, nil
  6. }

服务端开启一个服务,名为GetUser,传入一个CallUserStruct的参数,返回一个User参数 CallUserStruct参数定义:

  1. type CallUserStruct struct {
  2. ID string
  3. Male bool
  4. SubInfo SubInfo // 嵌套子结构
  5. }
  6. func (cs CallUserStruct) JavaClassName() string {
  7. return "com.ikurento.user.CallUserStruct"
  8. }
  9. type SubInfo struct {
  10. SubID string
  11. SubMale bool
  12. SubAge int
  13. }
  14. func (s SubInfo) JavaClassName() string {
  15. return "com.ikurento.user.SubInfo"
  16. }

User结构定义:

  1. type User struct {
  2. Id string
  3. Name string
  4. Age int32
  5. SubInfo SubInfo // 嵌套上述子结构SubInfo
  6. }
  7. func (u *User) JavaClassName() string {
  8. return "com.ikurento.user.User"
  9. }

开启服务:

  1. cd server`
  2. `source builddev.sh`
  3. `go run .

3.4.2 定义请求体 (适配于序列化协议)

请求体定义为json文件,约定键值均为string 键对应go语言struct字段名例如”ID”、“Name” ,值对应”type@val” 其中type支持string int bool time,val使用string 来初始化,如果只填写type则初始化为零值。 约定每个struct必须有JavaClassName字段,务必与server端严格对应

见userCall.json:

  1. {
  2. "ID": "string@A000",
  3. "Male": "bool@true",
  4. "SubInfo": {
  5. "SubID": "string@A001",
  6. "SubMale": "bool@false",
  7. "SubAge": "int@18",
  8. "JavaClassName":"string@com.ikurento.user.SubInfo"
  9. },
  10. "JavaClassName": "string@com.ikurento.user.CallUserStruct"
  11. }

userCall.json将参数CallUserStruct的结构及子结构SubInfo都定义了出来,并且给请求参数赋值。

user.json 同理,作为返回值不需要赋初始值,但JavaClassName字段一定与server端严格对应

  1. {
  2. "ID": "string",
  3. "Name": "string",
  4. "Age": "int",
  5. "JavaClassName": "string@com.ikurento.user.User",
  6. "SubInfo": {
  7. "SubID": "string",
  8. "SubMale": "bool",
  9. "SubAge": "int",
  10. "JavaClassName":"string@com.ikurento.user.SubInfo"
  11. }
  12. }

3.4.3 调试端口

  1. ./dubbo-go-cli -h=localhost -p=20001 -proto=dubbo -i=com.ikurento.user.UserProvider -method=GetUser -sendObj="./userCall.json" -recvObj="./user.json"

打印结果:

  1. 2020/10/26 20:47:45 Created pkg:
  2. 2020/10/26 20:47:45 &{ID:A000 Male:true SubInfo:0xc00006ea20 JavaClassName:com.ikurento.user.CallUserStruct}
  3. 2020/10/26 20:47:45 SubInfo:
  4. 2020/10/26 20:47:45 &{SubID:A001 SubMale:false SubAge:18 JavaClassName:com.ikurento.user.SubInfo}
  5. 2020/10/26 20:47:45 Created pkg:
  6. 2020/10/26 20:47:45 &{ID: Name: Age:0 JavaClassName:com.ikurento.user.User SubInfo:0xc00006ec90}
  7. 2020/10/26 20:47:45 SubInfo:
  8. 2020/10/26 20:47:45 &{SubID: SubMale:false SubAge:0 JavaClassName:com.ikurento.user.SubInfo}
  9. 2020/10/26 20:47:45 connected to localhost:20001!
  10. 2020/10/26 20:47:45 try calling interface:com.ikurento.user.UserProvider.GetUser
  11. 2020/10/26 20:47:45 with protocol:dubbo
  12. 2020/10/26 20:47:45 After 3ms , Got Rsp:
  13. 2020/10/26 20:47:45 &{ID:A002 Name:Alex Stocks Age:18 JavaClassName: SubInfo:0xc0001241b0}
  14. 2020/10/26 20:47:45 SubInfo:
  15. 2020/10/26 20:47:45 &{SubID:A001 SubMale:false SubAge:18 JavaClassName:}
  1. 可看到详细的请求体赋值情况,以及返回结果和耗时。支持嵌套结构
  2. server端打印结果

=======================

req:&main.CallUserStruct{ID:”A000”, Male:true, SubInfo:main.SubInfo{SubID:”A001”, SubMale:false, SubAge:18}}

```

可见接收到了来自cli的数据

最后修改 December 16, 2022: Fix check (#1736) (97972c1)