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