Kitex
Kitex介绍
KiteX 是字节跳动框架组研发的 Golang 微服务 RPC 框架。通过查看官方文档,可以知道Kitex具有高性能、强可拓展、多消息协议、多传输协议、多种消息类型、服务治理、代码生成等特点。
-
高性能
使用自研的高性能网络库 Netpoll,性能相较 go net 具有显著优势。
-
扩展性
提供了较多的扩展接口以及默认扩展实现,使用者也可以根据需要自行定制扩展,具体见下面的框架扩展。
-
多消息协议
RPC 消息协议默认支持 Thrift、Kitex Protobuf、gRPC。Thrift 支持 Buffered 和 Framed 二进制协议;Kitex Protobuf 是 Kitex 自定义的 Protobuf 消息协议,协议格式类似 Thrift;gRPC 是对 gRPC 消息协议的支持,可以与 gRPC 互通。除此之外,使用者也可以扩展自己的消息协议。
-
多传输协议
传输协议封装消息协议进行 RPC 互通,传输协议可以额外透传元信息,用于服务治理,Kitex 支持的传输协议有 TTHeader、HTTP2。TTHeader 可以和 Thrift、Kitex Protobuf 结合使用;HTTP2 目前主要是结合 gRPC 协议使用,后续也会支持 Thrift。
-
多种消息类型
支持 PingPong、Oneway、双向 Streaming。其中 Oneway 目前只对 Thrift 协议支持,双向 Streaming 只对 gRPC 支持,后续会考虑支持 Thrift 的双向 Streaming。
-
服务治理
支持服务注册/发现、负载均衡、熔断、限流、重试、监控、链路跟踪、日志、诊断等服务治理模块,大部分均已提供默认扩展,使用者可选择集成。
-
代码生成
Kitex 内置代码生成工具,可支持生成 Thrift、Protobuf 以及脚手架代码。
Kitex快速开始
1. 环境准备
通过查看官方文档,可以发现目前最新的kitex已经可以在windows环境使用了。这省去了安装 WSL2 的麻烦。
然后安装代码生成工具。
# 安装 kitex
go install github.com/cloudwego/kitex/tool/cmd/kitex@latest
# 安装 thriftgo
go install github.com/cloudwego/thriftgo@latest
通过查看版本命令判断是否安装成功
kitex --version
thriftgo --version
2. 定义IDL
IDL 全称是 Interface Definition Language,接口定义语言。如果我们要进行 RPC,就需要知道对方的接口是什么,需要传什么参数,同时也需要知道返回值是什么样的,就好比两个人之间交流,需要保证在说的是同一个语言、同一件事。 这时候,就需要通过 IDL 来约定双方的协议,就像在写代码的时候需要调用某个函数,我们需要知道函数签名一样。Kitex 框架及命令行工具,默认支持 thrift 和 proto3 两种 IDL,对应的 Kitex 支持 thrift 和 protobuf 两种序列化协议。 传输上 Kitex 使用扩展的 thrift 作为底层的传输协议(注:thrift 既是 IDL 格式,同时也是序列化协议和传输协议)。
Kitex最典型的情况是使用thrift定义的IDL来编写服务接口实现客户端和服务端的通信,以thrift IDL为例子首先先创建一个thift IDL文件hello.thrift接着定义我们的服务:
namespace go api
// struct Request{}表示我们编写一个请求消息体。struct中变量的格式为不重复的编号:类型:命名
struct Request {
1: string message
}
// struct Response{}表示我们编写了一个返回消息体。
struct Response {
1: string message
}
// service Echo{}表示定义了一个Echo服务
service Echo {
// Response echo(1:Request req)表示服务Echo中有一个叫做echo的方法
// 方法的返回消息为Response请求消息为Request请求消息的格式为编号: 请求消息:命名
Response echo(1: Request req)
}
3. 生成代码
使用如下命令生成项目代码:
kitex -module example -service example-server echo.thrift
上述命令中:
-module表示生成的该项目的 go module 名;建议使用完整包名,例如github.com/Yourname/exampleserver-service表明我们要生成一个服务端项目,后面紧跟的example-server为该服务的名字- 最后一个参数则为该服务的 IDL 文件
生成的项目结构如下:
其中需要编写的服务端逻辑都在 handler.go 这个文件中,服务默认监听8888端口。文件内容如下所示:
package main
import (
"context"
"example/kitex_gen/api" //如果修改了 -module 参数的值,这里的 'example' 也要相应替换
)
// EchoImpl implements the last service interface defined in the IDL.
type EchoImpl struct{}
// Echo implements the EchoImpl interface.
func (s *EchoImpl) Echo(ctx context.Context, req *api.Request) (resp *api.Response, err error) {
// TODO: Your code here...
return
}
我们在IDL中完成了echo方法,对应这这里的Echo函数,我们在这里修改服务端逻辑:
func (s *EchoImpl) Echo(ctx context.Context, req *api.Request) (resp *api.Response, err error) {
return &api.Response{Message: req.Message}, nil
}
接着对这个案例进行编译运行,Kitex工具已经生成了编译运行脚本:
$ sh build.sh
//运行后会生成一个output目录,里面有我们编译的结果
$ sh output/bootstrap.sh
//运行这条指令后Echo服务就开始运行了
4. 实现调用
接着编写客户端程序来完成对服务端的调用,创建文件夹进入目录:
//这是为了创建客户端
import "example/kitex_gen/api/echo"
import "github.com/cloudwego/kitex/client"
...
// echo.NewClient 用于创建 client,其第一个参数为调用的 服务名,第二个参数为 options,用于传入参数。
// 此处的 client.WithHostPorts 用于指定服务端的地址
c, err := echo.NewClient("example", client.WithHostPorts("0.0.0.0:8888"))
if err != nil {
log.Fatal(err)
}
然后编写用于发起调用的代码:
import "example/kitex_gen/api"
...
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)
首先创建了一个请求 req , 然后通过 c.Echo 发起了调用。其第一个参数为 context.Context,通过通常用其传递信息或者控制本次调用的一些行为。其第二个参数为本次调用的请求。其第三个参数为本次调用的 options ,Kitex 提供了一种 callopt 机制,顾名思义——调用参数 ,有别于创建 client 时传入的参数,这里传入的参数仅对此次生效。 此处的 callopt.WithRPCTimeout 用于指定此次调用的超时。
之后对服务端发起调用:
$ go run main.go
//正常会得到如下结果
2023/08/18 15:41:35 Response({Message:my request})