简介
Kitex 字节跳动内部的 Golang 微服务 RPC 框架,具有高性能、强可扩展的特点,在字节内部已广泛使用。如果对微服务性能有要求,又希望定制扩展融入自己的治理体系,Kitex 会是一个不错的选择。
Kitex 的架构主要包括四个部分:Kitex Tool、Kitex Core、Kitex Byted、Second Party Pkg。
- Kitex Core 是一个携带了一套微服务治理功能的 RPC 框架,它是 Kitex 的核心部分。
- Kitex Byted 是一套结合了字节跳动内部基础设施的拓展集合。通过这一套拓展集合,Kitex 能够在内部支持业务的发展。
- Kitex Tool 是一个命令行工具,能够在命令行生成我们的代码以及服务的脚手架,可以提供非常便捷的开发体验。
- Second Party Pkg,例如 netpoll, netpoll-http2,是 Kitex 底层的网络库,这两个库也开源在 CloudWeGo 组织中。
Kite 作为字节跳动第一代 Golang RPC 框架,主要存在以下缺陷:
- Kite 为了快速支持业务发展需求,不可避免地耦合了部分中台业务的功能;
- Kite 对 Go modules 支持不友好(Go modules 在 2019 年才进入语言核心);
- Kite 自身的代码拆分成多仓库,版本更新时推动业务升级困难;
- Kite 强耦合了早期版本的 Apache Thrift,协议和功能拓展困难;
- Kite 的生成代码逻辑与框架接口强耦合,成为了性能优化的天花板。
因此,业务的快速发展和需求场景的多样化,催生了新一代 Golang RPC 框架 Kitex。
使用
安装
目前kitex还没有支持Windows系统,所以对于Windows的用户,需要安装虚拟机。虚拟机软件可以选择VirtualBox或者Vmware。 在搭建好golang环境后,进入kitex的官方文档,安装kitex与thriftgo命令行工具。
bash
go install github.com/cloudwego/kitex/tool/cmd/kitex\@latest # 安装kitex
go install github.com/cloudwego/thriftgo\@latest # 安装thrift
这里需要注意,如果没有将GOPATH/bin添加到环境变量的话,安装后的命令行工具是无法用的。 可以使用go env查看GOPATH路径。
bash
export PATH=$PATH:$GOPATH/bin # 添加$GOPATH/bin到系统环境变量
如果不想每次都重新设置环境变量,可以在~/.bashrc文件末尾追加上述指令。
验证是否安装成功
bash
kitex --version
thriftgo --version
例程
获取示例代码
git clone github.com/cloudwego/k...
运行示例代码
直接启动:
- 进入示例仓库的 hello 目录
bash
cd kitex-examples/hello
- 运行 server
arduino
go run ./server
- 运行 client:另起一个终端后
arduino
go run ./client
使用 Docker 快速启动:
- 进入示例仓库目录
bash
cd kitex-examples
- 编译项目
erlang
docker build -t kitex-examples .
- 运行 server
arduino
docker run --network host kitex-examples ./hello-server
- 运行 client:另起一个终端后
arduino
docker run --network host kitex-examples ./hello-client
注:代码生成后的hello/hello.go报错,这是因为github.com/apache/thrift 这个包使用的是v0.17.0版本的,但v0.14.0之后的包中很多函数增加了context上下文参数,所以很多函数由于缺少参数报错。只需要修改go.mod中的require中github.com/apache/thrift v0.17.0为github.com/apache/thrift v0.13.0然后再执行go mod tidy问题就能解决
现在成功通过 Kitex 发起了 RPC 调用。增加一个新方法
打开 hello.thrift,为新方法分别定义一个新的请求和响应,AddRequest 和 AddResponse,并在 service Hello 中增加 add 方法
go
namespace go api
struct Request {
1: string message
}
struct Response {
1: string message
}
struct AddRequest {
1: i64 first
2: i64 second
}
struct AddResponse {
1: i64 sum
}
service Hello {
Response echo(1: Request req)
AddResponse add(1: AddRequest req)
}
重新生成代码
运行如下命令后,kitex 工具将根据 hello.thrift 更新代码文件
css
kitex -service a.b.c hello.thrift
若当前目录不在 $GOPATH/src 下,需要加上 -module 参数,一般为 go.mod 下的名字
arduino
kitex -module "your_module_name" -service a.b.c hello.thrift
执行完上述命令后,kitex 工具将更新下述文件
- 更新 ./handler.go,在里面增加一个 Add 方法的基本实现
- 更新 ./kitex_gen,里面有框架运行所必须的代码文件
- 更新服务端处理逻辑
上述步骤完成后,./handler.go 中会自动补全一个 Add 方法的基本实现,类似如下代码:
go
// Add implements the HelloImpl interface.
func (s *HelloImpl) Add(ctx context.Context, req *api.AddRequest) (resp *api.AddResponse, err error) {
// TODO: Your code here...
return
}
在里面增加我们所需要的逻辑,类似如下代码:
go
// Add implements the HelloImpl interface.
func (s *HelloImpl) Add(ctx context.Context, req *api.AddRequest) (resp *api.AddResponse, err error) {
// TODO: Your code here...
resp = &api.AddResponse{Sum: req.First + req.Second}
return
}
增加客户端调用
在 ./client/main.go 中你会看到类似如下的 for 循环:
css
for {
req := &api.Request{Message: "my request"}
resp, err := client.Echo(context.Background(), req)
if err != nil {
log.Fatal(err)
}
log.Println(resp)
time.Sleep(time.Second)
}
在里面增加 Add 方法的调用:
css
for {
req := &api.Request{Message: "my request"}
resp, err := client.Echo(context.Background(), req)
if err != nil {
log.Fatal(err)
}
log.Println(resp)
time.Sleep(time.Second)
addReq := &api.AddRequest{First: 512, Second: 512}
addResp, err := client.Add(context.Background(), addReq)
if err != nil {
log.Fatal(err)
}
log.Println(addResp)
time.Sleep(time.Second)
}
重新运行示例代码,可以看到客户端在调用 Add 方法
总结
总的来说,kitex框架降低了我们开发rpc服务的工作量,通过自动生成代码的方式,避免了重复的工作。然而在实际使用时也存在了一定的不便。自动生成模型时,无法携带结构体的tag标签,使得与gin等web框架结合使用时,无法使用参数帮等功能。虽然可以通过手动修改生成文件的方式来实现,但是这样一来,如果需要重新生成代码时,工作量又会上升。最后,希望kitex框架越做越好。