由 Golang 实现的面向微服务的治理框架

名字来源于:《战神》游戏以希腊神话为背景,讲述奎托斯(Kratos)由凡人成为战神并展开弑神屠杀的冒险经历。

由 Golang 实现的面向微服务的治理框架

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

设计原理

  • 简单:不过度设计,代码平实简单
  • 通用:通用业务开发所需要的基础库的功能
  • 高效:提高业务迭代的效率
  • 稳定:基础库可测试性高,覆盖率高,有线上实践安全可靠
  • 健壮:通过良好的基础库设计,减少错用
  • 高性能:性能高,但不特定为了性能做 hack 优化,引入 unsafe
  • 扩展性:良好的接口设计,来扩展实现,或者通过新增基础库目录来扩展功能
  • 容错性:为失败设计,大量引入对 SRE 的理解,鲁棒性高
  • 工具链:包含大量工具链,比如 cache 代码生成,lint 工具等等

特性

APIs :协议通信以 HTTP/gRPC 为基础,通过 Protobuf 进行定义

API 与用户的通信协议,通常是 REST API 和 RPC API 作为传输层协议,而 Kratos 主要参考 Google API 指南,实现了对应通信协议支持,并且遵守了 gRPC API 使用 HTTP 映射功能进行 JSON/HTTP 的支持。

也就是通过定义 proto 即可使用 REST API 和 RPC API,通过类似 Google API 的仓库方式进行 API Schema 的管理。

定义接口:

通过 Protobuf IDL 定义对应的 REST API 和 gRPC API:api/helloworld/v1/greeter.proto

syntax = "proto3";

package helloworld.v1;

import "google/api/annotations.proto";

option go_package = "github.com/go-kratos/service-layout/api/helloworld/v1;v1";
option java_multiple_files = true;
option java_package = "dev.kratos.api.helloworld.v1";
option java_outer_classname = "HelloWorldProtoV1";

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply)  {
    option (google.api.http) = {
        // 定义一个 GET 接口,并且把 name 映射到 HelloRequest
        get: "/helloworld/{name}",
        // 可以添加附加接口
        additional_bindings {
            // 定义一个 POST 接口,并且把 body 映射到 HelloRequest
            post: "/v1/greeter/say_hello",
            body: "*",
        }
    };
  }
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

生成接口:

# 生成 proto 模板
kratos proto add api/helloworld/v1/greeter.proto
# 生成 client 源码
kratos proto client api/helloworld/v1/greeter.proto
# 生成 server 源码
kratos proto server api/helloworld/v1/greeter.proto -t internal/service
client:
|____api
| |____helloworld
| | |____v1
| | | |____greeter.pb.go
| | | |____greeter.proto
| | | |____greeter_http.pb.go
| | | |____greeter_grpc.pb.go

server:
| |____service
| | |____greeter.go

注册接口:

HTTP API 是通过 protoc-gen-go-http 插件进行生成 http.Handler,然后可以注册到 HTTP Server 中:

import "github.com/go-kratos/kratos/v2/transport/http"

greeter := &GreeterService{}
srv := http.NewServer(http.Address(":9000"))
v1.RegisterGreeterHTTPServer(srv, greeter)

gRPC API 是通过 protoc-gen-go-grpc 插件进行生成 gRPC Register,然后可以注册到 GRPC Server 中;

import "github.com/go-kratos/kratos/v2/transport/grpc"

greeter := &GreeterService{}
srv := grpc.NewServer(grpc.Address(":9000"))
v1.RegisterGreeterServer(srv, greeter)


Errors :通过 Protobuf 的 Enum 作为错误码定义,以及工具生成判定接口

APIs 响应错误时可以直接使用 errors 包中的 New 方法来声明一个 error,也可以直接通过 proto 预定义定义错误码,然后通过 proto-gen-go 生成帮助代码,直接返回 error。

在 errors 包中,错误模型主要跟 gRPC 状态码一致,并且 Error 实现了 GRPCStatus() 接口, 实现了 grpc 和 http 错误码的转换, 业务原因通过 ErrorInfo 返回:

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


Metadata :在协议通信 HTTP/gRPC 中,通过 Middleware 规范化服务元信息传递

微服务之间通过 HTTP 和 gRPC API 进行接口交互,服务架构需要使用统一的元信息(Metadata)传输进行微服务间的传递。目前 gRPC 中可以携带元信息传递,原理是将元信息放入 HTTP Header 中,这样上游即可收到对应的元信息 信息。因此在 Kratos 的设计上,也是通过 HTTP Header 进行传递。在框架中先将元信息包封装成 key/value 结构,然后携带到 Transport Header 中。

文档:https://go-kratos.dev/docs/component/metadata/


Config :支持多数据源方式,进行配置合并铺平,通过 Atomic 方式支持动态配置

微服务或者说云原生应用的配置最佳实践是将配置文件和应用代码分开管理——不将配置文件放入代码仓库,也不打包进容器镜像,而是在服务运行时,把配置文件挂载进去或者直接从配置中心加载。Kratos 的 config 组件就是用来帮助应用从各种配置源加载配置。

文档:https://go-kratos.dev/docs/component/config


Logger :标准日志接口,可方便集成三方 log 库,并可通过 fluentd 收集日志

为了方便使用,Kratos 定义了两个层面的抽象,Logger 统一了日志的接入方式,Helper 接口统一的日志库的调用方式。

在不同的公司、使用不同的基础架构,可能对日志的打印方式、格式、输出的位置等要求各有不同。Kratos 为了更加灵活地适配和迁移到各种环境,把日志组件也进行了抽象,这样就可以把业务代码里日志的使用,和日志底层具体的实现隔离开来,提高整体的可维护性。

Kratos 的日志库主要有如下特性:

  • Logger 用于对接各种日志库或日志平台,可以用现成的或者自己实现
  • Helper 是在您的项目代码中实际需要调用的,用于在业务代码里打日志
  • Filter 用于对输出日志进行过滤或魔改(通常用于日志脱敏)
  • Valuer 用于绑定一些全局的固定值或动态值(比如时间戳、traceID 或者实例 id 之类的东西)到输出日志中
文档:https://go-kratos.dev/docs/component/log/


Metrics :统一指标接口,可以实现各种指标系统,默认集成 Prometheus

Metrics 中间件用于实现服务的性能指标监控,统计了请求耗时和请求计数。

文档:https://go-kratos.dev/docs/component/middleware/metrics/


Tracing :遵循 OpenTelemetry 规范定义,以实现微服务链路追踪

Tracing 中间件使用 OpenTelemetry 实现了链路追踪。

文档:https://go-kratos.dev/docs/component/middleware/tracing/


Encoding :支持 Accept 和 Content-Type 进行自动选择内容编码

我们抽象出了 Codec 接口,用于统一处理请求的序列化/反序列化逻辑,您也可以实现您自己的 Codec 以便支持更多格式。

文档:https://go-kratos.dev/docs/component/encoding/


Transport :通用的 HTTP /gRPC 传输层,实现统一的 Middleware 插件支持

kratos 框架对传输层进行了抽象,用户可以通过实现接口来接入实现,框架默认实现了 gRPC 和 HTTP 两种通信协议传输层。用户在实现通讯协议传输层时可以参考一下官方实现的代码。

文档:https://go-kratos.dev/docs/component/encoding/


Registry :实现统一注册中心接口,可插件化对接各种注册中心

Registry 接口分为两个,Registrar 为实例注册和反注册,Discovery 为服务实例列表获取。

type Registrar interface {
    // 注册实例
    Register(ctx context.Context, service *ServiceInstance) error
    // 反注册实例
    Deregister(ctx context.Context, service *ServiceInstance) error
}
type Discovery interface {
    // 根据 serviceName 直接拉取实例列表
    GetService(ctx context.Context, serviceName string) ([]*ServiceInstance, error)
    // 根据 serviceName 阻塞式订阅一个服务的实例列表信息
    Watch(ctx context.Context, serviceName string) (Watcher, error)
}
文档:https://go-kratos.dev/docs/component/encoding/


Validation: 通过 Protobuf 统一定义校验规则,并同时适用于 HTTP/gRPC 服务

Validate 中间件使用 proto-gen-validate 生成后的代码进行参数校验,我们可以通过在 proto 中编写参数校验规则,然后生成代码,通过中间件自动的进行校验。

文档:https://go-kratos.dev/docs/component/middleware/validate/


SwaggerAPI: 通过集成第三方 Swagger 插件 能够自动生成 Swagger API json 并启动一个内置的 Swagger UI 服务

框架可通过两种方式提供 OpenAPI/Swagger 的使用:1. 在服务上提供 swagger 接口,2. 使用 protoc 插件生成 swagger.json 文件。下面介绍这两种方式。

文档:https://go-kratos.dev/docs/guide/openapi/


项目结构

我们创建了 kratos-layout 作为使用 kratos new 新建项目时所使用结构,其中包括了开发过程中所需的配套工具链( Makefile 等),便于开发者更高效地维护整个项目,本项目亦可作为使用 Kratos 构建微服务的工程化最佳实践的参考。由 Golang 实现的面向微服务的治理框架使用如下命令即可基于 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

安装

go install 安装:

go install github.com/go-kratos/kratos/cmd/kratos/v2@latest
kratos upgrade

源码编译安装:

git clone https://github.com/go-kratos/kratos
cd kratos
make install


传送门

开源协议:MIT

开源地址:https://github.com/go-kratos/kratos

项目合集:https://github.com/OpenTechCol/OpenTechCol

「回复【加群】加入开源技术交流群,干货很多!」

由 Golang 实现的面向微服务的治理框架-END-


原文始发于微信公众号(开源技术专栏):由 Golang 实现的面向微服务的治理框架

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

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/155523.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!