在内部各个服务组件之间相互调用,离不开高性能Rpc。
除了gRpc,bRpc以外,在go的技术栈里还有一个开源好用的组件。
目录
[Kitex 框架介绍](#Kitex 框架介绍)
写一个gateway.go模拟入口网关,从屏幕读取输入,透传给后端:
再一个后端的worker,提供服务,服务里提供方法:SendMessage
Kitex 框架介绍
Kitex 是字节跳动 CloudWeGo 开源的Go语言高性能RPC微服务框架,广泛用于构建大规模分布式服务,兼顾高性能、多协议、强扩展能力,内置完整微服务治理能力。
核心特点与优点
- 高性能IO :底层基于自研
netpoll网络库,相比Go原生net,降低goroutine开销,高并发场景下延迟更低、吞吐更高,支持连接多路复用。 - 强可扩展:全链路预留扩展接口,编解码、传输、服务发现、负载均衡、中间件、监控均可自定义实现,不与特定基础设施强绑定。
- IDL代码生成 :内置
kitex命令行工具,读取Thrift/Protobuf IDL,一键生成服务端、客户端桩代码与项目脚手架,减少重复编码工作。 - 完备服务治理:原生支持注册发现、负载均衡、熔断、限流、重试、超时、链路追踪、日志、故障诊断,组件按需开启,非强制侵入。
- 多协议兼容:一套框架同时支持多种RPC消息、传输协议,可对接gRPC、Thrift生态,也支持自定义私有协议。
适用场景
- Go语言后端微服务集群,内部服务之间RPC调用;
- 高吞吐、低延迟业务:IM网关、消息服务、网关、数据计算、业务中台;
- 需要多协议互通:和Thrift、gRPC服务互相调用;
- 云原生环境,支持xDS无代理(Proxyless)模式对接Istio服务网格;
- 需要深度定制RPC逻辑:自定义负载、私有编解码、特殊元信息透传。
不适合:浏览器前端直接访问;面向公网对外暴露业务(优先HTTP网关做接入)。
支持消息协议(编解码Codec)
- Thrift:支持Framed / Buffered二进制,兼容多语言Thrift体系;支持Oneway单向调用。
- Kitex‑Protobuf :Kitex自研protobuf消息协议,格式风格类似Thrift,配合TTHeader做服务治理,我们之前demo用的就是这套,不走HTTP2/gRPC。
- gRPC‑Protobuf:标准gRPC协议,HTTP2传输,支持双向Streaming流调用,可以和标准gRPC服务互通。
- 扩展点:可实现
remote.Codec接口,接入自定义私有编解码。
传输层协议(Transport)
- TTHeader / TTHeaderFramed :Kitex私有TCP传输帧,用于透传trace、服务名、集群、环境等治理元数据,搭配Thrift、Kitex‑Protobuf使用,普通内部微服务最常用。
- HTTP2:主要用于gRPC协议,提供流能力。
- PurePayload:裸payload,无治理header,仅透传业务二进制。
交互调用模型:PingPong普通请求‑响应、Oneway单向调用、Streaming双向流。
服务发现种类(Resolver/Registry)
Kitex接口化设计,支持多种注册中心,社区扩展丰富:
- Etcd:最常用,适合K8s/自建集群;
- Consul;
- Nacos;
- 静态Resolver:硬编码节点列表,测试环境、demo开发使用;
- HTTP Resolver:通过HTTP接口获取实例列表;
- xDS Resolver:对接Istio控制平面,Proxyless无代理服务网格模式;
- 自定义:实现
discovery.Resolver接口,对接自研注册中心。
区分:
Registry服务端用于把自己服务实例注册到注册中心;Resolver客户端用来拉取下游实例列表。
内置调度(负载均衡)算法
| 算法 | 说明 |
|---|---|
| WeightedRoundRobin(默认) | 平滑加权轮询,均衡控制inflight并发请求,生产默认推荐 |
| InterleavedWeightedRoundRobin | 交错加权轮询,实例数量巨大场景优化 |
| WeightedRandom | 加权随机,按实例权重做随机选择 |
| AliasMethod | 别名算法,初始化后O(1)选取,高实例数性能更优 |
| ConsistentHash 一致性哈希 | 相同key固定路由到同一实例,适合本地缓存、状态服务场景 |
自定义调度(自定义负载均衡)
Kitex完全支持自行编写负载均衡策略:
- 实现
loadbalance.LoadBalancer接口,输入服务发现返回的实例列表,根据自定义规则选出目标endpoint; - Client初始化时通过
client.WithLoadBalancer(yourLB)注入自定义调度器; - 可以实现机房优先、就近调度、基于实时延迟调度、灰度流量、自定义权重逻辑等。
完整扩展点:除LB之外,还可以自定义Codec、MetaHandler、中间件、Registry、Resolver、Tracer监控上报。
简短小结
Kitex 以netpoll为底层,TTHeaderFramed+Kitex‑Protobuf是内部Go微服务最主流组合;服务发现可对接etcd/nacos/consul/xDS;内置多种负载均衡,并且支持完全自研调度逻辑,适合IM、网关这类高并发分布式服务开发。
那么今天开始一个最基础的入门调用练习,使用大家都熟悉的proto方式,
建立一个目录,比如叫demo-im
demo-im/
├── go.mod // module demo-im
├── im.proto // 放在根目录或 birdproto 目录下
├── birdproto/ // 新建的子目录
│ └── im.proto // (推荐) proto 文件放在这里
gen/ // 生成的代码放在这里
│ └── im/ // 对应 go_package 中的 im
│ ├── im.pb.go
│ └── im.kitex.go
├── gateway/
│ └── main.go
└── worker/
└── main.go
创建协议:im.proto
syntax = "proto3";
package im;
option go_package = "demo-im/bird-proto/gen/im;im";
message SendMessageReq {
string content = 1;
}
message SendMessageResp {
int32 code = 1;
string message = 2;
}
message PushMessageReq {
string content = 1;
}
message PushMessageResp {
int32 code = 1;
string message = 2;
}
service ImWorkerService {
rpc SendMessage(SendMessageReq) returns (SendMessageResp);
}
service ImGatewayService {
rpc PushMessage(PushMessageReq) returns (PushMessageResp);
}
编译方法:
bash
// # 安装kitex工具
// go install github.com/cloudwego/kitex/tool/cmd/kitex@latest
// kitex0.16.3
// # 生成worker服务代码(ImWorkerService)
// D:\go_work\bin\kitex -type protobuf -service ImWorkerService -gen-path ./ im.proto
//
// # 生成gateway服务代码(ImGatewayService)
// D:\go_work\bin\kitex -type protobuf -service ImGatewayService -gen-path ./ im.proto
写一个gateway.go模拟入口网关,从屏幕读取输入,透传给后端:
Go
package main
import (
"bufio"
"context"
"demo-im/bird-proto/gen/im"
"demo-im/bird-proto/gen/im/imgatewayservice"
"demo-im/bird-proto/gen/im/imworkerservice"
"fmt"
"log"
"net"
"os"
"strings"
"time"
"github.com/cloudwego/kitex/client"
"github.com/cloudwego/kitex/server"
)
// 实现 Gateway 服务的 PushMessage 方法
type GatewayServiceHandler struct{}
func (h *GatewayServiceHandler) PushMessage(ctx context.Context, req *im.PushMessageReq) (*im.PushMessageResp, error) {
fmt.Printf("\n[Gateway] 收到 Worker 推送: %s\n", req.Content)
return &im.PushMessageResp{
Code: 0,
Message: "Gateway received: " + req.Content,
}, nil
}
func main() {
// 1. 启动 Gateway RPC 服务(供 Worker 回调)
addr, _ := net.ResolveTCPAddr("tcp", "127.0.0.1:8888")
svr := imgatewayservice.NewServer(
new(GatewayServiceHandler),
server.WithServiceAddr(addr),
)
go func() {
fmt.Println("[Gateway] RPC 服务启动在 127.0.0.1:8888")
if err := svr.Run(); err != nil {
log.Fatalf("[Gateway] 服务启动失败: %v", err)
}
}()
// 2. 创建 Worker 服务的客户端
workerClient := imworkerservice.MustNewClient(
"ImWorkerService",
client.WithHostPorts("127.0.0.1:9999"),
)
fmt.Println("[Gateway] Worker 客户端已创建")
// 3. 命令行输入循环
scanner := bufio.NewScanner(os.Stdin)
fmt.Println("\n========================================")
fmt.Println(" IM Demo - Gateway")
fmt.Println(" 输入消息后按回车,Worker 会处理并回调")
fmt.Println(" 输入 'exit' 退出")
fmt.Println("========================================")
for {
fmt.Print("\n📝 请输入消息: ")
if !scanner.Scan() {
break
}
input := strings.TrimSpace(scanner.Text())
if input == "exit" {
fmt.Println("[Gateway] 退出")
break
}
if input == "" {
continue
}
// 4. 调用 Worker 的 SendMessage RPC
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
resp, err := workerClient.SendMessage(ctx, &im.SendMessageReq{
Content: input,
})
cancel()
if err != nil {
fmt.Printf("[Gateway] 调用 Worker 失败: %v\n", err)
continue
}
fmt.Printf("[Gateway] Worker 响应: code=%d, msg=%s\n", resp.Code, resp.Message)
}
}
再一个后端的worker,提供服务,服务里提供方法:SendMessage
Go
package main
import (
"context"
"demo-im/bird-proto/gen/im"
"demo-im/bird-proto/gen/im/imgatewayservice"
"demo-im/bird-proto/gen/im/imworkerservice"
"fmt"
"log"
"net"
"time"
"github.com/cloudwego/kitex/client"
"github.com/cloudwego/kitex/server"
)
// 实现 Worker 服务的 SendMessage 方法
type WorkerServiceHandler struct {
gatewayClient imgatewayservice.Client
}
func (h *WorkerServiceHandler) SendMessage(ctx context.Context, req *im.SendMessageReq) (*im.SendMessageResp, error) {
fmt.Printf("\n[Worker] 收到来自 Gateway 的消息: %s\n", req.Content)
// 1. 模拟处理(等待1秒)
time.Sleep(1 * time.Second)
fmt.Printf("[Worker] 消息处理完成: %s\n", req.Content)
// 2. 调用 Gateway 的 PushMessage RPC(添加前缀后回调)
pushContent := "[Worker-Processed] " + req.Content
fmt.Printf("[Worker] 正在回调 Gateway: %s\n", pushContent)
pushResp, err := h.gatewayClient.PushMessage(ctx, &im.PushMessageReq{
Content: pushContent,
})
if err != nil {
fmt.Printf("[Worker] 回调 Gateway 失败: %v\n", err)
return &im.SendMessageResp{
Code: 1,
Message: "回调失败: " + err.Error(),
}, nil
}
fmt.Printf("[Worker] Gateway 回调响应: %s\n", pushResp.Message)
return &im.SendMessageResp{
Code: 0,
Message: "消息已处理并推送",
}, nil
}
func main() {
// 1. 创建 Gateway 服务的客户端(用于回调)
gatewayClient := imgatewayservice.MustNewClient(
"ImGatewayService",
client.WithHostPorts("127.0.0.1:8888"),
)
fmt.Println("[Worker] Gateway 客户端已创建")
// 2. 启动 Worker RPC 服务
addr, _ := net.ResolveTCPAddr("tcp", "127.0.0.1:9999")
svr := imworkerservice.NewServer(
&WorkerServiceHandler{
gatewayClient: gatewayClient,
},
server.WithServiceAddr(addr),
)
fmt.Println("[Worker] RPC 服务启动在 127.0.0.1:9999")
fmt.Println("[Worker] 等待 Gateway 调用...")
if err := svr.Run(); err != nil {
log.Fatalf("[Worker] 服务启动失败: %v", err)
}
}
执行命令
bash
go mod init
go mod tidy
# 一个cmd内
go run ./gateway.go
# 一个cmd内
go run ./worker.go
在 Gateway 终端输入任意消息(如 hello),观察两个终端的输出:
Gateway 终端:
text
========================================
IM Demo - Gateway
输入消息后按回车,Worker 会处理并回调
输入 'exit' 退出
========================================
📝 请输入消息: hello
[Gateway] 收到 Worker 推送: [Worker-Processed] hello
[Gateway] Worker 响应: code=0, msg=消息已处理并推送
Worker 终端:
text
[Worker] 收到来自 Gateway 的消息: hello
[Worker] 消息处理完成: hello
[Worker] 正在回调 Gateway: [Worker-Processed] hello
[Worker] Gateway 回调响应: Gateway received: [Worker-Processed] hello
到此为止,我们已经能用Ketix写RPC调用了,注意这里示范使用了其内置的封装协议比grpc更高效。
未完待续,后文我们测试使用etcd做服务发现。