Kratos 微服务框架
1.简介
B站基于Golang实现的一个轻量级开源的面向微服务的框架.
Kratos框架不限制您使用任何第三方库来进行项目开发,因此您可以根据喜好来选择库进行集成。我们也会逐步针对更多被广泛使用的第三方库开发插件。
2.官方文档
https://go-kratos.dev/docs/
3.架构图
特性:
- APIs:协议通信以 HTTP/gRPC 为基础,通过 Protobuf 进行定义;
- Errors:通过 Protobuf 的 Enum 作为错误码定义,以及工具生成判定接口;
- Metadata:在协议通信 HTTP/gRPC 中,通过 Middleware 规范化服务元信息传递;
- Config:支持多数据源方式,进行配置合并铺平,通过 Atomic 方式支持动态配置;
- Logger:标准日志接口,可方便集成三方 log 库,并可通过 fluentd 收集日志;
- Metrics:统一指标接口,可以实现各种指标系统,默认集成 Prometheus;
- Tracing:遵循 OpenTelemetry 规范定义,以实现微服务链路追踪;
- Encoding:支持 Accept 和 Content-Type 进行自动选择内容编码;
- Transport:通用的 HTTP/gRPC 传输层,实现统一的 Middleware 插件支持;
- Registry:实现统一注册中心接口,可插件化对接各种注册中心;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i17ntljO-1671006695145)(image/Kratos微服务框架/1670998161976.png)]
4. 广泛使用的库
kratos 是一个 轻量级插件化的微服务框架. 使用者插入第三方库使用,灵活度更大
数据库:
缓存:
消息队列:
5 CLI工具
kratos命令目前主要用于从模板创建项目,维护依赖包版本等。具体请参考文档
6. Protobuf定义API
protoc.pb.go
option (google.api.http)
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;
}
7. 元信息传递
服务之间的API调用,如果有某些元信息需要传递过去,而不是写在payload消息中,可以使用Metadata包进行字段设置和提取,具体细节参考元信息传递文档
8. 错误处理
Kratos的errors模块提供了error的封装。框架也预定义了一系列标准错误供使用。
错误处理这一块的设计也经过了很久的讨论才定下来,主要设计理念如下:
codereasonmessagemetadata
在API返回的错误信息中,以HTTP接口为例,消息结构大概是长这个样子的:
{
// 错误码,跟 http-status 一致,并且在 grpc 中可以转换成 grpc-status
"code": 500,
// 错误原因,定义为业务判定错误码
"reason": "USER_NOT_FOUND",
// 错误信息,为用户可读的信息,可作为用户提示内容
"message": "invalid argument error",
// 错误元信息,为错误添加附加可扩展信息
"metadata": {"some-key": "some-value"}
}
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
})
9.配置文件
Kratos提供了统一的接口,支持配置文件的加载和变更订阅。
通过实现Source 和 Watcher即可实现任意配置源(本地或远程)的配置文件加载和变更订阅。
已经实现了下列插件:
10. 服务注册&服务发现
Kratos定义了统一的注册接口,通过实现Registrar和Discovery,您可以很轻松地将Kratos接入到您的注册中心中。
您也可以直接使用我们已经实现好的插件:
11.日志
Kratos的日志模块由两部分组成:
我们已经实现好的插件用于适配目前一些日志库,您也可以参考它们的代码来实现自己需要的日志库的适配:
12. 监控
监控告警方面,您可以通过实现metrics相关接口将服务的统计数据上报给监控平台。
也可以直接使用我们已经实现好的插件:
13. 链路追踪
Kratos使用OpenTelemetry作为分布式链路追踪所使用的标准,您可以通过对client和server配置tracing来将服务接入到链路追踪平台(如jaeger等),从而对服务的接口调用关系,耗时,错误等进行追踪。
14. 负载均衡
Kratos内置了若干种负载均衡算法,如Weighted round robin(默认)、P2C,Random等,您可以通过在client初始化时配置来使用他们。
15.限流熔断
Kratos提供了限流ratelimit和熔断circuitbreaker中间件,用于微服务出现异常故障时自动对流量进行限制,提升服务的健壮性,避免雪崩。
这两个中间件使用的算法,也可以在我们的可用性算法仓库aegis中找到,独立于Kratos直接使用。
16. 中间件
您可以通过Kratos的middleware机制,统一微服务接口的某些共同逻辑。上面提到的功能插件,您可以通过实现Middleware编写Kratos能够使用的中间件。
同时在仓库的middleware目录下,我们也提供了一系列中间件供您使用。
17. 插件
除了上述提到的插件外,我们还提供了一些其它插件,完整的插件列表请参考文档社区插件
18.示例代码
如果您看过文档后,对某些功能的使用仍有疑惑,或者是希望寻找一些用Kratos写项目的灵感,在examples仓库的目录下我们提供了很多代码供参考。
您也可以通过文档中的示例代码清单页面来查阅有哪些示例。
19.项目结构
kratos new
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MamWmiNH-1671006695146)(image/Kratos微服务框架/1671002891484.png)]
20. 使用如下命令即可基于 kratos-layout 创建项目:
kratos new <project-name>
生成的目录结构如下:
.
├── 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