Go
chassis是一個go語言微服務開發框架
通過這篇文章中,我將從設計思路到原始碼剖析來深度分析Go Chassis。並且介紹自己在實踐過程中的go語言效能調優和最佳實踐,最後將使用go chassis編寫一個http服務,此為上篇,將主要介紹go chassis的執行機制
為什麼我們要用go語言來開發微服務?
go依然是一門新興的語言,和java比它還非常年輕,不過隨著kubenetes和docker等專案的成功,可以說go語言已經成為了非常好的中間層開發語言,並且逐漸流行起來。
編譯速度快,支援多平臺,記憶體佔用低,輕量級協程等。
他的協程設計降低了開發者門檻,讓更多人可以輕鬆地編寫支援高併發的後臺服務
為什麼使用Go chassis
當你要解決微服務模式帶來的新問題的時候你要實現多少程式碼來處理分散式帶來的複雜度?
我相信一個成熟的開發框架需要2萬行以上的程式碼。而go chassis正是這樣一個框架
- go chassis整合了很多的功能,提供了一站式服務,能夠讓使用者在一個方案中,獲得路由管理,註冊發現,負載均衡,限流,指標監控,分散式追蹤等大量功能。
- go chassis是一個協議中立的開發框架,它不僅支援http,也支援rpc協議,甚至可以整合mysql等中介軟體的協議。並將它們納入統一的治理。
- go chasis支援Istio控制皮膚,也就是說你可以將它與envoy進行混合使用,但只需要使用istio即可,它支援原生的istio配置管理。以此使服務吞吐提升,CPU佔用降低。
- go chassis是外掛化設計,支援使用者開發定製模組,並接入到框架中
go chassis特性
主要有以下幾點:
● 外掛化註冊中心: 預設支援Service Center,kubernetes,istio
● 動態治理框架: 通過此框架,開發者可實現程式執行時配置熱載入
● 外掛化協議: 開發者可實現自己的RPC協議,預設實現了 http 和highway(RPC)
● 熔斷降級: 支援根據超時,併發,錯誤率等進行服務的熔斷
● 容錯:支援重試次數等配置,並支援backoff退讓重試,
● 路由管理: 可根據流量權重和Header匹配等配置規則,輕鬆實現金絲雀釋出
● 客戶端負載均衡: 支援定製策略
● 限流: 支援客戶端和服務端限流
● 外掛化Cipher: 支援開發者自定義加解密工具,並應用於AKSK和TLS 證照
● 處理鏈: 可支援在通訊的過程中加入定製的業務邏輯
● Metrics: 支援自動匯出Prometheus格式的執行時監控資料
● Tracing: 使用opentracing,支援使用者快速對接不同分散式追蹤系統
● Logger: 日誌工具支援擴充套件並下沉到不同儲存中
● 治理: 可通過動態治理框架,在執行時熱載入,熔斷,負載均衡,路由等配置資訊
設計目標
● 最大的靈活性和擴充套件性
協議是允許開發者靈活擴充套件的,在通訊管道中任意的插入自己的特殊業務邏輯。
● 易用性
開發者可以用最小化的配置和程式碼來啟動框架,並且框架內部提供友好的API供使用者使用,每個模組甚至可以拆開使用,功能任意剪裁。
● 服務可治理
提供客戶端負載均衡,熔斷降級,容錯,限流,路由管理等功能使分散式系統可治理,同時提供錯誤注入功能,來提前模擬分散式系統中的錯誤,以使自己的系統更加強壯。
● 服務視覺化
微服務執行時產生的監控資料能夠匯出到監控系統,使資料視覺化。
● 執行時配置熱載入
分散式環境中,存在大量程式,如果因為更改配置就要釋出新的軟體包,會有一定成本,如果登陸到機器上去改配置再重啟,更是費時費力。go chassis提供動態配置框架來幫開發者解決配置熱載入問題。這也是服務動態治理的基礎。
架構概述
如下圖所示:
● 架構思路
- 解耦的程式設計介面、執行模型、傳輸層
● 程式設計介面:擁有RPC和Rest 2種程式設計模型
● 執行模型:使用Handler Chain與Invocation概念統一了不同協議
● 傳輸層:一個程式擁有多種協議。同協議可執行多個協議服務例項,執行在不同埠,使用埠進行API隔離
- 基於Handler chain模式的外掛化架構
● Handler chain可任意插入業務邏輯
- 基於執行時動態配置的服務治理
- 相同的執行模型和統一的治理能力
- 相同的運維支撐方式
● Http服務可支援自動掛載 Promethues資料到指定的API路徑。
● 日誌可支援擴充套件,比如輸出到kafka等服務中
- 註冊中心拆分為Registrator和Service Discovery2個介面分別負責註冊和發現,可以支援平臺發現和客戶端註冊
● 請求處理過程
不同協議請求進入到對應的Server,Server將具體的協議請求轉換為Invocation統一抽象模型,並傳入Handler chain,在這裡Chassis已經預設實現了很多的Handler,比如熔斷,限流,路由管理,客戶端負載均衡,Metrics收集,分散式追蹤,錯誤注入等,由於handler根據統一模型Invocation進行處理,不必每個協議開發出來都自己開發一套治理。處理鏈可通過配置任意剪裁。最終再進入Transport handler,使用目標微服務的協議客戶端傳輸到目標。
這裡提到的幾個關鍵物件在後面會詳細介紹。
實現詳解
基本概念
● 處理鏈與Invocation
這個概念是從Java chassis引入的, 框架的程式設計介面層、執行模型層和傳輸層就是通過這個物件進行解耦,它是多協議支援的基礎。可以參考它的程式碼:
Invocation為一個結構體,它將各個協議的內容抽象了,執行不同協議的request都能夠統一對應到一次Invocation中,比如request的Payload,以及框架的治理相關資訊。
● Handler
Handler是微服務在執行過程中在框架層面裡的一個最小處理單元。go chassis通過handler和handler的組裝實現元件化的執行模型架構。其基本的使用方式就是實現介面、註冊邏輯:
- 實現基本介面
2. 開發者實現該介面後可通過API註冊進框架
● Handler Chain
用於載入一系列Handler並處理訊息,目前支援負載均衡,路由管理,監控等功能,使用者可以通過配置檔案定義載入多種handler。請求呼叫時,會按照配置檔案中的定義的順序進入handler進行處理
Handler的設計可以保證每一個handler都能得到後面的handler的執行結果。比如:熔斷和網路穿的功能就在chain當中,每當傳輸失敗,都會被熔斷拿到錯誤結果,並計算,當達到一定閾值,便會出發熔斷。
● Invoker
由於RPC和Http的程式設計風格不同,go chassis使用2種不同的Invoker來解決呼叫,無論哪種Invoker都會初始化一個Invocation並最終進入處理鏈中進行處理,最終進入各協議的Client實現並傳輸到目標服務中,這一切對使用者都是透明的。
RPC
為了降低使用者學習成本,使用了go語言標準庫中net/rpc的呼叫風格
Http
為了降低使用者學習成本,支援了go語言通用的http呼叫方式,允許使用者任意操控原生http request 與 response,並且沒有任何限制
接下來,用一個微服務呼叫過程中最基本的Consumer到Provider的業務請求流程來看一下前面的那些關鍵物件是如何協同工作的.
● 客戶端傳送請求
- 開發者使用Invoker來發起請求,Invoker建立統一Invocation物件
- Invocation進入處理鏈進行處理,比如熔斷,限流等
- 進入Load Balancing後,會根據Strategy和目標協議選擇一個IP:port
- 將協議和IP port繼續傳送到Transport 後,根據協議選擇具體的Client實現,並傳入IP port進行傳送
● 服務端接收請求
- 接收到協議請求後,由各協議Server轉為統一的Invocation模型
- Invocation進入處理鏈處理,比如限流,分散式追蹤
- 處理結束後,進入具體的業務處理邏輯
外掛化機制
go的動態能力相對有限,go 1.8提供了外掛能力,但是會給build帶來複雜度,我們先來看看Java怎麼解決外掛化的
Class<?> act = Class.forName("com.bla.TestActivity");複製程式碼
基於這個能力也出現了Spring這樣的專案,開發者可以輕鬆地解決外掛化的問題
可是go語言該怎麼做呢?
下面以Go chassis的實踐為例
提供介面與Map定義
開發者需要實現介面,並實現NewFunc返回具體實現
註冊外掛
通過呼叫API進行外掛安裝
使用外掛
考慮到易用性貼近Spring的風格,chassis使用yaml格式的配置檔案來管理外掛。
以下為實現思路
啟動和初始化機制如下:
- 通過檔案指定載入的外掛,在Server之上我們封裝Server manager管理所有協議的Server,並負責註冊到註冊中心,,收到系統終止訊號時,負責反註冊
- 使用了Client manager與github.com/ServiceComb… 對client進行封裝,按協議,微服務,例項的唯獨進行client初始化,即每個例項都有專屬client。
支援的外掛
chassis框架支援以下外掛,具體請參考gitbook文件https://go-chassis.readthedocs.io/en/latest/。
- Handler
- Provider
- Cipher
- Bootstrap
- Logger
- Config Source
- Registry
- InjectFault
- Server
- Client
- Strategy
- Tracing
客戶端負載均衡
客戶端負載均衡器負責使用本地的註冊中心快取來進行服務發現。
go chassis 封裝了很多的高階特性
- 融合了Backoff演算法,以使網路流量穩定。
- 容錯支援在請求錯誤後以怎樣的策略進行重試
- 會話粘滯與延遲感知Strategy實現
- 動態治理,支援執行時熱載入以上配置
- 支援目標服務級別的細粒度負載均衡策略配置(即一程式針對訪問不同微服務,可控制負載均衡策略)
錯誤注入
為了能讓使用者輕鬆地製造系統混亂,在Consumer側,實現了錯誤注入機制,可以根據配置定義錯誤或者故意製造呼叫延遲,來測試分散式系統遇到問題時的容錯能力,同樣支援執行時動態載入配置。目前只支援簡單的錯誤和延遲以及發生百分比
開發者甚至可以通過此介面為一個協議安裝錯誤注入外掛,可完全替代目前的錯誤注入實現
與其他微服務開發框架的對比
go micro架構:
圖片來自go micro官網https://micro.mu/docs/images/go-micro.png
這裡我引用micro.mu的關於go micro與go kit對比
Go micro是一個外掛化RPC分散式開發框架,可以開箱即用,也可以任意定製自己的RPC協議中的每個模組。他是一個eco system,現在已經有大量的外掛實現,並在go-micro基礎之上有了很多的新框架,Micro組織下有許多圍繞go-micro建立的子專案。
Go kit是一個用來構建微服務的的工具包,每個包都是獨立的,開發者自己選擇需要的工具組裝自己的微服務,包含了豐富的治理功能,熔斷,監控,限流等,且擁有豐富的外掛化協議和註冊中心。
Go chassis是外掛化框架,與Go micro的不同在於,go chassis提供的能力是外掛化協議,你可以將http或RPC,甚至是Mysql,Redis等協議接入到框架中,並且提供一站式功能,將熔斷,限流,監控等功能全部整合到框架中,開發者無需自己尋找這些方案。擁有3者中最豐富的治理功能。同樣擁有開放的定製能力,但是作為一個新的框架,生態尚需完善。
開發者可以通過開發體驗和特性支援對框架進行選型。