B站基于Golang实现的一个轻量级开源的面向微服务的框架.
Kratos框架不限制您使用任何第三方库来进行项目开发,因此您可以根据喜好来选择库进行集成。我们也会逐步针对更多被广泛使用的第三方库开发插件。
https://go-kratos.dev/docs/
特性:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i17ntljO-1671006695145)(image/Kratos微服务框架/1670998161976.png)]
kratos 是一个 轻量级插件化的微服务框架. 使用者插入第三方库使用,灵活度更大
数据库:
缓存:
消息队列:
kratos命令目前主要用于从模板创建项目,维护依赖包版本等。具体请参考文档
Kratos使用Protobuf进行API定义. 在使用Kratos的项目中,您将使用如下的IDL进行您的接口定义,并且通过 protoc
工具生成相应的 .pb.go
文件,其中包含根据定义生成的服务端和客户端代码。随后您就可以在自己的项目内部注册服务端代码使用,或引用客户端代码进行远程调用.
Kratos默认仅生成gRPC接口的代码,如果需要生成HTTP代码,请在proto文件中使用 option (google.api.http)
来添加HTTP部分的定义后再进行生成。默认情况下,HTTP接口将使用JSON作为序列化格式,如果想使用其它序列化格式(form,XML等),请参考文档序列化进行相应的配置即可!
syntax = "proto3";
package helloworld.v1;
import "google/api/annotations.proto";
option go_package = "github.com/go-kratos/kratos-layout/api/helloworld/v1;v1";
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {
option (google.api.http) = {
get: "/helloworld/{name}"
};
}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
服务之间的API调用,如果有某些元信息需要传递过去,而不是写在payload消息中,可以使用Metadata包进行字段设置和提取,具体细节参考元信息传递文档
Kratos的errors模块提供了error的封装。框架也预定义了一系列标准错误供使用。
错误处理这一块的设计也经过了很久的讨论才定下来,主要设计理念如下:
code
语义近似HTTP的Status Code(例如客户端传参数错误用400)同时也作为大类错误,在HTTP接口中的HTTP Code会使用它,好处是网关层可以根据这个code触发相应策略(重试、限流、熔断等)。reason
业务的具体错误码,为可读的字符串,能够表明,在同一个服务中应该唯一。message
用户可读的信息,可以在客户端(App、浏览器等)进行相应的展示给用户看。metadata
为一些附加信息,可以作为补充信息使用。在API返回的错误信息中,以HTTP接口为例,消息结构大概是长这个样子的:
{
// 错误码,跟 http-status 一致,并且在 grpc 中可以转换成 grpc-status
"code": 500,
// 错误原因,定义为业务判定错误码
"reason": "USER_NOT_FOUND",
// 错误信息,为用户可读的信息,可作为用户提示内容
"message": "invalid argument error",
// 错误元信息,为错误添加附加可扩展信息
"metadata": {"some-key": "some-value"}
}
在Kratos中您可以使用proto文件定义您的业务错误,并通过工具生成对应的处理逻辑和方法。(如使用layout中提供的 make errors
指令。)
syntax = "proto3";
package api.blog.v1;
import "errors/errors.proto";
option go_package = "github.com/go-kratos/examples/blog/api/v1;v1";
enum ErrorReason {
// 设置缺省错误码
option (errors.default_code) = 500;
// 为某个枚举单独设置错误码
USER_NOT_FOUND = 0 [(errors.code) = 404];
CONTENT_MISSING = 1 [(errors.code) = 400];;
}
// 通过 errors.New() 响应错误
errors.New(500, "USER_NAME_EMPTY", "user name is empty")
// 通过 proto 生成的代码响应错误,并且包名应替换为自己生成代码后的 package name
api.ErrorUserNotFound("user %s not found", "kratos")
// 传递metadata
err := errors.New(500, "USER_NAME_EMPTY", "user name is empty")
err = err.WithMetadata(map[string]string{
"foo": "bar",
})
err := wrong()
// 通过 errors.Is() 断言
if errors.Is(err,errors.BadRequest("USER_NAME_EMPTY","")) {
// do something
}
// 通过判断 *Error.Reason 和 *Error.Code
e := errors.FromError(err)
if e.Reason == "USER_NAME_EMPTY" && e.Code == 500 {
// do something
}
// 通过 proto 生成的代码断言错误,并且包名应替换为自己生成代码后的 package name
if api.IsUserNotFound(err) {
// do something
})
Kratos提供了统一的接口,支持配置文件的加载和变更订阅。
通过实现Source 和 Watcher即可实现任意配置源(本地或远程)的配置文件加载和变更订阅。
已经实现了下列插件:
Kratos定义了统一的注册接口,通过实现Registrar和Discovery,您可以很轻松地将Kratos接入到您的注册中心中。
您也可以直接使用我们已经实现好的插件:
Kratos的日志模块由两部分组成:
我们已经实现好的插件用于适配目前一些日志库,您也可以参考它们的代码来实现自己需要的日志库的适配:
监控告警方面,您可以通过实现metrics相关接口将服务的统计数据上报给监控平台。
也可以直接使用我们已经实现好的插件:
Kratos使用OpenTelemetry作为分布式链路追踪所使用的标准,您可以通过对client和server配置tracing来将服务接入到链路追踪平台(如jaeger等),从而对服务的接口调用关系,耗时,错误等进行追踪。
Kratos内置了若干种负载均衡算法,如Weighted round robin(默认)、P2C,Random等,您可以通过在client初始化时配置来使用他们。
Kratos提供了限流ratelimit和熔断circuitbreaker中间件,用于微服务出现异常故障时自动对流量进行限制,提升服务的健壮性,避免雪崩。
这两个中间件使用的算法,也可以在我们的可用性算法仓库aegis中找到,独立于Kratos直接使用。
您可以通过Kratos的middleware机制,统一微服务接口的某些共同逻辑。上面提到的功能插件,您可以通过实现Middleware编写Kratos能够使用的中间件。
同时在仓库的middleware目录下,我们也提供了一系列中间件供您使用。
除了上述提到的插件外,我们还提供了一些其它插件,完整的插件列表请参考文档社区插件
如果您看过文档后,对某些功能的使用仍有疑惑,或者是希望寻找一些用Kratos写项目的灵感,在examples仓库的目录下我们提供了很多代码供参考。
您也可以通过文档中的示例代码清单页面来查阅有哪些示例。
我们创建了 kratos-layout 作为使用 kratos new
新建项目时所使用结构,其中包括了开发过程中所需的配套工具链( Makefile 等),便于开发者更高效地维护整个项目,本项目亦可作为使用 Kratos 构建微服务的工程化最佳实践的参考。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MamWmiNH-1671006695146)(image/Kratos微服务框架/1671002891484.png)]
kratos new
生成的目录结构如下:
.
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── api // 下面维护了微服务使用的proto文件以及根据它们所生成的go文件
│ └── helloworld
│ └── v1
│ ├── error_reason.pb.go
│ ├── error_reason.proto
│ ├── error_reason.swagger.json
│ ├── greeter.pb.go
│ ├── greeter.proto
│ ├── greeter.swagger.json
│ ├── greeter_grpc.pb.go
│ └── greeter_http.pb.go
├── cmd // 整个项目启动的入口文件
│ └── server
│ ├── main.go
│ ├── wire.go // 我们使用wire来维护依赖注入
│ └── wire_gen.go
├── configs // 这里通常维护一些本地调试用的样例配置文件
│ └── config.yaml
├── generate.go
├── go.mod
├── go.sum
├── internal // 该服务所有不对外暴露的代码,通常的业务逻辑都在这下面,使用internal避免错误引用
│ ├── biz // 业务逻辑的组装层,类似 DDD 的 domain 层,data 类似 DDD 的 repo,而 repo 接口在这里定义,使用依赖倒置的原则。
│ │ ├── README.md
│ │ ├── biz.go
│ │ └── greeter.go
│ ├── conf // 内部使用的config的结构定义,使用proto格式生成
│ │ ├── conf.pb.go
│ │ └── conf.proto
│ ├── data // 业务数据访问,包含 cache、db 等封装,实现了 biz 的 repo 接口。我们可能会把 data 与 dao 混淆在一起,data 偏重业务的含义,它所要做的是将领域对象重新拿出来,我们去掉了 DDD 的 infra层。
│ │ ├── README.md
│ │ ├── data.go
│ │ └── greeter.go
│ ├── server // http和grpc实例的创建和配置
│ │ ├── grpc.go
│ │ ├── http.go
│ │ └── server.go
│ └── service // 实现了 api 定义的服务层,类似 DDD 的 application 层,处理 DTO 到 biz 领域实体的转换(DTO -> DO),同时协同各类 biz 交互,但是不应处理复杂逻辑
│ ├── README.md
│ ├── greeter.go
│ └── service.go
└── third_party // api 依赖的第三方proto
├── README.md
├── google
│ └── api
│ ├── annotations.proto
│ ├── http.proto
│ └── httpbody.proto
└── validate
├── README.md
└── validate.proto