Go 語言體系下的微服務框架選型:Dubbo-go

作者簡介:牛學蔚(GitHub: @justxuewei):Apache Dubbo PMC,對雲原生、中間件、容器等領域有濃厚興趣,活躍在 Dubbo 和 Kata containers 兩個開源項目中。

01 Go 微服務體系發展與選型

隨着微服務技術的快速發展,其在各個領域都形成了一系列事實標準,在 Kubernetes 和容器技術加持下,雲原生微服務已經成爲了主流解決方案。而 Go 語言作爲雲原生領域最受歡迎的開發語言,正被越來越多的企業作爲微服務開發的首選語言,其中比較流行的包括 Go-micro、Go-zero、Dubbo-go 等。作爲 Dubbo 微服務體系中多語言實現的一員,在 2022 年 Dubbo-go 以微服務領跑者的角色積極擁抱雲原生標準,探索了 Proxyless Mesh 形態,配合適配 Pixiu 雲原生網關,形成了完善的 Dubbo-go 微服務生態矩陣。

以 Dubbo-go 爲中心的微服務體系在多個知名企業中成功落地和實踐,框架的穩定性在實際場景下經受住了考驗。截止今年已有 60+ 家企業在我們的用戶列表中登記,其中較爲典型案例請參考文章《小米電商 Apache Dubbo-go 微服務實踐》。小米電商選用了 Dubbo-go + Nacos + sidecar + etcd + mirpc 爲核心的微服務體系,除了看中了 Dubbo-go 的互聯互通和服務治理能力外,也認可 Dubbo-go 在微服務方向的沉澱和積累。

02 Dubbo-go 簡介

2.1 什麼是 Dubbo-go

Apache Dubbo 是一款易用、高性能的 WEB 和 RPC 框架,同時爲構建企業級微服務提供服務發現、流量治理、可觀測、認證鑑權等能力、工具與最佳實踐。Dubbo3 從設計上不綁定編程語言,社區目前提供了 Java、Go、Rust、Node.js 等多語言實現,在未來,我們計劃爲所有主流語言提供對等的微服務開發體驗。

Dubbo 框架作爲國內最具影響力的開源微服務開發框架之一,擁有非常高的關注度和活躍度,在 GitHub 上擁有 3.8 萬+ stars。Dubbo 項目於 2017 年捐贈給 Apache 基金會,在經歷了短短 15 個月孵化後順利畢業,在 Apache 基金會管理的全部項目中關注度排名第三(前兩名分別是 echarts 和 superset),Dubbo-go 作爲 Dubbo 多語言生態的重要一員,很好的兼容 Dubbo 生態的同時提供面向 Go 語言體系的微服務開發體驗。

Dubbo-go(項目地址 github.com/apache/dubbo-go)作爲 Dubbo 多語言生態的重要組成部分,目前完全兌現了 Dubbo3 架構的核心能力,並且在雲原生時代,憑藉 Go 語言無需重量級虛擬機、靜態編譯以及垃圾回收的特性,獲得了廣泛關注,其應用規模也逐漸擴大。從特性上來說,Dubbo-go 目前支持 HTTP/2、TCP、gRPC 協議通信、服務發現、流量管控、配置管理、全鏈路追、可視化觀測等諸多新特性,Dubbo3 已是衆多用戶生產環境首選的微服務框架(用戶列表);在生態建設方面,Dubbo-go 適配了包括 Zookeeper、Nacos、Sentinel、Zipkin、Kubernetes、Prometheus、雲原生 API 網關項目 Dubbo-pixiu、異步網絡庫 Dubbo-getty、Hessian2 等生態項目。

2022 年 Dubbo-go 社區以生態互聯、開發者體驗、穩定性爲切入點,不斷優化系統架構,社區榮獲多個開源獎項:

  • Dubbo 生態被評爲 2021 年中國 20 大最活躍社區之一
  • Dubbo-go 入圍 2021 年“科創中國”榜單。
  • Dubbo-go 開源社區被 OSCHINA 評爲“2022 年度 OSCHINA 優秀開源技術團隊”。

2.2 重要特性

通信協議: 遵循 Dubbo 核心架構設計,Dubbo-go 在實現上不綁定通信協議,目前支持 HTTP/2、TCP (Dubbo2)、JSONRPC、gRPC、HTTP 等多種通信協議,開發者可以根據使用場景靈活的選擇通信協議。

服務註冊: 支持 Client-based 服務發現機制,支持註冊中心適配如 Nacos、Consul、Zookeeper 等。Dubbo3 的服務發現機制誕生於阿里巴巴超大規模微服務電商集羣實踐場景,其在性能、可伸縮性、易用性等方面的表現大幅領先於業界大多數主流開源產品。

配置中心: Dubbo 配置中心可實現應用配置的遠程託管,支持配置變更的實時感知,目前支持 Nacos、Apollo(攜程開源)、ZooKeeper 等作爲配置中心。

負載均衡: Dubbo 提供了多種負載均衡策略,如隨機負載均衡策略、一致性哈希負載、基於權重的輪詢、最小活躍度優先、自適應負載均衡 P2C 等。

流量控制: Dubbo 的流量管控規則可以基於應用、服務、方法、參數等粒度精準的控制流量走向,基於此可靈活的實現超時時間調整、開啓訪問日誌、金絲雀發佈、參數路由、同區域優先、按比例流量分發等。除此之外,通過接入 Hystrix、Sentinel 等,Dubbo-go 還支持自適應限流、限流熔斷等。

分佈式事務: 支持 Seata-golang 分佈式事務框架,實現了 AT 模式和 TCC 模式分佈式事務的調用,AT 模式相較 TCC 模式對代碼的入侵性更小、需要開發的接口更少,但 AT 模式對事務操作的數據持有全局鎖,TCC 模型性能更好。

鏈路追蹤: 支持基於 Jaeger、ZipKin 的鏈路追蹤能力。

指標可視化: 支持使用 Prometheus 收集框架指標和用戶指標。

可擴展性: Dubbo-go 提供了靈活的 extension 擴展機制,用戶可隨時根據自己的需求靈活擴展服務發現、負載均衡、配置中心、流量管控規則、全鏈路追蹤等中間件。

03 過去一年我們做了什麼

3.1 優雅上下線

在微服務場景下,業務是以容器的形式對外提供服務,k8s 能夠方便的對 Pod 進行滾動升級,在舊版本被替換的時候應該達到無損下線的效果,即容器不能被銷燬直到沒有正在處理的請求。如果其不能被正確實現,對於承載高流量的在線服務來說,在更新期間可能會導致大量的請求報錯,甚至可能觸發報警,其影響是巨大的。優雅上下線功能是 Dubbo-go 3.0 正式版本發佈後的第一個重大增強,王曉偉同學(GitHub: @XiaoWeiKIN)貢獻了全流程的優雅上下線能力。

image.png

Dubbo 經典的調用流程如上圖所示,這裏麪包含了服務提供者(Provider)、服務消費者(Consumer)以及註冊中心(Registry)三個關鍵組件,一個服務能夠被調用,首先需要提供者準備服務並對外暴露端口(步驟 0),然後提供者需要將調用信息註冊到註冊中心中(步驟 1),消費者則會通過異步訂閱的方式獲取最新的提供者數據(步驟 2),註冊中心在有新數據後會主動推送給消費者(步驟 3),此時消費者已經有本次調用的全部信息了,最後消費者發送調用請求(步驟 4),這樣就完成了整個調用鏈路。

在單體應用中,上述邏輯非常清晰和簡單,但是在大規模微服務集羣中,這個邏輯的每一個細節都需要被仔細推敲後,才能保證上下線的過程中調用不出錯。

image.png

優雅上線的目標是解決服務上線調用報錯的問題,主要針對微服務場景下的調用依賴問題。在 Dubbo 生態中,Service 表示一個服務,能夠被暴露並被其他服務調用,Reference 表示引用,可以簡單的理解爲下游服務。一個典型調用結構如上圖所示,該服務對外暴露一個接口,同時引用了下游的 N 個服務。該服務在上線的時候應該嚴格遵循以下流程,首先保證下游服務的引用被成功初始化,之後再初始化 Service 對外暴露服務,最後再向註冊中心註冊服務。優雅上線相對來說邏輯比較簡單,只需要嚴格遵循初始化過程的依賴關係就能保證上線過程中服務能夠被正常調用。

優雅下線是優雅上下線的難點,涉及到了信號監聽、反註冊、等待已有請求完成調用等邏輯。在需要銷燬容器的時候,kubelet 會向容器發送 SIGTERM 信號,Dubbo-go 會進入優雅下線流程,此時容器並不會立刻被銷燬。即將下線的提供者首先會執行反註冊,即向註冊中心中刪除自己的信息,消費者可以通過訂閱獲得這個信息,這個過程需要一定的時間。換句話說,在消費者獲得這個刪除信息之前,流量還是有可能會流向該提供者,此時提供者應該拒絕這部分請求。當然除了下線期間的新請求外,還有殘留的來自上游的請求以及自己調用下游的請求,我們分別爲這兩種情況設置一個計數器,當兩個計數器都被清零時,可以認爲該提供者是“乾淨”的。Dubbo-go 的策略是拒絕新請求,等待已放行的舊請求。最後,銷燬協議並關閉監聽,該容器就能夠被安全的摘除。

在啓動優雅上下線後,集羣內無錯誤請求,成功率保持在100%。

image.png

3.2 新一代柔性服務

在去年發佈 Dubbo-go 3.0 版本的時候,柔性服務首次作爲一個重要特性被提出。時隔一年,我們帶來了全新升級的新一代柔性服務,在新版本中我們將爬山算法替換爲峯值干預算法,在經過多次測試後新算法行爲可控性更高、性能更優異,這部分工作由來自北京郵電大學的張業鵬同學(GitHub: @CoolIceV)貢獻。

柔性服務是一種更智能的負載均衡算法。傳統負載均衡算法大多是基於消費者視角,它們共同的侷限性是無法根據服務提供者的當前狀態動態調整分流策略,如 RR、hash 等算法。這些算法總是以儘可能公平的概率分配流量,但在實踐中公平不等於負載均衡。

爬山算法是一種容量預估的算法,服務提供者需要將一些關鍵信息回傳給消費者,比如時延、請求排隊數量、預估容量等,消費者使用 P2C 算法選擇一個負載最低的作爲本次請求的提供者。這些數據實效性要求非常高,如果這些數據是被動傳遞的,那麼很難保證實效性,如果這些數據是被主動探測的,那麼在一個大型集羣下感知成本非常高。基於上述問題,我們選擇了更可控的峯值干預算法。

消費者部分中,我們使用了改良版的 P2C 算法,採集的指標包括請求數(requests)、成功數(accepts)、請求時延(rtt)。與原實現方案不同的是,該版本採用了更合理的滑動窗口(SlidingWindowCounter)和指數移動平均(EMA)兩種帶有時序性的模塊進行採集。

SlidingWindowCounter 會保存時長爲統計週期 T 的數據,整個週期內的數據被分割爲若干個 Bucket,每個Bucket 保存計數時長內的數據,當前所處的 Bucket 會隨着時間前進而向後移動。

image.png

EMA 利用指數移動平均算法進行平滑、減小抖動,適用於統計時延型的指標,計算公式:

image.png

以下爲一個客戶端請求 3 個服務端的測試結果,3 個服務端配置不同,分別爲 1 核 1GB、2 核 2GB、3 核 3GB。蘭青色虛線代表開始使用上述負載均衡算法,可以看到開啓前每個服務端接收到的請求數幾乎相同,開啓之後流量會根據提供者的規格進行智能分流。

image.png

提供者基於一個 AutoConcurrencyLimiter 組件限流,在請求到達時會判斷已接受的請求是否超過最大處理量,如果超過了就會直接返回失敗,限流導致的失敗會影響負載均衡時的成功率,進而影響該實例被請求的可能性。與常規限流組件不同的是,該組件會根據採樣情況自動調整服務的最大處理量,不需要手動配置,而且增加了 CPU 負載作爲啓動開關,可以減少被錯誤限流的數量。

該組件主要關注 QPS、無負載時延(NoLoadLatency)和最大併發量(maxConcurrency),同時有一個用戶指定的超參數 exploreRatio,表示探索最大併發量的程度。更新規則是

  • 使用總請求數(包含未被採樣的數據)計算 QPS,新 QPS 更大時直接替換,更小則使用指數移動平均進行平滑處理。
  • 使用採樣數據計算平均處理時延來估算 NoLoadLatency,平均時延變小纔會更新,並使用指數移動平均進行平滑處理。
  • 增加探索因子啓發式計算 maxConcurrency, 在採樣時延或 QPS 在探索允許的範圍之內時會逐步增大 exploreRatio,否則用指數移動平均的方式進行平滑處理

image.png

最後可以提供給用戶一個可以通過 cgroup v1 進行 CPU 限制,噹噹前提供者 CPU 負載過高的時候,會無條件拒絕一切新請求。CPU 限制是一種最壞情況下的兜底策略。

以下爲 1 個客戶端請求一個服務端的測試結果,該測試隨着時間推移,QPS 會逐步增大,如藍線所示。可以看到當CPU 負載(橙線)過高時,有請求被限流(黃線),隨後即使 QPS 再增大,CPU 負載、請求成功數均已相對穩定。

image.png

3.3 Dubbo Mesh

今年 Dubbo Go 社區發佈了 Dubbo Mesh [1] 架構的完整實現,能夠以 Proxyless Mesh 的形式加入 Istio 服務網格,開啓了 Go 語言體系下的微服務新形態。

Istio 在架構層面分爲控制平面(control plane)和數據平面(data plane),其中控制平面是一個名爲 istiod 的進程,網絡代理是 envoy 。Istiod 簡體 Kubernetes 資源(resources)獲取服務信息,比如 Service、Endpoint 等,將這些信息通過 xDS 協議發送給位於數據平面的 envoy。Envoy 作爲一個獨立代理進程以邊車(sidecar)形式運行,該進程與業務進程共同加入同一個網絡,劫持業務流量並轉發到正確的位置。

服務網格能夠屏蔽複雜的服務治理細節,讓開發者能夠專注於業務實現。Istio 通過邊車的形式實現了業務邏輯的無侵入性,降低了系統之間的耦合性,帶來開發便利的同時也引入了轉發時延、額外資源消耗的問題。但是 Istio 作爲雲原生時代的標杆產品,其架構模式和思路就有非常大的借鑑意義,針對上述提到的 Proxy Mesh 的弊端,我們提出了一套基於 Dubbo-go 的 Proxyless Mesh 微服務治理模式。

Proxyless Mesh 是無代理服務網格,由 Google 提出後,多個開源產品在這個方向進行了探索和實踐。其核心思路是用 SDK 代替獨立代理進程,SDK 作爲數據平面接收來自控制平面的控制信息,負責服務之間的通信和治理工作。

Dubbo-go 爲了融入 Istio 體系,將擴展出來的註冊發現流程進行了特殊改造。除了複用 Istio 提供的 EDS、CDS 主機發現的能力之外,增加了接口名到主機名的映射,作爲源數據註冊在了控制平面上。客戶端在發起調用前持有接口名,通過查詢 istiod 上的元數據信息,拿到接口名到主機名到映射,轉換爲主機名;再通過 EDS、CDS 和路由,完成主機名到下游端點實例的轉換。完成服務發現流程。

3.4 互聯互通的新典範:Polaris 和 Dubbo-go 全面對接

Dubbo-go 從發佈伊始,一直非常重視與各個開源產品之間的互聯互通,今年我們完成了與 Polaris 全面對接,這部分工作由社區鄧正威同學(GitHub: @jasondeng1997)和春少同學(GitHub: @chuntaojun)貢獻。

Polaris 是一款開源的服務治理平臺,致力於解決分佈式和微服務架構中的服務管理、流量管理、配置管理、故障容錯和可觀測性問題,針對不同的技術棧和環境提供服務治理的標準方案和最佳實踐。在經典 Dubbo-go 使用場景下,用戶需要自行部署註冊中心、可觀測服務、流量管理等組件,而 Polaris 內置了服務管理、流量管理、故障容錯、配置管理和可觀測性五大功能,能夠幫助用戶快速降低微服務開發門檻。

Polaris 有統一的控制平面,需要爲 Dubbo-go 框架適配相應的數據平面 SDK,用戶只需要在 Dubbo-go 中開啓 Polaris,框架將自動通過 extension 機制進行注入,開發者無需其他額外的開發工作。從用戶數據流的維度,當用戶在 dubbogo 中啓用 Polaris 的服務治理能力後,業務流量實際處理流程如下:

image.png

當前 Polaris 已實現了 Dubbo-go 原生的服務註冊擴展點,因此原本服務註冊邏輯不需要進行任何調整,只需要在 dubbogo.yaml 配置文件中新增 polaris 協議的註冊中心配置即可,如下所示。

dubbo:
  registries:
    demo:
      protocol: polaris
      address: {polaris-ip}:8091

其中 polaris-ip 表示北極星服務端 IP 地址,此時 Dubbo-go 框架就接入了 Polaris 服務治理框架。Polaris 還提供了流量管理、故障容錯等諸多內容,礙於篇幅限制這裏就不一一展開了,如果有興趣請參閱 《互聯互通的新典範:Polaris 和 Dubbo-go 全面對接》[2]。

3.5 TLS 安全通信支持

在今年我們爲 Dubbo 協議、Triple 協議和 gRPC 協議實現了 TLS 安全通信功能,微服務之間能夠以可信的方式調用,該部分由社區張立斌同學(GitHub: @ZLBer)貢獻。

TLS 的前身是 SSL,被用於通信加密,能夠保證傳輸內容不被其他主機查看和篡改,已經被廣泛的應用於 HTTPS 等技術中。在開啓 TLS 之前,需要生成所需要的證書和祕鑰,我們假設其保存在 x509 目錄中。啓用 TLS 不需要對業務邏輯進行修改,只需要設置相應的 Dubbo-go 配置文件 dubbogo.yaml 即可。

消費者配置文件:

dubbo:
  consumer:
    references:
      UserProvider:
        url: tri://localhost:20000
        protocol: tri
        serialization: json
        interface: com.apache.dubbogo.samples.rpc.extension.UserProvider
  tls_config:
      ca-cert-file: x509/server_ca_cert.pem
      tls-cert-file: x509/client2_cert.pem
      tls-key-file: x509/client2_key.pem
      tls-server-name: dubbogo.test.example.com

提供者配置文件:

dubbo:
  protocols:
    triple:
      name: tri
      port: 20000
  provider:
    services:
      UserProvider:
        serialization: json
        interface: com.apache.dubbogo.samples.rpc.extension.UserProvider
  tls_config:
    ca-cert-file: x509/client_ca_cert.pem
    tls-cert-file: x509/server2_cert.pem
    tls-key-file: x509/server2_key.pem
    tls-server-name: dubbogo.test.example.com

在正確開啓 TLS 之後,提供者會輸出一條 "Server initialized the TLSConfig configuration" 日誌,消費者會輸出一條 "Client initialized the TLSConfig configuration" 日誌。更詳細的使用實例請參考 tls 示例 [3]。

04 展望 2023

2022 年是極不容易的一年,感謝大家的信任,也非常感謝社區中每位同學的貢獻。展望 2023 我們將會持續打磨框架,在優先保障穩定性的前提下持續提升易用性,打造一流的 Go 語言微服務框架。

4.1 Dubbo 開源整體規劃

image.png

  • 官網與文檔體驗全面提升
  • Go、Node.js、Rust 等多語言體系建設
  • 全面提升整體可觀測性
  • Dubbo Admin 一站式服務運維管控平臺
  • Dubbo Mesh 走向成熟
  • 提升 HTTP 開發體驗,補全 Web 互通
  • 打造 gRPC over Dubbo 最佳實踐
  • 完善的認證鑑權體系

4.2 面向 Go 開發者全面使用體驗提升

Dubbo-go 基礎功能建設已經較爲完善,同時在最近幾年中我們持續在 dubbo-go-samples 目錄完善示例代碼 [4],能夠幫助用戶更加快速的上手項目。與此同時,Dubbo-go 文檔內容還較爲匱乏,代碼示例只能讓框架跑起來,但是這裏面的使用和實現細節還需要在文檔中進一步被詳細闡述,讓用戶知其然,更知其所以然。除了文檔建設工作外,社區對開發者工具的建設工作高度重視,在 2023 年,我們計劃在 dubboctl 工具中集成更多命令,爲用戶提供快速創建微服務、支持了 Hessian2 生成器、新建 Dubbo-go 項目等諸多特性。在 2023 年我們將會進一步提升文檔和工具的建設工作,除了強大的功能之外,成爲真正面向 Go 開發者的輕量、易用的框架。

參考鏈接:

1、Dubbo-go-Mesh 開啓新一代 Go 微服務形態 

2、https://baijiahao.baidu.com/s?id=1751764790109427167&wfr=spider&for=pc

3、https://github.com/apache/dubbo-go-samples/tree/master/tls

4、https://github.com/apache/dubbo-go-samples

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章