天天看點

雲原生應用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建構雲服務并将基礎能力慢慢建立起來,且聽我們慢慢道來。

從一個簡單雲應用看我們如何構築一個雲服務

雲原生應用Go語言:你還在考慮的時候,别人已經應用實踐

和Eureka一樣,一個簡單的注冊發現服務Service Center可以通過多種手段來增強。

1、靜态與動态資訊定義

雲原生應用Go語言:你還在考慮的時候,别人已經應用實踐

減少資料資訊量,抽出公共部分統一管理,通過靜态資訊來劃分執行個體組。這樣微服務與微服務執行個體為1對n的映射,将微服務名、版本、資料中心等資訊都抽到了公共部分,通過降低備援度,來減少網絡的開銷,同時也規範化了微服務模型。

2、契約化微服務

上一張圖我們看到微服務靜态資訊裡面包含了多個Schemas,裡面關聯了微服務所關聯的契約文檔,同樣是1對n的映射關系。通過手動上傳或者代碼自動生成文檔上傳,可以在注冊中心中檢視微服務文檔,且文檔與微服務版本綁定,不允許更改。

雲原生應用Go語言:你還在考慮的時候,别人已經應用實踐

對比用戶端開發團隊等待後端的服務編寫完成後,才開始進行內建開發的方式。高效方式是以文檔為基準,用戶端與服務端同時開發,用戶端通過Mock去除對服務端的依賴。

為何要保證文檔先行?如果文檔不及時審視,那麼将會出現非常糟糕的情況。比如不一緻的命名規範,定義相似的API,擴充能力差,任何一點都會大大增加研發成本。及早審視并規避十分重要,這就是為何注冊中心加入文檔上傳與查詢能力。

3、服務間依賴管理

雲原生應用Go語言:你還在考慮的時候,别人已經應用實踐

調用層級過高将引起定位困難、性能下降的問題,合理的層級是3個服務:a->b->c的調用就可以完成一次調用。彼此互相依賴的兩個服務在功能更新或者變更時要花費更多時間來分析影響,比如ab互相依賴,一個新功能涉及2個都要更改,那怎麼一起上線?

簡單的依賴有助于系統測試和分析,這給架構師一個很好的審視方式,可以及時看到微服務間的依賴關系,以及時對架構調整。

4、緩存機制

雲原生應用Go語言:你還在考慮的時候,别人已經應用實踐

由于Service Center内部本身是不存資料的,一旦etcd出現網絡故障的時候,就會導緻Service Center不可用。是以Service Center引入了異步緩存機制,啟動之初,Service Center會與etcd建立一個長連接配接,也就是watch。為了防止建立watch時間窗發生變化,又做了一層保護,在watch之前做全量的查詢。運作過程中查詢所得到的資源變化會緩存到Service Center本地,然後進行異步的循環。

總的來說,我們通過了多種手段來提升微服務研發效率,減少網絡開銷,并通過異步緩存提升性能。這是華為雲積累的能力,但傳遞一個雲服務遠遠不止傳遞業務功能這麼簡單,還要考慮微服務的安全、韌性、隐私、可運維等能力。

雲原生應用Go語言:你還在考慮的時候,别人已經應用實踐

我們剛才看到的隻是水面之上的冰山,水面之下還隐藏着大量的基礎能力需要編寫。真的要達成微服務架構模式的願景,需要繁重的工作量。就像冰山那樣,我們要将通用能力沉澱下去,能夠複用。如果讓各個業務團隊同時照顧冰山上下,各自開發各自的,那結果将是災難性的,企業用人成本極高,下面讓我們展開Service Center的架構看看。

立足Service Center架構,“冰山下”的基礎能力庫編寫很重要

下面這個元件主要負責微服務的注冊發現,提供Restful API。

雲原生應用Go語言:你還在考慮的時候,别人已經應用實踐

它有四個主要的子產品:

    • 服務注冊發現:通過注冊發現完成服務拓撲的感覺;
    • 契約發現:每個服務具備一個契約記錄,支援多種格式如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語言:你還在考慮的時候,别人已經應用實踐

從Go Chassis的開發架構可以看到,業務邏輯是使用者自己編寫的業務代碼,架構分為協定層、中間層和插件套件三部分,管理部分是雲服務,架構開發出來的應用可以快速對接使用這些雲能力。比如:

    • 注冊發現插件可以對接Service Center與kubenetes
    • 配額管理插件可以對接雲服務的配額管理服務
    • 中間件如名額監控對接到prometheus

那麼如何通過這個架構來加速我們的開發呢?

手段1:将後端服務作為插件使用

後端服務指的是不由自己組織開發并運維,從應用運作到基礎設施不可見的黑盒子服務。常見的後端包括配額管理、認證鑒權服務和對象存儲服務,雲原生的其中一個要素是把後端服務當作附加資源。

當我們調用這些後端服務時,其實它們并不在微服務的治理體系内,考慮到可測試性(比如mock測試)以及可替換性(業務能夠連續,且随時更換更好的服務,應對變換的需求等),我們需要将它們插件化,以靈活的進行選擇替換或者去除。

手段2:沉澱需求基線

在我們提供任何一種服務前,我們都需要滿足基本的要求,比如:

    • 請求體必須做大小限制
    • API必須限流
    • 密碼不能明文存儲
    • 通路進行認證鑒權
    • 無單點故障
    • 通路審計
    • 運維能力

考慮到這些需求,首先要将運作時的調用模型标準化。由于不同部門會有私有協定訴求,那麼服務治理就交給核心架構完成,協定由業務部門決定自主研發或是內建現有協定。

當公司内部不同部門都在開發自己的協定做自己的服務治理時,再将業務統一在一個架構、工具鍊上,就非常困難。

雲原生應用Go語言:你還在考慮的時候,别人已經應用實踐

是以,我們使用Invocation概念來統一協定描述,這樣就可以在統一的處理鍊中進行處理。

雲原生應用Go語言:你還在考慮的時候,别人已經應用實踐

處理鍊的設計滿足AOP,也就是在業務處理的前後加入代碼邏輯進行特殊處理,比如審計使用者操作。

ResponseCallBack 用于接受後置handler傳回的結果,是以每一個handler處理時都可以按需定義自己的ResponseCallBack來擷取後面handler,甚至是業務邏輯代碼的執行結果,讓通用邏輯(即中間件)和業務邏輯徹底解耦。

目前Go Chassis已經支援的中間件包括限流、熔斷、負載均衡、認證鑒權和審計,都用此機制來實作:将公司全部的工具鍊,服務治理手段,安全合規等都落入到處理鍊中,來快速加快研發速度,并統一規範,減少管理負擔。

雲原生應用Go語言:你還在考慮的時候,别人已經應用實踐

架構内部提供給了指令式調用能力,比如名額收集。

雲原生應用Go語言:你還在考慮的時候,别人已經應用實踐

也提供了聲明式使用方式,比如流量管理,其具備基于流量特征的限流能力。

雲原生應用Go語言:你還在考慮的時候,别人已經應用實踐

從插件能力全景圖可以看到,Go Chassis目前已經支援多種生态,并對多種後端系統提供了抽象接口,進而幫助應用快速開發。

雲原生應用Go語言:你還在考慮的時候,别人已經應用實踐

通過這樣的架構,我們可以讓業務團隊專注于業務代碼開發,而無需了解後端的複雜性和其他非功能需求。帶來的收益如下:

• 對于龐大的系統可以進行mock測試,提升傳遞品質

• 應對不同的傳遞場景

• 保證後端可替換性

• 研發職責界面分離

從架構或者業務演進的角度來思考,後端使用的技術是在快速演進的,我們需要通過後端服務的快速替換來確定系統和産品的及時演進,是以接口設計的可替換性大于可重用性。這也滿足程式設計原則的依賴倒置,當我們再開發一個新的微服務時,僅僅需要實作他的業務邏輯即可。

手段3:通過配置簡化開發流程

雲原生應用Go語言:你還在考慮的時候,别人已經應用實踐

這也是一種指令式調用方式,其結構如下:

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運作時,容器平台就能處理這樣的一個場景,是以我們談談面向意外的處理。

雲原生應用Go語言:你還在考慮的時候,别人已經應用實踐

這個Protocol server通常代表一個協定,也可以是某種程式設計模型,比如http。

還有個架構的配置樣例,意思是在一個微服務程序中拉起了2個http端口和grpc端口服務。

雲原生應用Go語言:你還在考慮的時候,别人已經應用實踐

在收到系統信号後,就會周遊的停止每個server。

雲原生應用Go語言:你還在考慮的時候,别人已經應用實踐

另外由社群開發者貢獻的自定義優雅停機功能,可以允許使用者劫持信号和停機處理過程,也可以在前後自定義處理過程。

手段5:輕量級核心

雲原生應用Go語言:你還在考慮的時候,别人已經應用實踐

目前,Go Chassis隻依賴必要的prometheus、opentracing、jwt、k8s client、Go-restful相關的依賴庫。

注冊發現也是可插拔的。

雲原生應用Go語言:你還在考慮的時候,别人已經應用實踐

另外,包括grpc協定、kubernetes注冊中心等多種能力都在另一個倉庫中提供,可以按需引入

擁有自己重新制造的輪子

雲原生應用Go語言:你還在考慮的時候,别人已經應用實踐

擁有自己重新制造的輪子是Go Chassis開發架構logo想要傳達的理念。

我認為真正有能力的團隊不會自己重新制造輪子,因為他們懂什麼是輪子,什麼樣的輪子适合自己,并将這種抽象的輪子引入并進行增強,打造成更加适合自己的輪子,你是“越野輪子”還是“雪地輪子”,品類皆由你定。我們将自己研發團隊積累的能力抽象成多種接口及插件,為的就是不要重複制造輪子,而是基于現有輪子重新打造,讓項目産品跑的更快。

Go Chassis的案例分享

雲原生應用Go語言:你還在考慮的時候,别人已經應用實踐

首先是基于Go Chassis和Service Center進行服務治理的視訊通話背景,其一直應用于華為榮耀手機和智慧屏等終端上,且上線了公有雲,有效支撐終端公司暢聯通話上億注冊使用者。

雲原生應用Go語言:你還在考慮的時候,别人已經應用實踐

第二個案例是基于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語言雲原生實戰經驗:建立雲原生應用開發基礎能力》,原文作者:灰灰哒 。

點選關注,第一時間了解華為雲新鮮技術~

繼續閱讀