Go 微服務(wù)工具包 Go kit 怎么集成 gRPC?
01介紹
我們?cè)谏弦黄恼隆??Go 語(yǔ)言基于 Go kit 開(kāi)發(fā) Web 項(xiàng)目??」中,介紹了怎么使用 Go kit 開(kāi)發(fā) Web 項(xiàng)目,在這篇文章中,我們傳輸層使用的是 HTTP,本文我們介紹 Go kit 怎么集成 gRPC,也就是說(shuō)我們?cè)趥鬏攲邮褂?rpc。
在閱讀完前面幾篇文章后,我們已經(jīng)了解 Go kit 分為三層,分別是 Transport、Endpoint 和 Service,其中 Transport 負(fù)責(zé)網(wǎng)絡(luò)傳輸,Endpoint 負(fù)責(zé)接收請(qǐng)求和返回響應(yīng),Service 層負(fù)責(zé)定義業(yè)務(wù)接口,并實(shí)現(xiàn)接口方法。
Go kit 集成 gRPC,主要在 Transport 層實(shí)現(xiàn)。
02實(shí)現(xiàn)原理
Go kit 集成 gRPC,即將 gRPC 集成到 Go kit 的 Transport 層。Transport 層將接收到的網(wǎng)絡(luò)請(qǐng)求轉(zhuǎn)換為 Endpoint 層可以處理的對(duì)象,主要需要實(shí)現(xiàn)兩個(gè)功能,解碼和編碼。
其中,解碼負(fù)責(zé)把網(wǎng)絡(luò)請(qǐng)求轉(zhuǎn)換為 Endpoint 可以處理的請(qǐng)求對(duì)象;編碼負(fù)責(zé)將 Endpoint 處理結(jié)果轉(zhuǎn)換為響應(yīng)對(duì)象,返回給客戶(hù)端。
03Go kit 集成 gRPC 的示例項(xiàng)目
在了解完實(shí)現(xiàn)原理之后,我們通過(guò)示例項(xiàng)目介紹 Go kit 怎么集成 gRPC,關(guān)于定義 proto 文件,和使用 protoc 生成 pb 文件,我們?cè)谥暗奈恼轮幸呀?jīng)介紹過(guò),限于篇幅,本文不再贅述。
使用 Go kit 集成 gRPC,實(shí)際上就是在 Transport 層使用 gRPC 傳輸,除此之外,它和我們上一節(jié)講的使用 Go kit 開(kāi)發(fā) Web 項(xiàng)目的流程是一樣的,共分為五個(gè)步驟實(shí)現(xiàn)該示例項(xiàng)目,分別是定義 proto 并生成 pb 文件、創(chuàng)建 service 層、創(chuàng)建 endpoint 層、創(chuàng)建 transport 層和定義主函數(shù)。
定義 proto
option go_package = "./user";
service UserService {
rpc Register(RegisterReq) returns (RegisterRes) {}
}
生成 pb 文件
protoc -I proto \
> --go_out ./pb/user --go_opt paths=source_relative \
> --go-grpc_out=require_unimplemented_servers=false:./pb/user --go-grpc_opt paths=source_relative \
> proto/user.proto
閱讀上面這段代碼,我們定義一個(gè) proto 文件,并使用 protoc 工具生成 pb 文件,需要注意的是我們將 require_unimplemented_servers 設(shè)置為 false。
原因如下:
- By default, to register services using the methods generated by this tool, the service implementations must embed the corresponding UnimplementedServer for future compatibility. This is a behavior change from the grpc code generator previously included with protoc-gen-go. To restore this behavior, set the option require_unimplemented_servers=false.
Service - 定義接口
type IUser interface {
Register(ctx context.Context, username, email, password string) error
}
type User struct{}
func (u User) Register(ctx context.Context, username, email, password string) error {
if username != "" && email != "" && password != "" {
return nil
}
return errors.New("register param is invalid")
}
閱讀上面這段代碼,我們?cè)?Service 層創(chuàng)建 IUser 接口,接口包含一個(gè)方法 Register,需要注意的是,Register 方法會(huì)通過(guò)調(diào)用 grpc.Handler 的 ServeGRPC 方法,將請(qǐng)求參數(shù)傳遞給 Go kit 處理。
Endpoint - 接收請(qǐng)求和返回響應(yīng)
func MakeUserEndpoint(user IUser) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (response interface{}, err error) {
req := request.(RegisterReq)
err = user.Register(ctx, req.Username, req.Email, req.Password)
if err != nil {
log.Printf("err:%s", err)
}
return RegisterRes{
Username: req.Username,
Email: req.Email,
}, nil
}
}
閱讀上面這段代碼,在 Endpoint 層,我們給業(yè)務(wù)接口 IUser 構(gòu)建 endpoint.Endpoint,用于調(diào)用 Service 層的接口的方法處理請(qǐng)求。
Transport - 傳輸層
type grpcHandler struct {
register grpc.Handler
}
func (g *grpcHandler) Register(ctx context.Context, req *pb.RegisterReq) (*pb.RegisterRes, error) {
_, res, err := g.register.ServeGRPC(ctx, req)
if err != nil {
return nil, err
}
return res.(*pb.RegisterRes), nil
}
func NewUserServer(ctx context.Context, endpoints Endpoints) pb.UserServiceServer {
return &grpcHandler{
register: grpc.NewServer(
endpoints.UserEndpoint,
DecodeRegister,
EncodeRegister,
),
}
}
閱讀上面這段代碼,我們?cè)?Transport 層實(shí)現(xiàn) pb 文件中的 UserServiceServer 方法,需要注意的是,我們?cè)? NewUserService 函數(shù)中,傳入 Endpoint。
完整代碼,請(qǐng)參閱 Github。
04總結(jié)
本文我們通過(guò)示例項(xiàng)目介紹 Go kit 怎么集成 gRPC,通過(guò)集成 gRPC,Transport 層實(shí)現(xiàn)通過(guò) rpc 進(jìn)行網(wǎng)絡(luò)傳輸。





































