作 者 | 牛學蔚(蔚俊)
本文介紹了Go 微服務體系發展與選型,過去一年Dubbo-go 社區的飛速發展以及對未來的展望。
一、Go 微服務體系發展與選型
隨著微服務技術的快速發展,其在各個領域都形成了一系列事實標準,在 Kube.NETes 和容器技術加持下,云原生微服務已經成為了主流解決方案。而 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 在微服務方向的沉淀和積累。
二、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 擴展機制,用戶可隨時根據自己的需求靈活擴展服務發現、負載均衡、配置中心、流量管控規則、全鏈路追蹤等中間件。
三、過去一年我們做了什么
3.1 優雅上下線
在微服務場景下,業務是以容器的形式對外提供服務,k8s 能夠方便的對 Pod 進行滾動升級,在舊版本被替換的時候應該達到無損下線的效果,即容器不能被銷毀直到沒有正在處理的請求。如果其不能被正確實現,對于承載高流量的在線服務來說,在更新期間可能會導致大量的請求報錯,甚至可能觸發報警,其影響是巨大的。優雅上下線功能是 Dubbo-go 3.0 正式版本發布后的第一個重大增強,王曉偉同學(GitHub: @XiaoWeiKIN)貢獻了全流程的優雅上下線能力。
Dubbo 經典的調用流程如上圖所示,這里面包含了服務提供者(Provider)、服務消費者(Consumer)以及注冊中心(Registry)三個關鍵組件,一個服務能夠被調用,首先需要提供者準備服務并對外暴露端口(步驟 0),然后提供者需要將調用信息注冊到注冊中心中(步驟 1),消費者則會通過異步訂閱的方式獲取最新的提供者數據(步驟 2),注冊中心在有新數據后會主動推送給消費者(步驟 3),此時消費者已經有本次調用的全部信息了,最后消費者發送調用請求(步驟 4),這樣就完成了整個調用鏈路。
在單體應用中,上述邏輯非常清晰和簡單,但是在大規模微服務集群中,這個邏輯的每一個細節都需要被仔細推敲后,才能保證上下線的過程中調用不出錯。
優雅上線的目標是解決服務上線調用報錯的問題,主要針對微服務場景下的調用依賴問題。在 Dubbo 生態中,Service 表示一個服務,能夠被暴露并被其他服務調用,Reference 表示引用,可以簡單的理解為下游服務。一個典型調用結構如上圖所示,該服務對外暴露一個接口,同時引用了下游的 N 個服務。該服務在上線的時候應該嚴格遵循以下流程,首先保證下游服務的引用被成功初始化,之后再初始化 Service 對外暴露服務,最后再向注冊中心注冊服務。優雅上線相對來說邏輯比較簡單,只需要嚴格遵循初始化過程的依賴關系就能保證上線過程中服務能夠被正常調用。
優雅下線是優雅上下線的難點,涉及到了信號監聽、反注冊、等待已有請求完成調用等邏輯。在需要銷毀容器的時候,kubelet 會向容器發送 SIGTERM 信號,Dubbo-go 會進入優雅下線流程,此時容器并不會立刻被銷毀。即將下線的提供者首先會執行反注冊,即向注冊中心中刪除自己的信息,消費者可以通過訂閱獲得這個信息,這個過程需要一定的時間。換句話說,在消費者獲得這個刪除信息之前,流量還是有可能會流向該提供者,此時提供者應該拒絕這部分請求。當然除了下線期間的新請求外,還有殘留的來自上游的請求以及自己調用下游的請求,我們分別為這兩種情況設置一個計數器,當兩個計數器都被清零時,可以認為該提供者是“干凈”的。Dubbo-go 的策略是拒絕新請求,等待已放行的舊請求。最后,銷毀協議并關閉監聽,該容器就能夠被安全的摘除。
在啟動優雅上下線后,集群內無錯誤請求,成功率保持在100%。
3.2 新一代柔性服務
在去年發布 Dubbo-go 3.0 版本的時候,柔性服務首次作為一個重要特性被提出。時隔一年,我們帶來了全新升級的新一代柔性服務,在新版本中我們將爬山算法替換為峰值干預算法,在經過多次測試后新算法行為可控性更高、性能更優異,這部分工作由來自北京郵電大學的張業鵬同學(GitHub: @CoolIceV)貢獻。
柔性服務是一種更智能的負載均衡算法。傳統負載均衡算法大多是基于消費者視角,它們共同的局限性是無法根據服務提供者的當前狀態動態調整分流策略,如 RR、hash 等算法。這些算法總是以盡可能公平的概率分配流量,但在實踐中公平不等于負載均衡。
爬山算法是一種容量預估的算法,服務提供者需要將一些關鍵信息回傳給消費者,比如時延、請求排隊數量、預估容量等,消費者使用 P2C 算法選擇一個負載最低的作為本次請求的提供者。這些數據實效性要求非常高,如果這些數據是被動傳遞的,那么很難保證實效性,如果這些數據是被主動探測的,那么在一個大型集群下感知成本非常高。基于上述問題,我們選擇了更可控的峰值干預算法。
消費者部分中,我們使用了改良版的 P2C 算法,采集的指標包括請求數(requests)、成功數(accepts)、請求時延(rtt)。與原實現方案不同的是,該版本采用了更合理的滑動窗口(SlidingWindowCounter)和指數移動平均(EMA)兩種帶有時序性的模塊進行采集。
SlidingWindowCounter 會保存時長為統計周期 T 的數據,整個周期內的數據被分割為若干個 Bucket,每個Bucket 保存計數時長內的數據,當前所處的 Bucket 會隨著時間前進而向后移動。
EMA 利用指數移動平均算法進行平滑、減小抖動,適用于統計時延型的指標,計算公式:
以下為一個客戶端請求 3 個服務端的測試結果,3 個服務端配置不同,分別為 1 核 1GB、2 核 2GB、3 核 3GB。蘭青色虛線代表開始使用上述負載均衡算法,可以看到開啟前每個服務端接收到的請求數幾乎相同,開啟之后流量會根據提供者的規格進行智能分流。
提供者基于一個 AutoConcurrencyLimiter 組件限流,在請求到達時會判斷已接受的請求是否超過最大處理量,如果超過了就會直接返回失敗,限流導致的失敗會影響負載均衡時的成功率,進而影響該實例被請求的可能性。與常規限流組件不同的是,該組件會根據采樣情況自動調整服務的最大處理量,不需要手動配置,而且增加了 CPU 負載作為啟動開關,可以減少被錯誤限流的數量。
該組件主要關注 QPS、無負載時延(NoLoadLatency)和最大并發量(maxConcurrency),同時有一個用戶指定的超參數 exploreRatio,表示探索最大并發量的程度。更新規則是
-
使用總請求數(包含未被采樣的數據)計算 QPS,新 QPS 更大時直接替換,更小則使用指數移動平均進行平滑處理。
-
使用采樣數據計算平均處理時延來估算 NoLoadLatency,平均時延變小才會更新,并使用指數移動平均進行平滑處理。
-
增加探索因子啟發式計算 maxConcurrency, 在采樣時延或 QPS 在探索允許的范圍之內時會逐步增大 exploreRatio,否則用指數移動平均的方式進行平滑處理
最后可以提供給用戶一個可以通過 cgroup v1 進行 CPU 限制,當當前提供者 CPU 負載過高的時候,會無條件拒絕一切新請求。CPU 限制是一種最壞情況下的兜底策略。
以下為 1 個客戶端請求一個服務端的測試結果,該測試隨著時間推移,QPS 會逐步增大,如藍線所示。可以看到當CPU 負載(橙線)過高時,有請求被限流(黃線),隨后即使 QPS 再增大,CPU 負載、請求成功數均已相對穩定。
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 的服務治理能力后,業務流量實際處理流程如下:
當前 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]。
四、展望 2023
2022 年是極不容易的一年,感謝大家的信任,也非常感謝社區中每位同學的貢獻。展望 2023 我們將會持續打磨框架,在優先保障穩定性的前提下持續提升易用性,打造一流的 Go 語言微服務框架。
4.1 Dubbo 開源整體規劃
-
官網與文檔體驗全面提升
-
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