go kratos 微服务框架(笔记一)

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 是一个 轻量级插件化的微服务框架. 使用者插入第三方库使用,灵活度更大

数据库:

  • database/sql 官方库
  • gorm
  • ent

缓存:

  • go-redis
  • redigo
  • gomemcache

消息队列:

  • sarama kafka客户端
  • kafka-go

5 CLI工具

kratos命令目前主要用于从模板创建项目,维护依赖包版本等。具体请参考文档

6. Protobuf定义API

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

7. 元信息传递

服务之间的API调用,如果有某些元信息需要传递过去,而不是写在payload消息中,可以使用Metadata包进行字段设置和提取,具体细节参考元信息传递文档

8. 错误处理

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

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

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

9.配置文件

Kratos提供了统一的接口,支持配置文件的加载和变更订阅。

通过实现Source 和 Watcher即可实现任意配置源(本地或远程)的配置文件加载和变更订阅。

已经实现了下列插件:

  • file 本地文件加载,Kratos内置
  • apollo
  • etcd
  • kubernetes
  • nacos

10. 服务注册&服务发现

Kratos定义了统一的注册接口,通过实现Registrar和Discovery,您可以很轻松地将Kratos接入到您的注册中心中。

您也可以直接使用我们已经实现好的插件:

  • consul
  • discovery
  • etcd
  • kubernetes
  • nacos
  • zookeeper

11.日志

Kratos的日志模块由两部分组成:

  1. Logger:底层日志接口,用于快速适配各种日志库到框架中来,仅提供一个最简单的Log方法。
  2. Helper:高级日志接口,提供了一系列带有日志等级和格式化方法的帮助函数,通常业务逻辑中建议使用这个,能够简化日志代码。

我们已经实现好的插件用于适配目前一些日志库,您也可以参考它们的代码来实现自己需要的日志库的适配:

  • std 标准输出,Kratos内置
  • fluent
  • zap

12. 监控

监控告警方面,您可以通过实现metrics相关接口将服务的统计数据上报给监控平台。

也可以直接使用我们已经实现好的插件:

  • datadog
  • prometheus

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-layout 作为使用 kratos new 新建项目时所使用结构,其中包括了开发过程中所需的配套工具链( Makefile 等),便于开发者更高效地维护整个项目,本项目亦可作为使用 Kratos 构建微服务的工程化最佳实践的参考。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MamWmiNH-1671006695146)(image/Kratos微服务框架/1671002891484.png)]

20. 使用如下命令即可基于 kratos-layout 创建项目:

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

21.推荐阅读

  • Go 工程化 - Project Layout 最佳实践
  • Kratos 学习笔记 - 通过 layout 简单分析应用是如何跑起来的

你可能感兴趣的:(微服务框架,微服务,架构)