雲原生應用Go語言:你還在考慮的時候,別人已經應用實踐
摘要:在近日於上海召開的第六屆Gopher China大會上,華為雲微服務首席架構師田曉亮分享了《華為雲的Go語言云原生實戰經驗》,講述如何構建韌性、高可靠、安全的雲原生應用系統,並孵化雲原生應用開發框架Go chassis,以提升團隊開發效能。
Gopher China作為國內最權威和最實力乾貨的Go大會,致力於為廣大的Gopher提供一線分享交流機會,也為眾多一線網際網路公司大咖深入探討Go語言的應用發展提供契機。
在近日於上海召開的第六屆Gopher China大會上,華為雲微服務首席架構師田曉亮就受邀分享了《華為雲的Go語言云原生實戰經驗》,講述如何構建韌性、高可靠、安全的雲原生應用系統,並孵化雲原生應用開發框架Go chassis,以提升團隊開發效能。
自華為在2016年成立Cloud BU以來,就引入了Go語言編寫的Kubernetes,Prometheus等CNCF專案,華為雲的研發團隊也開始用Go語言來構建雲服務。不過,當時Go的生態並不完善,所以要自己從頭到尾編寫基礎能力模組。
那麼,如何用Go構建雲服務並將基礎能力慢慢建立起來,且聽我們慢慢道來。
從一個簡單雲應用看我們如何構築一個雲服務
和Eureka一樣,一個簡單的註冊發現服務Service Center可以通過多種手段來增強。
1、靜態與動態資訊定義
減少資料資訊量,抽出公共部分統一管理,通過靜態資訊來劃分例項組。這樣微服務與微服務例項為1對n的對映,將微服務名、版本、資料中心等資訊都抽到了公共部分,通過降低冗餘度,來減少網路的開銷,同時也規範化了微服務模型。
2、契約化微服務
上一張圖我們看到微服務靜態資訊裡面包含了多個Schemas,裡面關聯了微服務所關聯的契約文件,同樣是1對n的對映關係。通過手動上傳或者程式碼自動生成文件上傳,可以在註冊中心中檢視微服務文件,且文件與微服務版本繫結,不允許更改。
對比客戶端開發團隊等待後端的服務編寫完成後,才開始進行整合開發的方式。高效方式是以文件為基準,客戶端與服務端同時開發,客戶端通過Mock去除對服務端的依賴。
為何要保證文件先行?如果文件不及時審視,那麼將會出現非常糟糕的情況。比如不一致的命名規範,定義相似的API,擴充套件能力差,任何一點都會大大增加研發成本。及早審視並規避十分重要,這就是為何註冊中心加入文件上傳與查詢能力。
3、服務間依賴管理
呼叫層級過高將引起定位困難、效能下降的問題,合理的層級是3個服務:a->b->c的呼叫就可以完成一次呼叫。彼此互相依賴的兩個服務在功能升級或者變更時要花費更多時間來分析影響,比如ab互相依賴,一個新功能涉及2個都要更改,那怎麼一起上線?
簡單的依賴有助於系統測試和分析,這給架構師一個很好的審視方式,可以及時看到微服務間的依賴關係,以及時對架構調整。
4、快取機制
由於Service Center內部本身是不存資料的,一旦etcd出現網路故障的時候,就會導致Service Center不可用。所以Service Center引入了非同步快取機制,啟動之初,Service Center會與etcd建立一個長連線,也就是watch。為了防止建立watch時間窗發生變化,又做了一層保護,在watch之前做全量的查詢。執行過程中查詢所得到的資源變化會快取到Service Center本地,然後進行非同步的迴圈。
總的來說,我們通過了多種手段來提升微服務研發效率,減少網路開銷,並通過非同步快取提升效能。這是華為雲積累的能力,但交付一個雲服務遠遠不止交付業務功能這麼簡單,還要考慮微服務的安全、韌性、隱私、可運維等能力。
我們剛才看到的只是水面之上的冰山,水面之下還隱藏著大量的基礎能力需要編寫。真的要達成微服務架構模式的願景,需要繁重的工作量。就像冰山那樣,我們要將通用能力沉澱下去,能夠複用。如果讓各個業務團隊同時照顧冰山上下,各自開發各自的,那結果將是災難性的,企業用人成本極高,下面讓我們展開Service Center的架構看看。
立足Service Center架構,“冰山下”的基礎能力庫編寫很重要
下面這個元件主要負責微服務的註冊發現,提供Restful API。
它有四個主要的模組:
- 服務註冊發現:通過註冊發現完成服務拓撲的感知;
- 契約發現:每個服務具備一個契約記錄,支援多種格式如Open API,gRPC proto;
- RBAC:基於角色的訪問控制,管理員可以管理賬號,將賬號分發給微服務或者不同人員;
- 服務治理:針對微服務下發治理規則,比如重試,限流,熔斷,路由策略等。
交付一個雲服務遠遠不止交付業務功能,而是要去全方面的考慮安全,韌性,隱私,可運維等能力,當然我們將部分的能力可以交給一些中介軟體來完成,比如閘道器。然而仍有大量功能需要自己編寫,且可以複用在每個微服務中,這就是基礎能力庫編寫的初衷。
- 配額管理:雲資源按照租戶進行配額管理,租戶所能使用的資源受到嚴格限制
- 告警:當微服務發生關鍵問題時要直接上報告警系統,而非通過雲服務設定閾值等告警策略
- 安全:加解密證書,密碼
- ID生成:ID的生成演算法,用於生成微服務ID,例項ID等
- 多種中介軟體:呼叫過程需要被審計,呼叫鏈追蹤,生成指標監控等
該專案已經開源並捐獻給Apache,專案地址https://github.com/apache/servicecomb-service-center
對於這些能力,抽取普通的庫函式也是完全不夠用的,所以要做到如下能力:
可插拔:也就是按需在編譯期引入(受限於Go語言能力),例如配額系統的具體實現在社群是不需要的。
異構系統:也就是一個功能要有多種具體實現,比如審計,公有云存在一套審計系統需要對接,而社群則是本地日誌列印。
不同的演算法:解密工具、ID生成器……面對不同的交付場景或安全要求,都要通過不同實現來替換演算法。比如ID生成可以是snowflake、UUID;加解密演算法使用AES或者其他公開演算法。
如何通過Go Chassis加速雲服務開發?
為了滿足上面提到的需求多樣性,並且讓所有新規劃的元件受益、快速進行開發,我們需要統一的框架和標準來加速開發,這就是華為雲用Go語言編寫的開發框架Go Chassis誕生的原因。所以大家看可以看到go chassis的原始碼和設計有著service center程式碼的影子,感興趣的同學可以去深入閱讀下。
從Go Chassis的開發框架可以看到,業務邏輯是使用者自己編寫的業務程式碼,框架分為協議層、中間層和外掛套件三部分,管理部分是雲服務,框架開發出來的應用可以快速對接使用這些雲能力。比如:
- 註冊發現外掛可以對接Service Center與kubenetes
- 配額管理外掛可以對接雲服務的配額管理服務
- 中介軟體如指標監控對接到prometheus
那麼如何通過這個框架來加速我們的開發呢?
手段1:將後端服務作為外掛使用
後端服務指的是不由自己組織開發並運維,從應用執行到基礎設施不可見的黑盒子服務。常見的後端包括配額管理、認證鑑權服務和物件儲存服務,雲原生的其中一個要素是把後端服務當作附加資源。
當我們呼叫這些後端服務時,其實它們並不在微服務的治理體系內,考慮到可測試性(比如mock測試)以及可替換性(業務能夠連續,且隨時更換更好的服務,應對變換的需求等),我們需要將它們外掛化,以靈活的進行選擇替換或者去除。
手段2:沉澱需求基線
在我們提供任何一種服務前,我們都需要滿足基本的要求,比如:
- 請求體必須做大小限制
- API必須限流
- 密碼不能明文儲存
- 訪問進行認證鑑權
- 無單點故障
- 訪問審計
- 運維能力
考慮到這些需求,首先要將執行時的呼叫模型標準化。由於不同部門會有私有協議訴求,那麼服務治理就交給核心框架完成,協議由業務部門決定自主研發或是整合現有協議。
當公司內部不同部門都在開發自己的協議做自己的服務治理時,再將業務統一在一個架構、工具鏈上,就非常困難。
所以,我們使用Invocation概念來統一協議描述,這樣就可以在統一的處理鏈中進行處理。
處理鏈的設計滿足AOP,也就是在業務處理的前後加入程式碼邏輯進行特殊處理,比如審計使用者操作。
ResponseCallBack 用於接受後置handler返回的結果,所以每一個handler處理時都可以按需定義自己的ResponseCallBack來獲取後面handler,甚至是業務邏輯程式碼的執行結果,讓通用邏輯(即中介軟體)和業務邏輯徹底解耦。
目前Go Chassis已經支援的中介軟體包括限流、熔斷、負載均衡、認證鑑權和審計,都用此機制來實現:將公司全部的工具鏈,服務治理手段,安全合規等都落入到處理鏈中,來快速加快研發速度,並統一規範,減少管理負擔。
框架內部提供給了命令式呼叫能力,比如指標收集。
也提供了宣告式使用方式,比如流量管理,其具備基於流量特徵的限流能力。
從外掛能力全景圖可以看到,Go Chassis目前已經支援多種生態,並對多種後端系統提供了抽象介面,從而幫助應用快速開發。
通過這樣的框架,我們可以讓業務團隊專注於業務程式碼開發,而無需理解後端的複雜性和其他非功能需求。帶來的收益如下:
• 對於龐大的系統可以進行mock測試,提升交付質量
• 應對不同的交付場景
• 保證後端可替換性
• 研發職責介面分離
從架構或者業務演進的角度來思考,後端使用的技術是在快速演進的,我們需要通過後端服務的快速替換來確保系統和產品的及時演進,所以介面設計的可替換性大於可重用性。這也滿足程式設計原則的依賴倒置,當我們再開發一個新的微服務時,僅僅需要實現他的業務邏輯即可。
手段3:通過配置簡化開發流程
這也是一種命令式呼叫方式,其結構如下:
Source層: 配置源是一種標準介面,可以通過實現一個source來接入不同配置源,它定義配置來自哪個資源:可以來自遠端系統,來自本地檔案,來自環境變數或是啟動命令列。source負責將配置項快取到本地記憶體,使用者可以選擇載入任意的source實現。
remote source:對接分散式配置管理系統,目前對接了攜程開源的配置中心Apollo。
Config manager:負責整合管理所有source的配置,每個source可以定義優先順序,當通過manager獲取配置時,如果2個不同的source有相同的配置,那麼就會取最大優先順序的配置。
Event Dispatcher:使用者可以通過Archaius API進行配置變化監聽,當source內部的配置項新增、更新、刪除、時,都會通知監聽器。
Source優先順序:優先順序由大到小依次為Config center、CLI、ENV、file,當有相同配置項的時候僅優先順序大的配置生效。在一個分散式系統中,遠端的配置中心理應擁有最大優先順序。而在本地執行一個獨立的程序時,通常的思維是命令列引數優先順序高於環境變數,高於本地檔案內容。擁有了這樣一套機制後,使用者就無需再寫程式碼處理配置項生效邏輯。
Archaius API: 封裝底層實現,提供友好的API供開發者使用。
其中,記憶體source非常重要,它使得UT測試更加簡單。File source使得本地程序的測試可行。遠端的配置中心比如攜程的Apollo,則幫助系統進行聯調測試並支撐生產環境。
手段4:易處理
意思是它們可以瞬間開啟或停止。 這裡我們不會談到快速的開始,因為Go語言和Docker執行時,容器平臺就能處理這樣的一個場景,所以我們談談面向意外的處理。
這個Protocol server通常代表一個協議,也可以是某種程式設計模型,比如http。
還有個框架的配置樣例,意思是在一個微服務程序中拉起了2個http埠和grpc埠服務。
在收到系統訊號後,就會遍歷的停止每個server。
另外由社群開發者貢獻的自定義優雅停機功能,可以允許使用者劫持訊號和停機處理過程,也可以在前後自定義處理過程。
手段5:輕量級核心
目前,Go Chassis只依賴必要的prometheus、opentracing、jwt、k8s client、Go-restful相關的依賴庫。
註冊發現也是可插拔的。
另外,包括grpc協議、kubernetes註冊中心等多種能力都在另一個倉庫中提供,可以按需引入
擁有自己重新制造的輪子
擁有自己重新制造的輪子是Go Chassis開發框架logo想要傳達的理念。
我認為真正有能力的團隊不會自己重新制造輪子,因為他們懂什麼是輪子,什麼樣的輪子適合自己,並將這種抽象的輪子引入並進行增強,打造成更加適合自己的輪子,你是“越野輪子”還是“雪地輪子”,品類皆由你定。我們將自己研發團隊積累的能力抽象成多種介面及外掛,為的就是不要重複製造輪子,而是基於現有輪子重新打造,讓專案產品跑的更快。
Go Chassis的案例分享
首先是基於Go Chassis和Service Center進行服務治理的視訊通話後臺,其一直應用於華為榮耀手機和智慧屏等終端上,且上線了公有云,有效支撐終端公司暢聯通話上億註冊使用者。
第二個案例是基於Go Chassis開發服務治理底座的邊緣處理能力,它管理全國29個省、自治區的將近10萬邊緣節點,超過50萬邊緣應用的部署。支撐了1萬多個收費站的門架資訊採集業務的不斷調整、更新,滿足了每日3億條以上的資訊採集。為日後車路協同、自動駕駛等創新業務的發展提供了良好的平臺支撐。
(https://github.com/kubeedge/kubeedge)
除此之外,華為雲ServiceStage就是無縫託管基於GoChassis開發的微服務,並在此之上提供免運維的微服務引擎功能
( https://www.huaweicloud.com/product/servicestage.html)
總結
1、定義你的應用開發通訊協議
一家公司非常重要的兩樣東西是企業文化與行為規範,這是每個公司的領導者必須優先定義的事情,它就像是一種通訊協議,保證團隊之間能夠良好的協作。這樣領導者就無需事必躬親,甚至可以做到無為而治。這套機制就是所謂的“通訊協議”
所以定義一套通訊協議是非常重要的。Go chassis就是Go研發團隊的通訊協議。
每個微服務都是個小團隊開發的,有可能是同一個團隊,也可能是不同團隊,我們所做的框架是為了定義一套最簡化的正規化(介面與模型),以此來減輕研發的成本,同時兼顧擴充套件性,不要對開發有過度的限制。我們規範化了API first來審視API設計,依賴管理來審視合理的服務關係,並規定所有的能力要沉澱為外掛與中介軟體,而這些都是為了定義研發團隊開發與治理雲服務的“通訊協議”。
2、Go在新基建中的作用
網際網路演進第一代是PC,第二代是手機,第三代便是萬物互聯,5G時代允許更多的裝置接入,而較小的裝置勢必會催生新的半導體,新的作業系統(比如說華為鴻蒙),這樣一層層下去,勢必會需要一種新的語言及對應的框架,Go語言的特性就很契合這樣一個位置,而分散式的裝置也需要一種框架來進行治理,Go Chassis也將在這裡扮演比較重要的角色。
綜上,我認為Go語言很可能成為基礎設施領域的一個開發底座,從kubeedge、視訊雲等專案使用Go Chassis就可以看出端倪。
歡迎大家參與社群,Go Chassis開源專案地址:https://github.com/go-chassis/go-chassis
本文分享自華為雲社群《華為雲的Go語言云原生實戰經驗:建立雲原生應用開發基礎能力》,原文作者:灰灰噠 。
點選關注,第一時間瞭解華為雲新鮮技術~