go-kit是什么?

gokit是构建golang微服务的工具集,能够帮助我们构建基础的、可靠的、可扩展的微服务,使用go语言实现的。

架构设计

gk使用分层模式,如果你是从PHP、Ruby、Django等语言过渡到go语言,那么经典的MVC分层肯定很熟悉,gk的也分为三层:

1.Transport层 (传输)

2.Endpoint层 (终点)

3.Service层 (逻辑服务)

请求从1->3, 响应从3->1

Transports 层

transport 域会绑定到具体的传输协议上,例如:HTTP或者gRPC; 总而言之,微服务可能会支持多种传输协议;这是非常重要且强力的,可以在一个简单的微服务中支持HTTP API和 RPC service。

当实现一个Restful HTTP API时,路由定义在httptransport中. 设置的路由代码如下:


userRegisterHandler := httptransport.NewServer(selfendpoint.MakeUserRegisterHandler(s),decodeUserRegisterRequest,encodeUserRegisterResponse,opt...,)r := mux.NewRouter()r.Handle("/user/register", userRegisterHandler).Methods("POST")

Endpoints 层

endpoint 就像controller中的action/handler;该层是处理request和response的地方;如果你实现了两种transport (http/grpc), 那么两个方法会发送请求到相同的endpoint。代码会如下


// UserRegisterRequest 用户注册请求type UserRegisterRequest struct {Email stringFirstName stringLastNamestringPasswordstringConfirmPassword string}// UserRegisterResponse 用户注册响应type UserRegisterResponse struct {UID usermodel.UID `json:"uid,omitempty"`Err error `json:"err,omitempty"`}func MakeUserRegisterHandler(service user.UserService) endpoint.Endpoint {return func(ctx context.Context, request interface{}) (response interface{}, err error) {req := request.(UserRegisterRequest)uid, err := service.Register(gin.Context{}, req.Email, req.FirstName, req.LastName, req.Password, req.ConfirmPassword)return UserRegisterResponse{uid, err}, nil}}

Services层

service 层是所有业务逻辑实现的地方. service经常将多个endpoints粘合在一起.service 经常被声明为interface,为了实现业务逻辑去实现interface下的方法,可以采用六边形设计模式(Hexagonal Architecture). 业务逻辑不会关心endpoint或者特殊的transport域:services不应该知道任何关于http headers 或者 grpc error codes。代码块如下:


type UserService interface {Register(ctx gin.Context, email string, firstname string, lastname string, password string, confirmpassword string) (models.UID, error)}

Middlewares 中间件

gk 使用严格的分层,所以使用中间件模式来添加注入例如日志、请求频率、负载均衡、分布式tracing. 在endpoint和service层可以使用中间件。

设计

上图是官网摘录的,可以看到该图像个洋葱一样,有很多层。

所有的层可以归纳到3个域中:最里面的service域,中间的endpoint域,和最外层的transport域

为了实现business logic,我们在service层定义interface,并且提供一个实现logic.go


type UserLogic struct {repo UserRepository}var (ErrParamsEmpty = errors.New("request params empty")ErrUserAlreadyExists = errors.New("user already exists")ErrConfirmPassword = errors.New("confirm password conflict"))func NewUserLogic(repo UserRepository) UserService {return &UserLogic{repo: repo,}}func (u *UserLogic) Register(ctx gin.Context, email string, firstname string, lastname string, password string, confirmpassword string) (uid models.UID, err error) {if email == "" || firstname == "" || lastname == "" || password == "" || confirmpassword == "" {return uid, ErrParamsEmpty}// 查找用户是否存在,存在则报错existUser, err := u.repo.FindByEmail(email)if existUser != nil || err != nil {return uid, ErrUserAlreadyExists}if password != confirmpassword {return uid, ErrConfirmPassword}return u.repo.Create(ctx)}

我们可以在logic中注入middleware. 简而言之,gk严格的分层可以通过middleware来注入。