0%

kratos微服务框架

Kratos 一套轻量级 Go 微服务框架,包含大量微服务相关框架及工具。

1. 介绍

1.1 特性

  • 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 :实现统一注册中心接口,可插件化对接各种注册中心;
  • Validation: 通过 Protobuf 统一定义校验规则,并同时适用于 HTTP/gRPC 服务.
  • SwaggerAPI: 通过集成第三方 Swagger插件 能够自动生成 Swagger API json 并启动一个内置的 Swagger UI 服务.

1.2 架构

500

1.3 代码结构

可参考这个项目: https://github.com/go-kratos/kratos-layout

它包含一个参考了 DDD 和简洁架构设计的项目结构、Makefile 脚本和 Dockerfile 文件。但这个项目模板不是必需的,您可以任意修改它,或使用自己设计的项目结构,Kratos 依然可以正常工作。框架本身不对项目结构做任何假设和限制,您可以按照自己的想法来使用,具有很强的可定制性。

使用如下命令即可基于 kratos-layout 创建项目: kratos new projiect-name

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
  .
├── 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

2. 使用

2.1 proto文件

Kratos 默认仅生成 gRPC 接口的代码,如果需要生成 HTTP 代码,请在 proto 文件中使用 option (google.api.http) 来添加 HTTP 部分的定义后再进行生成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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;
}

2.2 生成 proto

1
2
3
4
5
6
7
8
9

# 生成proto模板
kratos proto add api/helloworld/helloworld.proto

# 生成proto源码
kratos proto client api/helloworld/helloworld.proto

# 生成server模板
kratos proto server api/helloworld/helloworld.proto -t internal/service

2.3 错误

Kratos 的 errors 模块提供了 error 的封装。框架也预定义了一系列 标准错误 供使用。

错误处理这一块的设计也经过了很久的讨论才定下来,主要设计理念如下:

  1. code 语义近似 HTTP 的 Status Code(例如客户端传参数错误用 400)同时也作为大类错误,在 HTTP 接口中的 HTTP Code 会使用它,好处是网关层可以根据这个 code 触发相应策略(重试、限流、熔断等)。
  2. reason 业务的具体错误码,为可读的字符串,能够表明,在同一个服务中应该唯一。
  3. message 用户可读的信息,可以在客户端(App、浏览器等)进行相应的展示给用户看。
  4. metadata 为一些附加信息,可以作为补充信息使用。

在 API 返回的错误信息中,以 HTTP 接口为例,消息结构大概是长这个样子的:

1
2
3
4
5
6
7
8
9
10
{
// 错误码,跟 http-status 一致,并且在 grpc 中可以转换成 grpc-status
"code": 500,
// 错误原因,定义为业务判定错误码
"reason": "USER_NOT_FOUND",
// 错误信息,为用户可读的信息,可作为用户提示内容
"message": "invalid argument error",
// 错误元信息,为错误添加附加可扩展信息
"metadata": {"some-key": "some-value"}
}

3. 参考文档

给作者打赏,可以加首页微信,咨询作者相关问题!