当前位置: 代码网 > it编程>编程语言>Java > [Go 微服务] Kratos 使用的简单总结

[Go 微服务] Kratos 使用的简单总结

2024年07月31日 Java 我要评论
Kratos 使用的简单总结

1.kratos 简介

kratos并不绑定于特定的基础设施,不限定于某种注册中心,或数据库orm等,所以您可以十分轻松地将任意库集成进项目里,与kratos共同运作。

在这里插入图片描述
api -> service(wire) -> db

  1. 可以看到kratos将整个服务大体分为了3层,api / service / db。
  2. 左侧标注了在 service和db层,使用依赖注入(di)进行实现,工具名称为wire。
  3. 可以看到wire这个工具几乎贯穿kratos架构始终,是一个大角色。

2.传输协议

支持http + grpc两种调用方式,通过编写proto文件来实现。

一般,http开放给外部调用,可以使用restful风格定义。grpc面向内部微服务之间进行调用。

在这里插入图片描述

​ 在项目中,会以这样的结构出现,并且可以对不同协议进来的请求进行处理,添加处理的中间件,如权限校验、熔断限流等等。

3.日志

在kratos中,可以自定义日志框架选型,设置日志格式和输出内容,然后将logger对象以依赖注入的方式,分配给server中的grpc server和http server,这样就可以实现每次收到请求后的日志打印。

将logger对象以依赖注入的方式,注入到业务层,就可以在业务层中统一使用logger进行输出。

4.错误处理

在grpc中,比较通用的一种错误处理方式就是直接通过 proto 预定义定义错误码,然后通过 proto-gen-go 生成帮助代码,直接返回 error。

{
    // 错误码,跟 http-status 一致,并且在 grpc 中可以转换成 grpc-status
    "code": 500,
    // 错误原因,定义为业务判定错误码
    "reason": "user_not_found",
    // 错误信息,为用户可读的信息,可作为用户提示内容
    "message": "invalid argument error",
    // 错误元信息,为错误添加附加可扩展信息
    "metadata": {
      "foo": "bar"
    }
}

这里可以发现,为了兼容grpc,在http的返回结果中,code也无法自定义,只能跟随httpcode。所以这里客户端或者第三方去处理错误时,需要判断reason字段。

5.配置管理

使用proto文件定义配置和生成struct,然后将yaml中的内容读取到对应struct 字段中进行使用。

在这里我们可以注意到,在kratos中,除了传输格式使用了proto进行定义之外,错误处理和配置管理,也使用了proto来进行。可以说,一切皆proto。

6.wire

wire 是一个灵活的依赖注入工具(需要安装),通过自动生成代码的方式在编译期完成依赖注入。通过 wire 进行初始化代码,可以很好地解决组件之间的耦合,以及提高代码维护性。

打开kratos的示例项目,从main入口看,有一处调用了wireapp方法,这里就是一切的源头(万恶之源)。

这个方法调用的是main同目录的wire文件中的wireapp方法,同目录的wire_gen.go实现了此方法。

wire_gen中去实例化不同service和组建的对象,用于调用。关系图如下:

在这里插入图片描述

在这里插入图片描述

server -> service -> biz -> data

main.go -> wire.go(wire_gen.go)

在这里插入图片描述

wire.go 中有用到providerset

package main

import (
	"kratos-demo03/internal/biz"
	"kratos-demo03/internal/conf"
	"kratos-demo03/internal/data"
	"kratos-demo03/internal/server"
	"kratos-demo03/internal/service"

	"github.com/go-kratos/kratos/v2"
	"github.com/go-kratos/kratos/v2/log"
	"github.com/google/wire"
)

// wireapp init kratos application.
func wireapp(*conf.server, *conf.data, log.logger) (*kratos.app, func(), error) {
	panic(wire.build(server.providerset, data.providerset, biz.providerset, service.providerset, newapp))
}

main.go 有用到app和config

package main

import (
	"flag"
	"os"

	"kratos-demo03/internal/conf"

	"github.com/go-kratos/kratos/v2"
	"github.com/go-kratos/kratos/v2/config"
	"github.com/go-kratos/kratos/v2/config/file"
	"github.com/go-kratos/kratos/v2/log"
	"github.com/go-kratos/kratos/v2/middleware/tracing"
	"github.com/go-kratos/kratos/v2/transport/grpc"
	"github.com/go-kratos/kratos/v2/transport/http"

	_ "go.uber.org/automaxprocs"
)

// go build -ldflags "-x main.version=x.y.z"
var (
	// name is the name of the compiled software.
	name string
	// version is the version of the compiled software.
	version string
	// flagconf is the config flag.
	flagconf string

	id, _ = os.hostname()
)

func init() {
	flag.stringvar(&flagconf, "conf", "../../configs", "config path, eg: -conf config.yaml")
}

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,
		),
	)
}

func main() {
	flag.parse()
	logger := log.with(log.newstdlogger(os.stdout),
		"ts", log.defaulttimestamp,
		"caller", log.defaultcaller,
		"service.id", id,
		"service.name", name,
		"service.version", version,
		"trace.id", tracing.traceid(),
		"span.id", tracing.spanid(),
	)
	c := config.new(
		config.withsource(
			file.newsource(flagconf),
		),
	)
	defer c.close()

	if err := c.load(); err != nil {
		panic(err)
	}

	var bc conf.bootstrap
	if err := c.scan(&bc); err != nil {
		panic(err)
	}

	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)
	}
}

在每个模块中,只需要一个 providerset 提供者集合,就可以在 wire 中进行依赖注入。

有一个数据库连接对象,service需要操作数据库,依赖数据库连接对象。这时候我们可以声明数据库连接对象在providerset集合,然后在service对象处声明,我需要一个数据库连接对象。 然后我们使用wire工具,就可以自动帮我们生成依赖注入的代码。

这里的依赖注入让代码间的依赖关系一目了然。只需要查看wire_gen.go代码就可以了解依赖关系。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com