这是我参与「第五届青训营 」伴学笔记创作活动的第 4 天,记录一下对 kitex 框架的学习。
什么是 kitex
Kitex[kaɪt’eks] 字节跳动内部的 Golang 微服务 RPC 框架,具有高性能、强可扩展的特点,在字节内部已广泛使用。
快速开始
Kitex 默认支持 thrift、kitex protobuf 和 grpc,本文的实验中只使用了 kitex + thrift 的组合。
下载
- 安装 kitex:
go install github.com/cloudwego/kitex/tool/cmd/kitex@latest; - 安装 thriftgo:
go install github.com/cloudwego/thriftgo@latest; - 执行
kitex --version和thrift --version,测试是否安装成功。
$ kitex --version
v0.4.4
$ thriftgo --version
thriftgo 0.2.5
编写 thrift idl
在文件 hello.thrift 文件中编写 idl。
下面的 idl 定义了一个名为 hello 的 service,它包含一个接口 echo,入参是 Request,出参是Response。
namespace go api
struct Request {
1: string message
}
struct Response {
1: string message
}
service Hello {
Response echo(1: Request req)
}
生成代码
运行命令kitex -module hello -service HelloService hello.thrift即可生成代码。
-module 用来指定生成的 module 的名字,-service用来指定 service 的名字。
生成的目录结构如下。
|-- build.sh 构建工程的脚本
|-- go.mod
|-- handler.go idl定义的接口的空实现
|-- hello.thrift 我们编写的idl
|-- kitex.yaml 记录kitex版本和service名称
|-- kitex_gen
| `-- api
| |-- hello
| | |-- client.go 客户端相关方法
| | |-- hello.go
| | |-- invoker.go
| | `-- server.go 服务端相关方法
| |-- hello.go
| |-- k-consts.go
| `-- k-hello.go
|-- main.go 服务端入口
`-- script
`-- bootstrap.sh
其中 handler.go 提供了 idl 定义的接口的空实现,需要我们补充对应的业务逻辑。
...
// HelloImpl implements the last service interface defined in the IDL.
type HelloImpl struct{}
// Echo implements the HelloImpl interface.
func (s *HelloImpl) Echo(ctx context.Context, req *api.Request) (resp *api.Response, err error) {
// TODO: Your code here...
return
}
补充代码
让 Echo 方法简单的返回 Request 中的 Message。
func (s *HelloImpl) Echo(ctx context.Context, req *api.Request) (resp *api.Response, err error) {
return &api.Response{Message: req.Message}, nil
}
运行服务端
运行命令go mod tidy和go build hello,发现在 build 的时候报错了,错误与 thrift 相关。该问题在官方文档中也有描述。
出现 Thrift 接口编译问题,如 not enough arguments in call to iprot.ReadStructBegin
Kitex 依赖 Thrift v0.13,因为Apache Thrift v0.14 接口有 breaking change,无法直接升级。出现该问题是拉到了新版本的 Thrift,升级版本时建议不使用 -u 参数,可以执行命令固定版本 go mod edit -replace github.com/apache/thri…
解决问题后,重新运行上面的命令得到可执行文件 hello,运行命令./hello即可看到服务端可以正常运行了。
编写客户端
在与服务端工程同级目录下新建一个客户端工程。
| -- hello_server 服务端
| -- hello_client 客户端
要构建客户端,还需要之前 kitex 生成的代码,可以在 go.mod 中导入。
require hello_server v0.0.0
replace hello_server => ../hello_server
参考官方文档编写一个简单的客户端,代码如下。
...
func main() {
c, err := echo.NewClient("example", client.WithHostPorts("0.0.0.0:8888"))
if err != nil {
log.Fatal(err)
}
req := &api.Request{Message: "my request"}
resp, err := c.Echo(context.Background(), req, callopt.WithRPCTimeout(3*time.Second))
if err != nil {
log.Fatal(err)
}
log.Println(resp)
}
运行客户端
在服务端开启的情况下运行客户端,可以看到如下输出。
2023/01/18 20:50:08 Response({Message:hello})
其他
上面的例子中服务端业务代码和 kitex 生成的代码耦合到了一起,客户端又依赖了服务端代码,耦合性太高,不利于维护。比较合适的结构应该是分为服务端、客户端和 rpc sdk(即 kitex 生成的代码)三个模块,服务端和客户端分别去依赖 rpc sdk。