Go 微服務(wù)工具包 Go kit 怎么集成 gRPC?
01介紹
我們在上一篇文章「??Go 語言基于 Go kit 開發(fā) Web 項目??」中,介紹了怎么使用 Go kit 開發(fā) Web 項目,在這篇文章中,我們傳輸層使用的是 HTTP,本文我們介紹 Go kit 怎么集成 gRPC,也就是說我們在傳輸層使用 rpc。
在閱讀完前面幾篇文章后,我們已經(jīng)了解 Go kit 分為三層,分別是 Transport、Endpoint 和 Service,其中 Transport 負責(zé)網(wǎng)絡(luò)傳輸,Endpoint 負責(zé)接收請求和返回響應(yīng),Service 層負責(zé)定義業(yè)務(wù)接口,并實現(xiàn)接口方法。
Go kit 集成 gRPC,主要在 Transport 層實現(xiàn)。
02實現(xiàn)原理
Go kit 集成 gRPC,即將 gRPC 集成到 Go kit 的 Transport 層。Transport 層將接收到的網(wǎng)絡(luò)請求轉(zhuǎn)換為 Endpoint 層可以處理的對象,主要需要實現(xiàn)兩個功能,解碼和編碼。
其中,解碼負責(zé)把網(wǎng)絡(luò)請求轉(zhuǎn)換為 Endpoint 可以處理的請求對象;編碼負責(zé)將 Endpoint 處理結(jié)果轉(zhuǎn)換為響應(yīng)對象,返回給客戶端。
03Go kit 集成 gRPC 的示例項目
在了解完實現(xiàn)原理之后,我們通過示例項目介紹 Go kit 怎么集成 gRPC,關(guān)于定義 proto 文件,和使用 protoc 生成 pb 文件,我們在之前的文章中已經(jīng)介紹過,限于篇幅,本文不再贅述。
使用 Go kit 集成 gRPC,實際上就是在 Transport 層使用 gRPC 傳輸,除此之外,它和我們上一節(jié)講的使用 Go kit 開發(fā) Web 項目的流程是一樣的,共分為五個步驟實現(xiàn)該示例項目,分別是定義 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
閱讀上面這段代碼,我們定義一個 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")
}
閱讀上面這段代碼,我們在 Service 層創(chuàng)建 IUser 接口,接口包含一個方法 Register,需要注意的是,Register 方法會通過調(diào)用 grpc.Handler 的 ServeGRPC 方法,將請求參數(shù)傳遞給 Go kit 處理。
Endpoint - 接收請求和返回響應(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 層的接口的方法處理請求。
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,
),
}
}
閱讀上面這段代碼,我們在 Transport 層實現(xiàn) pb 文件中的 UserServiceServer 方法,需要注意的是,我們在 NewUserService 函數(shù)中,傳入 Endpoint。
完整代碼,請參閱 Github。
04總結(jié)
本文我們通過示例項目介紹 Go kit 怎么集成 gRPC,通過集成 gRPC,Transport 層實現(xiàn)通過 rpc 進行網(wǎng)絡(luò)傳輸。