Skip to content

支持 kitex <-> dubbo 互通的 dubbo 协议编解码器。

License

Notifications You must be signed in to change notification settings

kitex-contrib/codec-dubbo

Repository files navigation

codec-dubbo

中文 | English

Kitex 为了支持 kitex <-> dubbo 互通 推出的 dubbo 协议编解码器。

功能

Kitex-Dubbo 互通

  1. kitex -> dubbo

基于已有的 dubbo Interface API类型映射,编写 api.thrift。然后使用最新的 kitex 命令行工具和 thriftgo 生成 kitex 的脚手架代码(包括用于编解码的stub代码)。

  1. dubbo -> kitex

基于已有的 api.thrift类型映射,编写 dubbo 客户端代码。

类型映射

thrift 类型 golang 类型 hessian2 类型 java 类型
bool bool boolean java.lang.Boolean
byte int8 int java.lang.Byte
i16 int16 int java.lang.Short
i32 int32 int java.lang.Integer
i64 int64 long java.lang.Long
double float64 double java.lang.Double
string string string java.lang.String
binary []byte binary byte[]
list<bool> []bool list List<Boolean>
list<i32> []int32 list List<Integer>
list<i64> []int64 list List<Long>
list<double> []float64 list List<Double>
list<string> []string list List<String>
map<bool, bool> map[bool]bool map Map<Boolean, Boolean>
map<bool, i32> map[bool]int32 map Map<Boolean, Integer>
map<bool, i64> map[bool]int64 map Map<Boolean, Long>
map<bool, double> map[bool]float64 map Map<Boolean, Double>
map<bool, string> map[bool]string map Map<Boolean, String>

重要提示

  1. 映射表中的 map 类型并没有被完全列举,当前仅包含经过测试的用例。 请勿在map类型中使用包含 i8i16binary 的键值。
  2. 当前仅支持表格中所记录的 thrift 类型和 java 类型映射。 更多映射关系(例如,bool <-> boolean)将在未来支持,请参考 issue
  3. 目前不支持float32,因为它在 thrift 中不是有效的类型。计划在后续迭代中支持该类型。

开始

完整代码.

安装命令行工具

# 安装 kitex 命令行工具,需指定版本
go install github.com/cloudwego/kitex/tool/cmd/kitex@008f748

# 安装 thriftgo 命令行工具
go install github.com/cloudwego/thriftgo@latest

支持Hessian2协议的提交已经合并,但尚未发布,因此需要安装Kitex的特定版本。我们将很快发布Kitex的新版本,之后便可使用@latest进行安装。

生成 kitex stub 代码

mkdir ~/kitex-dubbo-demo && cd ~/kitex-dubbo-demo
go mod init kitex-dubbo-demo

# 编写你所需的 Thrift IDL,此处仅为演示
cat > api.thrift << EOF
namespace go hello

struct GreetRequest {
    1: required string req,
}(JavaClassName="org.cloudwego.kitex.samples.api.GreetRequest")

struct GreetResponse {
    1: required string resp,
}(JavaClassName="org.cloudwego.kitex.samples.api.GreetResponse")

service GreetService {
    string Greet(1: string req)
    GreetResponse GreetWithStruct(1: GreetRequest req)
}

EOF

# 使用 `-protocol Hessian2` 配置项生成 Kitex 脚手架代码
kitex -module kitex-dubbo-demo -thrift template=slim -service GreetService -protocol Hessian2 ./api.thrift

重要提示:

  1. api.thrift 中定义的每个结构体都应该有一个名为 JavaClassName 的注解,并且注解值与 Dubbo Java 中对应的类名必须一致。

实现业务逻辑并完成初始化

业务逻辑

import (
    "context"
    hello "github.com/kitex-contrib/codec-dubbo/samples/helloworld/kitex/kitex_gen/hello"
)

func (s *GreetServiceImpl) Greet(ctx context.Context, req string) (resp string, err error) {
	return "Hello " + req, nil
}

func (s *GreetServiceImpl) GreetWithStruct(ctx context.Context, req *hello.GreetRequest) (resp *hello.GreetResponse, err error) {
	return &hello.GreetResponse{Resp: "Hello " + req.Req}, nil
}

实现在 handler.go 中定义的接口.

客户端初始化

import (
	"context"
	"github.com/cloudwego/kitex/client"
	"github.com/cloudwego/kitex/pkg/klog"
	dubbo "github.com/kitex-contrib/codec-dubbo/pkg"  
	"github.com/kitex-contrib/codec-dubbo/samples/helloworld/kitex/kitex_gen/hello"
	"github.com/kitex-contrib/codec-dubbo/samples/helloworld/kitex/kitex_gen/hello/greetservice"
)

func main() {
	cli, err := greetservice.NewClient("helloworld",
		// 指定想要访问的服务端地址
		client.WithHostPorts("127.0.0.1:21001"),
		// 配置 DubboCodec
		client.WithCodec(
			dubbo.NewDubboCodec(
				// 指定想要调用的 Dubbo Interface
				dubbo.WithJavaClassName("org.cloudwego.kitex.samples.api.GreetProvider"),
			),
		),
	)
	if err != nil {
		panic(err)
	}

	resp, err := cli.Greet(context.Background(), "world")
	if err != nil {
		klog.Error(err)
		return
	}
	klog.Infof("resp: %s", resp)
	
	respWithStruct, err := cli.GreetWithStruct(context.Background(), &hello.GreetRequest{Req: "world"})
	if err != nil {
		klog.Error(err)
		return
	}
	klog.Infof("respWithStruct: %s", respWithStruct.Resp)
}

重要提示:

  1. 每个 Dubbo Interface 对应一个 DubboCodec 实例,请不要在多个客户端之间共享同一个实例。

服务端初始化

import (
	"github.com/cloudwego/kitex/server"
	dubbo "github.com/kitex-contrib/codec-dubbo/pkg"
	hello "github.com/kitex-contrib/codec-dubbo/samples/helloworld/kitex/kitex_gen/hello/greetservice"
	"log"
	"net"
)

func main() {
	// 指定服务端将要监听的地址
	addr, _ := net.ResolveTCPAddr("tcp", ":21000")
	svr := hello.NewServer(new(GreetServiceImpl),
		server.WithServiceAddr(addr),
		// 配置 DubboCodec
		server.WithCodec(dubbo.NewDubboCodec(
			// 配置 Kitex 服务所对应的 Interface. 其他 dubbo 客户端和 kitex 客户端可以通过这个名字进行调用。
			dubbo.WithJavaClassName("org.cloudwego.kitex.samples.api.GreetProvider"),
		)),
	)

	err := svr.Run()

	if err != nil {
		log.Println(err.Error())
	}
}

重要提示:

  1. 每个 Dubbo Interface 对应一个 DubboCodec 实例,请不要在多个服务端之间共享同一个实例。

性能测试

测试环境

CPU: Intel(R) Xeon(R) Gold 5118 CPU @ 2.30GHz
内存: 192GB

测试代码

测试代码主要参考 dubbo-go-benchmark. 将 dubbo 客户端和 dubbo 服务端替换成对应的 kitex 客户端和 kitex 服务端。 具体实现请看代码

测试结果

kitex -> kitex

bash deploy.sh kitex_server -p 21001
bash deploy.sh kitex_client -p 21002 -addr "127.0.0.1:21001"
bash deploy.sh stress -addr '127.0.0.1:21002' -t 1000000 -p 100 -l 256

结果:

平均响应时间(ns) tps 成功率
2310628 46015 1.000000
2363729 44202 1.000000
2256177 43280 1.000000
2194147 43171 1.000000

资源占用:

进程名 %CPU %内存
kitex_client_main 914.6 0.0
kitex_server_main 520.5 0.0
stress_main 1029 0.1

测试总结

dubbo-go-hessian2 依赖反射进行编解码,因此可以通过基于生成代码的编解码器来提升性能。

我们将在后续迭代中推出Hessian2 fastCodec

致谢

这是一个由社区驱动的项目,由 @DMwangnima 维护。

我们衷心感谢dubbo-go开发团队的宝贵贡献!

参考