Kratos 設計理念

2022-04-22 13:56 更新

設計理念

本篇文檔闡述Kratos的設計理念,介紹Kratos項目的整體情況和主要組件

設計哲學

Kratos是一個Go語言實現的微服務框架,說得更準確一點,它更類似于一個使用Go構建微服務的工具箱,開發(fā)者可以按照自己的習慣選用或定制其中的的組件,來打造自己的微服務。也正是由于這樣的原因,Kratos并不綁定于特定的基礎設施,不限定于某種注冊中心,或數據庫ORM等,所以您可以十分輕松地將任意庫集成進項目里,與Kratos共同運作。

圍繞這樣的核心設計理念,我們設計了如下的項目生態(tài):

  • ?kratos ?Kratos框架核心,主要包含了基礎的CLI工具,內置的HTTP/gRPC接口生成和服務生命周期管理,提供鏈路追蹤、配置文件、日志、服務發(fā)現、監(jiān)控等組件能力和相關接口定義。
  • ?contrib ?基于上述核心定義的基礎接口,對配置文件、日志、服務發(fā)現、監(jiān)控等服務進行具體實現所形成的一系列插件,可以直接使用它們,也可以參考它們的代碼,做您需要的服務的適配,從而集成進kratos項目中來。
  • ?aegis ?我們將服務可用性相關的算法:如限流、熔斷等算法放在了這個獨立的項目里,幾乎沒有外部依賴,它更不依賴Kratos,您可以在直接在任意項目中使用。您也可以輕松將它集成到Kratos中使用,提高服務的可用性。
  • ?layout ?我們設計的一個默認的項目模板,它包含一個參考了DDD和簡潔架構設計的項目結構、Makefile腳本和Dockerfile文件。但這個項目模板不是必需的,您可以任意修改它,或使用自己設計的項目結構,Kratos依然可以正常工作??蚣鼙旧聿粚椖拷Y構做任何假設和限制,您可以按照自己的想法來使用,具有很強的可定制性。
  • ?gateway ?這個是我們剛剛起步,用Go開發(fā)的API Gateway,后續(xù)您可以使用它來作為您Kratos微服務的網關,用于微服務API的治理,項目正在施工中,歡迎關注。

倉庫、文檔和社區(qū)

GitHub倉庫:https://github.com/go-kratos

文檔:https://go-kratos.dev/

微信群:go-kratos 官方微信群

Discord:go-kratos

為什么v2完全重新設計

以前關注過kratos項目的可能知道,Kratos的v1版本已經開源了很久,也是個較為完善的框架。那么為什么不直接基于v1繼續(xù)迭代,而是要推倒重來,推出完全重新設計的v2呢?

經驗源自踩坑。

在業(yè)務不斷迭代、項目不斷膨脹的情況下,我們發(fā)現,過去的框架和項目結構設計,導致代碼變更成本逐漸升高,而沒有進行合理的抽象,導致更難進行模塊的測試,也更難對第三方基礎庫進行適配和遷移,這在一定程度上拉低了生產力。

因此,我們參考了大量的DDD和Clean Architecture等業(yè)界先進設計理念,重新設計了微服務的項目結構,并且這個結構隨著我們的后續(xù)研究,會進一步進行迭代,讓它成為微服務項目結構的最佳實踐。

沒錯,新版本的是從kratos-layout開始的。也許剛接觸這個項目結構時會覺得不適應,但隨著項目迭代,代碼復雜度的提高,這個定義良好的結構,將使項目保持優(yōu)秀的代碼可讀性、可測試性,以及令人滿意的開發(fā)效率和可維護性。

更重要的一點是,這一次我們想面向社區(qū)來設計和開發(fā)這個框架。讓更多的開發(fā)者能夠使用我們的框架來提高生產力,同時參與到我們的項目中來。

所以我們把整個框架設計成為一個插座,我們希望整個框架輕量,插件化,可定制。對于幾乎每一個微服務相關的功能模塊,我們都設計了標準化接口,對于第三方庫設計為插件,這樣就能迅速把任意基礎設施集成到使用Kratos的項目里,因此,無論您的公司使用何種基礎設施,有何種規(guī)范,您都可以輕松將Kratos定制成與您的開發(fā)、生產環(huán)境相匹配的樣子。

不破不立,v2是一次從內到外的徹底革新,我們無法在舊版本上修修補補,而是選擇重新設計和開發(fā)新版本。而目前v2版本也已經在很多生產環(huán)境使用,我們也將持續(xù)迭代和完善這個框架,同時也更歡迎各位開發(fā)者參與進來,一起讓它變得更好。

數據庫/緩存/消息隊列/...

正如前文提到的,Kratos框架不限制您使用任何第三方庫來進行項目開發(fā),因此您可以根據喜好來選擇庫進行集成。我們也會逐步針對更多被廣泛使用的第三方庫開發(fā)插件。

這里給出一些被廣泛使用的庫供參考:

數據庫:

緩存:

消息隊列:

其它更多的優(yōu)秀go庫,可以在awesome-go這個倉庫中找找。

CLI工具

kratos命令目前主要用于從模板創(chuàng)建項目,維護依賴包版本等。

Protobuf定義API

Kratos使用Protobuf進行API定義。Protobuf是由Google開發(fā)的一種語言中立的數據序列化協議。它有結構定義清晰、可擴展性好、體積小、性能優(yōu)秀等特點,在眾多公司和項目被廣泛使用。

在使用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;
}

需要注意,雖然Protobuf定義的API的可靠性更強,但字段結構靈活性相對JSON要弱一些,因此如果您有諸如文件上傳接口,或者某些無法對應到proto的JSON結構需要使用,我門還提供了“逃生門”,在我們的Protobuf體系之外定義這些接口,實現為普通的http.Handler并且掛載到路由上,或者用struct來定義您的字段??梢詤⒖嘉覀兊?a href="http://o2fo.com/targetlink?url=https://github.com/go-kratos/examples/blob/main/http/upload/main.go" target="_blank">upload例子進行實現。

元信息傳遞

服務之間的API調用,如果有某些元信息需要傳遞過去,而不是寫在payload消息中,可以使用Metadata包進行字段設置和提取。

錯誤處理

Kratos的errors模塊提供了error的封裝??蚣芤差A定義了一系列標準錯誤供使用。

錯誤處理這一塊的設計也經過了很久的討論才定下來,主要設計理念如下:

  1. ?code ?語義近似HTTP的Status Code(例如客戶端傳參數錯誤用400)同時也作為大類錯誤,在HTTP接口中的HTTP Code會使用它,好處是網關層可以根據這個code觸發(fā)相應策略(重試、限流、熔斷等)。
  2. ?reason ?業(yè)務的具體錯誤碼,為可讀的字符串,能夠表明,在同一個服務中應該唯一。
  3. ?message ?用戶可讀的信息,可以在客戶端(App、瀏覽器等)進行相應的展示給用戶看。
  4. ?metadata ?為一些附加信息,可以作為補充信息使用。

在API返回的錯誤信息中,以HTTP接口為例,消息結構大概是長這個樣子的:

{
    // 錯誤碼,跟 http-status 一致,并且在 grpc 中可以轉換成 grpc-status
    "code": 500,
    // 錯誤原因,定義為業(yè)務判定錯誤碼
    "reason": "USER_NOT_FOUND",
    // 錯誤信息,為用戶可讀的信息,可作為用戶提示內容
    "message": "invalid argument error",
    // 錯誤元信息,為錯誤添加附加可擴展信息
    "metadata": {"some-key": "some-value"}
}

在Kratos中您可以使用proto文件定義您的業(yè)務錯誤,并通過工具生成對應的處理邏輯和方法。(如使用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];;
}

錯誤創(chuàng)建:

// 通過 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提供了統(tǒng)一的接口,支持配置文件的加載和變更訂閱。

通過實現Source 和 Watcher即可實現任意配置源(本地或遠程)的配置文件加載和變更訂閱。

已經實現了下列插件:

服務注冊&服務發(fā)現

Kratos定義了統(tǒng)一的注冊接口,通過實現Registrar和Discovery,您可以很輕松地將Kratos接入到您的注冊中心中。

您也可以直接使用我們已經實現好的插件:

日志

Kratos的日志模塊由兩部分組成:

  1. Logger:底層日志接口,用于快速適配各種日志庫到框架中來,僅提供一個最簡單的Log方法。
  2. Helper:高級日志接口,提供了一系列帶有日志等級和格式化方法的幫助函數,通常業(yè)務邏輯中建議使用這個,能夠簡化日志代碼。

我們已經實現好的插件用于適配目前一些日志庫,您也可以參考它們的代碼來實現自己需要的日志庫的適配:

監(jiān)控

監(jiān)控告警方面,您可以通過實現metrics相關接口將服務的統(tǒng)計數據上報給監(jiān)控平臺。

也可以直接使用我們已經實現好的插件:

鏈路追蹤

Kratos使用OpenTelemetry作為分布式鏈路追蹤所使用的標準,您可以通過對client和server配置tracing來將服務接入到鏈路追蹤平臺(如jaeger等),從而對服務的接口調用關系,耗時,錯誤等進行追蹤。

負載均衡

Kratos內置了若干種負載均衡算法,如Weighted round robin(默認)、P2C,Random等,您可以通過在client初始化時配置來使用他們。

限流熔斷

Kratos提供了限流ratelimit和熔斷circuitbreaker中間件,用于微服務出現異常故障時自動對流量進行限制,提升服務的健壯性,避免雪崩。這兩個中間件使用的算法,也可以在我們的可用性算法倉庫aegis中找到,獨立于Kratos直接使用。

中間件

您可以通過Kratos的middleware機制,統(tǒng)一微服務接口的某些共同邏輯。上面提到的功能插件,您可以通過實現Middleware編寫Kratos能夠使用的中間件。

同時在倉庫的middleware目錄下,我們也提供了一系列中間件供您使用。

插件

除了上述提到的插件外,我們還提供了一些其它插件,完整的插件列表請參考文檔社區(qū)插件

示例代碼

如果您看過文檔后,對某些功能的使用仍有疑惑,或者是希望尋找一些用Kratos寫項目的靈感,在倉庫的examples目錄下我們提供了很多代碼供參考。


以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號