使用 dubbogo-cli 工具

1. 安装

dubbogo-cli 是 Apache/dubbo-go 生态系统的一个子项目,它为开发者提供了便捷的功能,例如应用模板创建、工具安装和接口调试,以提高用户研发效率。

执行以下命令将 dubbogo-cli 安装到 $GOPATH/bin

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

2. 功能概述

dubbogo-cli 支持以下功能

  • 应用模板创建

    dubbogo-cli newApp.
    

    在当前目录创建应用模板

  • Demo 创建

    dubbogo-cli newDemo.
    

    在当前目录创建 RPC 示例,包括客户端和服务器

  • 编译和调试工具安装

    dubbogo-cli install all
    

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

    -protoc-gen-go-triple

    Compilation for triple protocol interface
    
  • 查看 dubbo-go 应用注册信息

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

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

    • 查看 Istio 的注册信息 [功能开发中]

  • 调试 Dubbo 协议接口

  • 调试 Triple 协议接口

3. 功能详情

3.1 Demo 应用介绍

3.1.1 Demo 创建

dubbogo-cli newDemo.

在当前目录创建 Demo,包括客户端和服务器。Demo 演示了基于一组接口完成 RPC 调用。

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

.
├── api
│ ├── samples_api.pb.go
│ ├── samples_api.proto
│ └── samples_api_triple.pb.go
├── go-client
│ ├── cmd
│ │ └── client.go
│ └── conf
│ └── dubbogo.yaml
├── go-server
│ ├── cmd
│ │ └── server.go
│ └── conf
│ └── dubbogo.yaml
└── go.mod

3.1.2 运行 Demo

启动服务器

$ cd go-server/cmd
$ go run .

另一个终端打开客户端

$ go mod tidy
$ cd go-client/cmd
$ go run .

可以看到打印日志

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

3.2 应用模板介绍

3.2.1 应用模板创建

dubbogo-cli newApp.

在当前目录创建应用模板

.
├── Makefile
├── api
│ ├── api.pb.go
│ ├── api.proto
│ └── api_triple.pb.go
├──build
│ └── Dockerfile
├── chart
│ ├── app
│ │ ├── Chart.yaml
│ │ ├── templates
│ │ │ ├── _helpers.tpl
│ │ │ ├── deployment.yaml
│ │ │ ├── service.yaml
│ │ │ └── serviceaccount.yaml
│ │ └── values.yaml
│ └── nacos_env
│ ├── Chart.yaml
│ ├── templates
│ │ ├── _helpers.tpl
│ │ ├── deployment.yaml
│ │ └── service.yaml
│ └── values.yaml
├── cmd
│ └── app.go
├── conf
│ └── dubbogo.yaml
├── go.mod
├── go.sum
└── pkg
    └── service
        └── 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 配置,重点关注 image 部分。
image:
  repository: $(your_repo)/$(namespace)/$(image_name)
  pullPolicy: Always
  tag: "1.0.0"
  1. make deploy,使用 helm 发布应用。

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

3.3.1 简介

grpc_cli 工具是 gRPC 生态系统用来调试服务的工具。它可以在服务器上启用了 [反射服务] (https://github.com/grpc/grpc/blob/master/doc/server-reflection.md) 的前提下获取服务的 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 服务的接口定义
$ grpc_cli ls localhost:20001 -l
filename: helloworld.proto
package: org.apache.dubbo.quickstart.samples;
service UserProvider {
  rpc SayHello(org.apache.dubbo.quickstart.samples.HelloRequest) returns (org.apache.dubbo.quickstart.samples.User) {}
  rpc SayHelloStream(stream org.apache.dubbo.quickstart.samples.HelloRequest) returns (stream org.apache.dubbo.quickstart.samples.User) {}
}
  1. 检查请求参数类型

例如,如果开发者想测试上述端口的 SayHello 方法,并尝试获取 HelloRequest 的具体定义,则需要执行以下命令查看对应参数的定义。

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

了解请求参数的具体类型后,就可以发起调用来测试对应的服务。检查返回值是否符合预期。

$ grpc_cli call localhost:20001 SayHello "name: 'laurence'"
connecting to localhost:20001
name: "Hello Laurence"
id: "12345"
age: 21
Received trailing metadata from server:
accept-encoding: identity, gzip
adaptive-service.inflight : 0
adaptive-service. remaining : 50
grpc-accept-encoding : identity,deflate,gzip
Rpc succeeded with OK status

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

3.4.1 打开 Dubbo 服务器

示例:user.go

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

服务器打开一个名为 GetUser 的服务,传入一个 CallUserStruct 参数,并返回一个 User 参数 CallUserStruct 参数定义

type CallUserStruct struct {
ID string
Male bool
SubInfo SubInfo // nested substructure
}
func (cs CallUserStruct) JavaClassName() string {
return "com.ikurento.user.CallUserStruct"
}

type SubInfo struct {
SubID string
SubMale bool
SubAge int
}

func (s SubInfo) JavaClassName() string {
return "com.ikurento.user.SubInfo"
}

User 结构定义

type User struct {
Id string
name string
Age int32
SubInfo SubInfo // Nest the above substructure SubInfo
}

func (u *User) JavaClassName() string {
return "com.ikurento.user.User"
}

启动服务

cd server`
`source builddev.sh`
`go run.

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

请求体定义为 json 文件,约定 key value 为 string key 对应 Go 语言 struct 的字段名,例如 “ID” 和 “Name”,value 对应 “type@val” 其中 type 支持 string int bool time,val 用 string 初始化,如果只填写 type,则初始化为零值。约定每个 struct 必须有一个 JavaClassName 字段,该字段必须与服务器端严格对应

参见 userCall.json

{
  "ID": "string@A000",
  "Male": "bool@true",
  "SubInfo": {
    "SubID": "string@A001",
    "SubMale": "bool@false",
    "SubAge": "int@18",
    "JavaClassName": "string@com.ikurento.user.SubInfo"
  },
  "JavaClassName": "string@com.ikurento.user.CallUserStruct"
}

userCall.json 定义了参数 CallUserStruct 和子结构 SubInfo 的结构,并为请求参数赋值。

同样,user.json 不需要赋值作为返回值,但 JavaClassName 字段必须与服务器端严格对应

{
  "ID": "string",
  "Name": "string",
  "Age": "int",
  "JavaClassName": "string@com.ikurento.user.User",
  "SubInfo": {
    "SubID": "string",
    "SubMale": "bool",
    "SubAge": "int",
    "JavaClassName": "string@com.ikurento.user.SubInfo"
  }
}

3.4.3 调试端口

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

打印结果

2020/10/26 20:47:45 Created pkg:
2020/10/26 20:47:45 &{ID:A000 Male:true SubInfo:0xc00006ea20 JavaClassName:com.ikurento.user.CallUserStruct}
2020/10/26 20:47:45 SubInfo:
2020/10/26 20:47:45 &{SubID:A001 SubMale:false SubAge:18 JavaClassName:com.ikurento.user.SubInfo}


2020/10/26 20:47:45 Created pkg:
2020/10/26 20:47:45 &{ID: Name: Age:0 JavaClassName:com.ikurento.user.User SubInfo:0xc00006ec90}
2020/10/26 20:47:45 SubInfo:
2020/10/26 20:47:45 &{SubID: SubMale:false SubAge:0 JavaClassName:com.ikurento.user.SubInfo}


2020/10/26 20:47:45 connected to localhost:20001!
2020/10/26 20:47:45 try calling interface: com.ikurento.user.UserProvider.GetUser
2020/10/26 20:47:45 with protocol: dubbo

2020/10/26 20:47:45 After 3ms , Got Rsp:
2020/10/26 20:47:45 &{ID:A002 Name:Alex Stocks Age:18 JavaClassName: SubInfo:0xc0001241b0}
2020/10/26 20:47:45 SubInfo:
2020/10/26 20:47:45 &{SubID:A001 SubMale:false SubAge:18 JavaClassName:}```

可以看到详细的请求体赋值,以及返回结果和耗时。支持嵌套结构

打印服务器端的结果

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

可以看到已经收到了来自 cli 的数据


上次修改时间:2023 年 1 月 2 日:增强 Dubbogo 文档 (#1800) (71c8e722740)