《从零单排Golang》系列,又重新开张了。后续会不定期更新自己学习Golang的笔记跟心得。
这次的话,就介绍一款名为奎爷kratos的微服务框架,以及讲述一下基础的使用机理。
kratos是B站开源的微服务框架,不仅提供了grpc、http协议支持,而且有较为完善的层级架构、微服务中间件以及第三方组件的编写约定,可以说是非常方便上手跟扩展。
要上手kratos,我们可以从两个地方入手:
通过kratos的quickstart文档,我们可以创建一个名为kratostest的项目。项目的目录结构遵循kratos-layout,具体如下:
api:接口定义,主要是proto文件
go文件给到internal或者service模块做请求处理实现的编写cmd:main.go与wire.goconfigs:配置yamlinternal:
biz:业务逻辑
controller或handler,则类似于service的概念service不是指kratos的serviceconf:配置data:数据访问server:对外服务service:类似于controller、handlerthird_party:第三方内容kratostest项目在启动之前,除了需要go-protobuf环境把proto文件编译成go文件之外,默认还需要通过wire模块自动初始化对象实例。wire是一种在golang里实现依赖注入的解决方案,可以参考以下文档,了解wire的作用:
从使用角度上来说,实际上经过了如下的步骤:
以http-server的基础greeter接口为例,存在着这样的调用层次:
NewHTTPServer:在internal/server/http.go,生成HTTPServer实例
conf.Server实例,是服务器启动的配置,可以通过internal/conf/conf.proto生成
configs/config.yaml实际配置这些内容*service.GreeterService,该实例需要实现GreeterHTTPServer的接口定义GreeterHTTPServer的接口定义实际是由greeter.proto定义之后自动生成的NewGreeterService:在internal/service/greeter.go,生成GreeterService实例
GreeterHTTPServer的接口定义biz层成员*biz.GreeterUsecase,在接口实现会调用这个成员方法执行实际业务NewGreeterUsecase:在internal/biz/greeter.go,生成GreeterUsecase实例
GreeterRepo类型成员,用来做数据的CRUDNewGreeterRepo:在internal/data/greeter.go,生成GreeterRepo实例
*Data类型成员,用来做实际对接数据库的访问操作NewData:在internal/data/data.go,生成*Data实例
conf.Data实例,是数据库的配置,可以通过internal/conf/conf.proto生成wire的ProviderSet,然后一并Build起来// cmd/kratostest/main.go
func newApp(logger log.Logger, gs *grpc.Server, hs *http.Server) *kratos.App {
return kratos.New(
kratos.ID(id),
kratos.Name(Name),
kratos.Version(Version),
kratos.Metadata(map[string]string{}),
kratos.Logger(logger),
kratos.Server(
gs,
hs,
),
)
}
// cmd/kratostest/wire.go
func wireApp(*conf.Server, *conf.Data, log.Logger) (*kratos.App, func(), error) {
panic(wire.Build(server.ProviderSet, data.ProviderSet, biz.ProviderSet, service.ProviderSet, newApp))
}
在cmd/kratostest执行了wire之后,就会把这些依赖注入,代码重新组装起来,最后生成wire_gen.go文件。
func wireApp(confServer *conf.Server, confData *conf.Data, logger log.Logger) (*kratos.App, func(), error) {
dataData, cleanup, err := data.NewData(confData, logger)
if err != nil {
return nil, nil, err
}
greeterRepo := data.NewGreeterRepo(dataData, logger)
greeterUsecase := biz.NewGreeterUsecase(greeterRepo, logger)
greeterService := service.NewGreeterService(greeterUsecase)
grpcServer := server.NewGRPCServer(confServer, greeterService, logger)
httpServer := server.NewHTTPServer(confServer, greeterService, logger)
app := newApp(logger, grpcServer, httpServer)
return app, func() {
cleanup()
}, nil
}
wire_gen.go的wireApp,最终会在main.go里实际执行,从而真正启动整个kratostest服务和各层的对象实例。
func main() {
// 忽略上面
app, cleanup, err := wireApp(bc.Server, bc.Data, logger)
if err != nil {
panic(err)
}
defer cleanup()
// start and wait for stop signal
if err := app.Run(); err != nil {
panic(err)
}
}
这样,整个kratos服务的基础逻辑结构就顺起来了。