What's new of dubbogo v1.4

joke59發表於2020-03-26

得益於社群活躍的支援,2020年3月25日我們釋出了一個讓人興奮的版本——dubbo-go v1.4.0。除了繼續支援已有的 Dubbo 的一些特性外, dubbo-go 開始了一些自己的創新嘗試。

這個版本,最大的意義在於,做了一些支援雲原生的準備工作。比如說,社群在探討了很久的 k8s 落地之後,終於拿出來了使用 k8s 作為註冊中心的解決方案。

其次一個比較大的改進是--我們在可觀測性上也邁出了重要的一步。在這之前,dubbo-go 只提供了日誌這麼一個單一手段,內部的資訊比較不透明,這個版本將有很大的改善。

最後一個令人心動的改進是,我們支援了 REST 協議。

1. K8s 註冊中心

dubbo-go 註冊中心的本質為 K/V 型的資料儲存。當前版本實現了以 Endpoint 為維度在 k8s API Server 進行服務註冊和發現的方案【下文簡稱 Endpoint 方案】,架構圖如下。

Endpoint 方案,首先將每個 dubbo-go 程式自身服務資訊序列化後,通過 Kubernetes 提供的 Patch 的介面寫入在自身 Pod 物件的 Annotation 中。其次,通過 Kubernetes 的 Watch 介面觀察叢集中本 Namespace 內帶有某些固定 lable [見上圖] Pod 的 Annotation 資訊的更新,處理服務健康檢查、服務上下線等情況並實時更新本地快取。整體流程僅使用 Kubernetes 原生 API 完成將 Kubernetes 作為註冊中心的功能特性。

這個方案非常簡潔,不需要實現額外的第三方模組,也不需要對 Dubbo 業務作出改動,僅僅把 k8s 當做部署平臺,依賴其容器管理能力,沒有使用其 label selector 和 service 等服務治理特性。如果站在 k8s Operator 的角度來看,Operator 方案的優點即 Endpoint 方案的缺點,Endpoint 方案無法使用 k8s 的健康檢查能力,亦沒有使用 k8s service 的事件監聽能力,每個 consumer 冗餘監聽一些不必要監聽的事件,當 Endpoint 過多時會加大 API Server 的網路壓力。

目前 dubbo-go 社群其實已經有了 operator 版本註冊中心的技術方案, 後續版本【計劃版本是 v1.6】的 dubbo-go 會給出其實現。相比當前實現,operator 方案開發和線上維護成本當然上升很多。二者如同硬幣的兩面,社群會讓兩種方式會共存,以滿足不同 level 的使用者。

注意: 因 Pod 被排程而 IP 發生變化時,當前版本的 configuration 以及 router config 模組暫時無法動態更新。這有待於我們進一步解決。

參考範例 [1].

2. tracing 和 metric

可觀測性是微服務重要的一環,也是我們 1.4 版本著力支援的部分。在 1.4 版本中,我們主要在 tracing 和 metric 兩個方向提供了支援。

為了支援 tracing 和 metric,關鍵的一點是支援 context 在整個呼叫過程中傳遞。為此我們解決了 context 跨端傳遞的問題。目前使用者可以在介面中宣告 context 並且設定值,dubbo-go 在底層完成 context 內容從 client 傳遞到 server 的任務。

在 metric 方面,dubbo-go 開始支援 Prometheus 採集資料了。目前支援 Prometheus 中 的 Histogram 和 Summary。使用者也可以通過擴充套件 Reporter 介面來自定義資料採集。

在 tracing 方面,目前 dubbo-go 的設計是採用 opentracing 作為統一的 API,在該 API 的基礎上,通過在 client 和 server 之中傳遞 context,從而將整個鏈路串起來。使用者可以採用任何支援 opentracing API 的監控框架來作為實現,例如 zipkin,jaeger 等。

3. rest 協議支援

Dubbo 生態的應用與其他生態的應用互聯互通,一直是 dubbo-go 社群追求的目標。dubbo-go v1.3 版本已經實現了 dubbo-go 與 grpc 生態應用的互聯互通,若想與其他生態如 Spring 生態互聯互通,藉助 rest 協議無疑是一個很好的技術手段。

Rest 協議是一個很強大並且社群呼聲很高的特性,它能夠有效解決 open API,前端通訊,異構系統通訊等問題。比如,如果你的公司裡面有一些陳年程式碼是通過 http 介面來提供服務的,那麼使用我們的 rest 協議就可以無縫整合了。

通過在 dubbo-go 中釋出 RESTful 的介面的應用可以呼叫任意的 RESTful 的介面,也可以被任何客戶端以 http 的形式呼叫,框架圖如下:

在設計過程中,考慮到不同的公司內部使用的 web 框架並不相同,所以我們允許使用者擴充套件自己 rest server ( web 框架在 dubbo-go 的封裝)的實現,當然,與 rest server 相關的,諸如 filter 等,都可以在自己的 rest server 實現內部擴充套件。

4. 路由功能增強

路由規則在發起一次 RPC 呼叫前起到過濾目標伺服器地址的作用,過濾後的地址列表,將作為消費端最終發起 RPC 呼叫的備選地址。v1.4 版本的 dubbo-go 實現了 Condition Router 和 Health Instance First Router,將在後面版本中陸續給出諸如 Tag Router 等剩餘 Router 的實現。

4.1 條件路由

條件路由,是 dubbo-go 中第一個支援的路由規則,允許使用者通過配置檔案及遠端配置中心管理路由規則。

與之相似的一個概念是 dubbo-go 裡面的 group 概念,但是條件路由提供了更加細粒度的控制手段和更加豐富的表達語義。比較典型的使用場景是黑白名單設定,灰度以及測試等。

參考範例 [2]。

4.2 健康例項優先路由

在 RPC 呼叫中,我們希望儘可能地將請求命中到那些處理能力快、處於健康狀態的例項,該路由的功能就是通過某種策略斷定某個例項不健康,並將其排除在候選呼叫列表,優先呼叫那些健康的例項。這裡的"健康"可以是我們自己定義的狀態,預設實現即當錯誤比例到達某一個閾值時或者請求活躍數大於上限則認為其不健康,允許使用者擴充套件健康檢測策略。

在我們服務治理裡面,核心的問題其實就在於如何判斷一個例項是否可用。無論是負載均衡、

熔斷還是限流,都是對這個問題的解答。所以,這個 feature 是一個很好的嘗試。因為我們接下來計劃提供的特性,基於規則的限流以及動態限流,都是要解決 “如何斷定一個例項是否可用” 這麼一個問題。

所以歡迎大家使用這個特性,並向社群反饋各自設定的健康指標。這對我們接下來的工作會有很大的幫助。

5. hessian 協議增強

相較於 dubbo 的 Java 語言以及其他多語言版本,dubbo-go 社群比較自豪的地方之一就是:無論底層網路引擎還是原生使用的 hessian2 協議,以及整體服務治理框架,都由 dubbo-go 社群從零開發並維護。v1.4 版本的 dubbo-go 對 hessian2 協議又帶來了諸多新 feature。

5.1 支援 dubbo 協議的 attachments

在 dubbo-go 中,attachments 機制用於傳遞業務引數之外的附加資訊,是在客戶端和服務端之間傳遞非業務引數資訊的重要方式。

hessian 編碼協議將之編碼在 body 內容的後面進行傳輸,dubbo-go-hessian2 之前並不支援讀/寫 attachments,在多個使用方【如螞蟻金服】的要求下,dubbo-go-hessian2 以相容已有的使用方式為前提,支援了 attachments 的讀/寫。

Request 和 Response 的 struct 中定義了 attachments 的 map,當需要使用 attachments,需要由使用方構造這兩種型別的引數或者返回物件。否則,將無法在 hessian 的傳輸流中獲取和寫入 attachments。

另外,利用 dubbo-go 呼叫鏈中傳輸 context 的功能,使用者已經可以在服務方法中通過 context 新增 attachments 了。

5.2 支援忽略非註冊 pojo 的解析方式

由於 hessian 編碼協議與 Java 的型別高度耦合,在 golang 的實現中會相對比較麻煩,需要有指明的對應型別。dubbo-go-hessian2 的實現方式是:定義 POJO 介面,要求實現 JavaClassName 方法來供程式獲取 Java 對應的類名。這導致了接收到包含未註冊類的請求時,將會無法解析而報錯,這個問題以前是無法解決的。

但是,有一些使用場景如閘道器或者 service mesh 的 sidecar,需要在不關心 Java 類的具體定義的情況下,像 http 讀取 header 資訊一樣僅僅讀取 dubbo 請求的附加資訊,將 dubbo/dubbo-go 請求轉發。通過該 feature,閘道器/sidecar 並不關注請求的具體內容,可以在解析請求的資料流時跳過無法解析的具體型別,直接讀取 attachments 的內容。

該實現通過在 Decoder 中新增的 skip 欄位,對每一個 object 做出特殊處理。

5.3 支援 java.math.BigInteger 和 java.math.BigDecimal

在 Java 服務中,java.math.BigInteger 和 java.math.BigDecimal 是被頻繁使用的數字型別,hessian 庫將它們對映為 github.com/dubbogo/gost/math/big 下的對應型別。

5.4 支援 ‘繼承’ 和忽略冗餘欄位

由於 go 沒有繼承的概念,所以在之前的版本,Java 父類的欄位不被 dubbo-go-hessian2 所支援。新版本中,dubbo-go-hessian2 將 Java 來自父類的欄位用匿名結構體對應,如:


type Dog struct {
    Animal
    Gender  string
    DogName string `hessian:"-"`
}

同時,就像 json 編碼中通過 immediately 可以在序列化中忽略該欄位,同理,通過 hessian:"-" 使用者也可以讓冗餘欄位不參與 hessian 序列化。

目前,上述四個特性已被某 Go 版本的 sidecar 整合到其商業版本中提供商業服務。

6. Nacos 配置中心

配置中心是現代微服務架構裡面的核心元件,現在 dubbo-go 提供了對配置中心的支援。

Nacos 作為一個易於構建雲原生應用的動態服務發現、配置管理和服務管理平臺,在該版本終於作為配置中心而得到了支援。

參考範例 [3].

7. 介面級簽名認證

Dubbo 鑑權認證是為了避免敏感介面被匿名使用者呼叫而在 SDK 層面提供的額外保障。使用者可以在介面級別進行定義是否允許匿名呼叫,並對呼叫方進行驗籤操作,對於驗籤不通過的消費端,禁止呼叫。

如上圖,總體實現基於 AK/SK 機制,應用通過 HTTPS 通訊,啟動時向鑑權服務拉取,定期更新。且允許使用者自定義獲取 AK/SK 的源,在 RPC 層面保障安全性。

8. 回顧與展望

目前 dubbo-go 已經到了一個比較穩定成熟的狀態。在接下來的版本里面,我們將集中精力在雲原生上。下一個版本,我們將首先實現應用維度的服務註冊,這是一個和現有註冊模型完全不同的新的註冊模型。也是我們朝著雲原生努力的一個關鍵版本。

在可觀測性上,我們計劃在整個 dubbo-go 的框架內,引入更多的埋點,收集更加多的內部狀態。這需要實際生產環境使用者的使用反饋,從而知道該如何埋點,收集何種資料。

在限流和熔斷上,可以進一步擴充套件。當下的限流演算法,是一種靜態的演算法--限流引數並沒有實時根據當前伺服器的狀態來推斷是否應該限流,它可能僅僅是使用者的經驗值。其缺點在於,使用者難以把握應該如何配置,例如 TPS 究竟應該設定在多大。所以計劃引入一種基於規則的限流和熔斷。這種基於規則的限流和熔斷,將允許使用者設定一些系統狀態的狀態,如 CPU 使用率,磁碟 IO,網路 IO 等。當系統狀態符合使用者規則時,將觸發熔斷。

目前這些規劃的 任務清單 [4],都已經放入在 dubbo-go 專案的 issue 裡面,歡迎感興趣的朋友認領參與開發。dubbo-go 社群在 釘釘群 23331795 歡迎你的加入。

文中連結:

[1] https://github.com/apache/dubbo-samples/tree/master/golang/registry/kubernetes

[2] https://github.com/dubbogo/dubbo-samples/tree/master/golang/router/condition

[3] https://github.com/dubbogo/dubbo-samples/tree/master/golang/configcenter/nacos

[4] https://github.com/apache/dubbo-go/milestone/1

更多原創文章乾貨分享,請關注公眾號
  • What's new of dubbogo v1.4
  • 加微信實戰群請加微信(註明:實戰群):gocnio

相關文章