Go chassis 微服務(wù)開發(fā)框架實(shí)戰(zhàn)系列(一)
什么是 Go chassis
go chassis 是一個(gè) go 語言微服務(wù)開發(fā)框架,專注于云原生應(yīng)用的開發(fā),我們主要的使用場景是云服務(wù)開發(fā)。我們將自己在云服務(wù)開發(fā)過程中沉淀的能力融入到了開發(fā)框架中,以幫助開發(fā)團(tuán)隊(duì)快速編寫云原生應(yīng)用。
文章目標(biāo)
本文介紹我們的設(shè)計(jì)理念和目標(biāo),為何 go chassis 會誕生。后面的系列文章會著重介紹使用方法,項(xiàng)目實(shí)戰(zhàn)。對于微服務(wù)架構(gòu)模式,云原生要素,為什么選擇 go 語言等將不再過多贅述。
誕生背景
公司開發(fā)云服務(wù),要構(gòu)建健壯,韌性,安全,高可靠的云服務(wù),必然有大量基礎(chǔ)能力需要編寫,為了加速開發(fā),我們將這些能力便沉淀在了該框架中。為什么呢?我們希望加速每一個(gè)組件也就是微服務(wù)的開發(fā)速度。有的人看到的只是冰山一角,真的要達(dá)成微服務(wù)架構(gòu)模式的愿景,其實(shí)需要繁重的工作量。就像冰山那樣,我們要將通用能力沉淀下去,能夠復(fù)用。如果讓各個(gè)業(yè)務(wù)團(tuán)隊(duì)同時(shí)照顧冰山上下,各自開發(fā)各自的,那結(jié)果將是災(zāi)難性的,企業(yè)用人成本極高。

在業(yè)務(wù)交付的過程中,各個(gè)云團(tuán)隊(duì)有大量的管理服務(wù)需要對接,每個(gè)團(tuán)隊(duì)都在寫重復(fù)的代碼,通過框架能力,將交付職責(zé)分離,減少開發(fā)成本:

如何快速開發(fā)一個(gè)微服務(wù)
可以跟隨這個(gè)文檔體驗(yàn):?https://github.com/go-chassis/go-chassis/edit/master/docs/getstarted/install.md
統(tǒng)一治理和協(xié)議模型
想要復(fù)用統(tǒng)一的一套能力,我們自然要先統(tǒng)一模型。我們使用 Invocation 概念來統(tǒng)一協(xié)議描述,當(dāng)協(xié)議請求到來后,go chassis 會把 request 轉(zhuǎn)換為 Invocation 進(jìn)行治理(如負(fù)載均衡,限流,熔斷,重試,金絲雀發(fā)布等),這樣就可以允許任意的協(xié)議接入到 go chassis,并無縫使用 go chassis 提供的核心功能,當(dāng)前默認(rèn)提供原生 grpc 和 http 兩種協(xié)議的接入。
為什么會有這樣的設(shè)計(jì)呢?
每個(gè)協(xié)議層的優(yōu)化空間非常大,用戶態(tài)到內(nèi)核態(tài)的調(diào)用速度本來就相對內(nèi)部代碼來說是很慢的,優(yōu)化這一層代碼很重要,RPC 怎么也比 http 來得好。
不同部門可能有私有協(xié)議訴求,那么服務(wù)治理就交給核心框架完成。協(xié)議由業(yè)務(wù)部門決定自主研發(fā)或是集成現(xiàn)有協(xié)議。當(dāng)你發(fā)現(xiàn)公司內(nèi)部不同部門都在開發(fā)自己的協(xié)議做自己的服務(wù)治理時(shí),再向?qū)I(yè)務(wù)統(tǒng)一一個(gè)架構(gòu),一個(gè)工具鏈上,將非常困難。
可擴(kuò)展的處理鏈條:handler chain as middleware
我們以 Java 為例,大家在寫一個(gè)攔截器或者過濾器的時(shí)候可以對請求進(jìn)行處理,處理完,這個(gè)攔截器的的執(zhí)行過程就結(jié)束了,那么如何達(dá)成以下目標(biāo)?
1.跟蹤業(yè)務(wù)執(zhí)行結(jié)果指標(biāo),比如 http 狀態(tài)碼,并導(dǎo)出他們讓 prometheus 收集。
2.跟蹤關(guān)鍵的業(yè)務(wù)執(zhí)行結(jié)果,審計(jì)這些信息。比如請求返回的一些結(jié)果信息
3.分布式調(diào)用鏈追蹤,end span 必須等到請求返回才能拿到。
客戶端調(diào)用遠(yuǎn)程服務(wù)時(shí),也需要進(jìn)行中間處理,比如客戶端負(fù)載均衡,請求重試,這些不能夠耦合在業(yè)務(wù)代碼中
Java 的答案很簡單,注解。那么 go 呢?我們引入了 handler chain 編程模型,chain 中每個(gè) handler 都可以拿到后面的 handler 的執(zhí)行結(jié)果,包括業(yè)務(wù)代碼的執(zhí)行結(jié)果。

看下接口定義
type Handler interface {
Handle(*Chain, *invocation.Invocation, invocation.ResponseCallBack)
Name() string
}
// ResponseCallBack process invocation response
type ResponseCallBack func(*Response)
ResponseCallBack 用于接受后置 handler 返回的結(jié)果,所以每一個(gè) handler 處理時(shí)都可以按需定義自己的 ResponseCallBack 來獲取后面 handler 甚至是業(yè)務(wù)邏輯代碼的執(zhí)行結(jié)果。幫助通用邏輯(即中間件)和業(yè)務(wù)邏輯徹底解耦??梢钥聪卢F(xiàn)在已經(jīng)支持的中間件,無論限流,熔斷,負(fù)載均衡,認(rèn)證鑒權(quán),審計(jì),我們都用此機(jī)制實(shí)現(xiàn):https://go-chassis.readthedocs.io/en/latest/middleware.html 將公司全部的工具鏈,服務(wù)治理手段,安全合規(guī)等都落入到處理鏈中,可快速加快研發(fā)速度,并統(tǒng)一規(guī)范,減少管理負(fù)擔(dān)。
不只是 API,通過配置簡化開發(fā)過程
只舉 2 個(gè)例子
監(jiān)控
減少讓開發(fā)者自己調(diào)用 API 的過程,將他們簡化為配置項(xiàng) 例如可觀察:引入一行代碼
import _ github.com/go-chassis/go-chassis/v2/middleware/monitoring
加上配置
handler:
chain:
Provider:
default: monitoring
就可以在服務(wù)端進(jìn)行監(jiān)控,導(dǎo)出請求數(shù),延遲等指標(biāo),大大加速開發(fā)人員效率
# HELP request_count
# TYPE request_count counter
request_count{app="default",env="",instance="",service="servicecomb-kie",version="0.1.0"} 14
# HELP request_process_duration
# TYPE request_process_duration summary
request_process_duration{app="default",env="",instance="",service="servicecomb-kie",version="0.1.0",quantile="0.5"} 3
request_process_duration{app="default",env="",instance="",service="servicecomb-kie",version="0.1.0",quantile="0.9"} 80
request_process_duration{app="default",env="",instance="",service="servicecomb-kie",version="0.1.0",quantile="0.99"} 80
request_process_duration_sum{app="default",env="",instance="",service="servicecomb-kie",version="0.1.0"} 315
request_process_duration_count{app="default",env="",instance="",service="servicecomb-kie",version="0.1.0"} 14
需要自定義指標(biāo):
err := metrics.CreateCounter(metrics.CounterOpts{
Name: “user_login”,
Labels: labelsSlice,
})
metrics.CounterAdd(“user_login”, 1, labelMap)
通用能力
我們也將通用的部分都落地到了框架中,通過簡單的配置文件啟用,不再需要不同團(tuán)隊(duì)重復(fù)編寫代碼
servicecomb:
transport:
failure:
rest: http_500,http_502 #統(tǒng)計(jì)錯(cuò)誤率時(shí),例如只把500和502作為錯(cuò)誤
maxIdleCon:
rest: 1024
maxBodyBytes:
rest: 20 #只需要指定我的服務(wù)能接受的body體大小,訪問的超時(shí)時(shí)間即可不再需要各個(gè)團(tuán)隊(duì)維護(hù)代碼。
maxHeaderBytes:
rest: 1 #限制http header大小
timeout: #限制客戶端超時(shí)
rest: 30s
插件化
為了應(yīng)對不同業(yè)務(wù)訴求,我們總是要考慮 “可替換性”。而這個(gè)的優(yōu)先級總是大于 “可復(fù)用性”。這就是 go chassis 的插件理念。基本所有的重要組件都是插件化的,框架已經(jīng)定義好標(biāo)準(zhǔn)接口,只需要開發(fā)者實(shí)現(xiàn)好,注冊到框架中,就可以在配置文件中配置并生效了,業(yè)務(wù)開發(fā)者是完全不感知的。可以參考我們對 quota 組件的擴(kuò)展過程,他負(fù)責(zé)資源的配額管理 https://go-chassis.readthedocs.io/en/latest/dev-guides/backends.html
后續(xù)
我將詳細(xì)剖析 go chassis 的內(nèi)部設(shè)計(jì)和特性使用。
在下一篇文章中,我將講述 go chassis 如何快速開發(fā)出一個(gè)微服務(wù)。由于是系列文章,隨著文章不斷更新,如果有期望了解的話題,內(nèi)容可以留言反饋,我會加入到后續(xù)文章中。
項(xiàng)目地址
https://github.com/go-chassis/go-chassis
目前的用戶
趣頭條
邊緣計(jì)算:http://kubeedge.io/
ServiceComb:?https://github.com/apache/servicecomb-service-center?等多個(gè) go 語言開發(fā)項(xiàng)目
本文來源為?GoCN 社區(qū)原創(chuàng)投稿,點(diǎn)擊“閱讀原文”前往社區(qū)。
