導讀
高德啟動Serverless建設已經有段時間了,目前高德Serverless業務的峰值早已超過十萬QPS量級,平台從0到1,QPS從零到超過十萬,成為阿裡集團内Serverless應用落地規模最大的BU。這個過程如何實作,遇到過哪些問題?本文将和大家分享高德為何要搞Serverless/Faas,如何做,技術方案是什麼?目前進展以及後續計劃有哪些,希望對感興趣的同學有所幫助。
1. 高德為什麼要搞Serverless
背景原因是高德當年啟動了一個用戶端上雲項目,項目主要目的是為了提升用戶端的開發疊代效率。以前用戶端業務邏輯都在端上,産品需求的變更需要走用戶端發版才能釋出,而用戶端發版需要走各種測試流程,灰階流程,解用戶端崩潰等問題。
用戶端上雲之後,某些易變的業務邏輯放到雲上來。新的産品需求通過在雲端來開發,不用走月度的版本釋出,加快了需求的開發疊代效率,離産研同頻的理想目标又近了一步(為什麼要說“又”,是因為高德之前也做了一些優化往産研同頻的方向努力,但是我們希望雲端一體化開發能是其中最有效的一個技術助力)。
1.1 目标:用戶端開發模式——端雲一體
雖然開發模式從以前的端開發轉變為現在的雲 + 端開發,開發同學應該還是原來負責相應業務的同學,而大家知道,服務端開發和用戶端開發顯然是有差異的,用戶端開發往往是面向單機模式的開發,服務端開發通常是叢集模式,需要考慮分布式系統的協調、負載均衡,故障轉移降級等各種複雜問題。
如果使用傳統的服務端模式來開發,這個過渡風險就會比較大。Faas很好的解決了這一問題。我們結合高德用戶端現有的xbus架構(一套用戶端上的本地服務注冊、調用的架構),擴充了xbus-cloud元件,使得雲上的開發就像端上開發一樣,目标是一套代碼,兩地運作,一套業務代碼既能在用戶端上運作,也能在服務端上運作。
高德用戶端主要有三個端:iOS、Android、車機(類Linux作業系統)。主要有兩種語言,C++和Node.js。傳統地圖功能:如地圖顯示,導航路徑顯示,導航播報等等,由于需要跨三個端,采用C++語言來開發。地圖導航基礎之上的一些地圖應用功能,如行前、行後卡片,推薦目的地等主要是用Node.js來開發的。
在阿裡集團,淘系前端團隊開發了Node.js Faas Runtime。高德用戶端上雲項目,Node.js的部分就采用了現有的淘系的Node.js Runtime,來接入集團的Faas平台,完成Node.js這部分的一些業務上雲。2020年十一很好的支撐了高德的十一出行節業務。
C++ Faas沒有現有的解決方案,是以我們決定在集團的基礎設施之上做加法,建立C++ Faas基礎平台,來助力高德用戶端上雲。
1.1.1 端雲一體的最佳實踐關鍵:用戶端和Faas之間的接口抽象
原本用戶端的邏輯移到Faas服務端上來,或者新的需求一部分在Faas服務端上開發,這裡的成敗關鍵點在于:用戶端和Faas的接口協定定義,也就是Faas的API定義。好的API定義除了對系統的可維護性有好處以外,對後續支撐業務的疊代開發也很重要。
理想情況下:用戶端做成一個解析Faas傳回結果資料的一個浏覽器。浏覽器協定一旦定義好,就不會經常變換,你看IE,Chrome就很少更新。
當然我們的這個浏覽器會複雜一些,我們這個浏覽器是地圖浏覽器。如何檢驗用戶端和Faas之間的接口定義好不好,可以看後續的産品需求疊代,如果有些産品需求疊代隻需要在Faas上完成,不需要用戶端的任何修改,那麼這個接口抽象就是成功的。
1.2 BFF層開發提效
提到高德,大家首先想到的應該是其工具屬性:高德是一個導航工具,(這個說法現在已經不太準确了,因為高德這幾年在做工具化往平台化轉型,高德的交易類業務正在興起,高德打車、門票、酒店等業務發展非常迅猛)。針對高德導航來說,相比集團其他業務,相比電商來說,有大量的隻讀場景是高德業務的一大技術特點。
這些隻讀場景裡,大量的需求是BFF(Backend For Frontend)類型的隻讀場景。為什麼這麼說,因為導航的最核心功能,例如routing, traffic, eta等都是相對穩定的,這部分的主要工作在用持續不斷的優化算法,使得高德的導航更準,算出的路徑更優。這些核心功能在接口和功能上都是相對比較穩定的,而前端需求是多變的,例如增加個路徑上的限寬墩提示等。
Faas特别适合做BFF層開發,在Faas上調用後端相對穩定的各個Baas服務,Faas服務來做資料和調用邏輯封裝,快速開發、釋出。在業界,Faas用的最多的場景也正是BFF場景(另外一個叫法是SFF場景,service for frontend)。
1.3 Serverless是雲時代的進階語言
雖然高德已經全面上雲了,但是目前還不是雲時代的終局,目前主要是全面Docker化并上雲,容器方面做了标準化,在規模化,資源使用率方面可以全面享受雲的紅利,但是業務開發模式上基本還和以前一樣,還是一個大型的分布式系統的寫法。
對于研發模式來說還并沒有享受雲的紅利,可以類比為我們現在是在用彙編語言的方式來寫跑在雲上的服務。而Serverless、雲原生可以了解為雲時代的進階語言,真正做到了Cloud as a computer,隻需要關注于業務開發,不需要考慮大型分布式系統的各種複雜性。
1.4 Go-Faas補充Go語言生态
前面講到了因為用戶端上雲項目,我們在阿裡雲FC(函數計算)團隊之上做加法,開發了C++ Faas Runtime。
不僅如此,我們還開發了Go-Faas,為什麼會做Go-Faas呢,這裡也簡單介紹一下背景,高德服務端Go部分的QPS峰值已超百萬。高德已補齊了阿裡各中間件的Go用戶端,和集團中間件部門共建。可觀測性、自動化測試體系也基本完善,目前Go生态已基本完善。補齊了Go-Faas之後,我們就既能用Go寫Baas服務,又能用Go寫Faas服務了,在不同的業務場景采用不同的服務實作方式,Go-Faas主要應用于上文提到的BFF場景。
2. 技術方案介紹——在集團現有基礎設施之上做加法
2.1 整體技術架構
上文講了我們為什麼要做這個事情,現在來講一下我們具體是怎麼做這個事情:如何實作,具體的技術方案是什麼樣的。
我們本着在集團現有的基礎設施、現有的中間件基礎之上做加法的思想,我們和CSE,阿裡雲FC函數計算團隊合作共建,開發了C++ Faas Runtime 和 Go Faas Runtime。整體和集團拉通的技術架構如下圖所示,主要分為研發态、運作态、運維态三個部分。
2.1.1 運作态
先說運作态,業務流量從網關進來,調用到FC API Server,轉發到C++/Go Faas Runtime,Runtime來完成使用者函數裡的功能。Runtime的架構下一章節來具體介紹。
和Runtime Container一起部署的有監控、日志、Dapr各種Side car,Side car來完成各種日志采集上報功能,Dapr Side car來完成調用集團中間件的功能。
另外,目前Dapr還在試點的階段,調用中間件主要是通過Broker和各個中間件Proxy來完成,中間件調用的有HSF,Tair,Metaq,Diamond等中間件Proxy。
最後Autoscaling子產品來管理函數執行個體的擴縮容,達到函數自動伸縮的目的。這裡的排程就有各種政策了,有根據請求并發量的排程,函數執行個體的CPU使用率的排程。也能提前設定預留執行個體數,避免縮容到0之後的冷啟動問題。
底層調用的是集團ASI的能力,ASI可以簡單了解為集團的K8S + Sigma(集團的排程系統),最終的部署是FC調用ASI來完成函數執行個體部署。彈性伸縮的,部署的最小機關是上圖中的POD,一個POD裡包含Runtime Container和Sidecar Set Container。
2.1.2 研發态
再來看研發态,運作态是決定函數是如何運作的,研發态關注的函數的開發體驗。如何友善的讓開發者開發、調試、部署、測試一個函數。
C++ Faas有個跨平台的難點問題,C++ Faas Runtime裡有一些依賴庫,這些依賴庫沒有Java依賴庫管理那麼友善。這些依賴庫的安裝比較麻煩,Faas腳手架就是為了解決這個問題,調用腳手架,一鍵生成C++ Faas示例工程,安裝好各種依賴包。為了本地能友善的Debug,開發了一個C++ Faas Runtime Boot子產品,函數Runtime啟動入口在Boot子產品裡,Boot子產品裡內建Runtime和使用者Faas函數,可以對Runtime來做Debug單步調試。
我們和集團Aone團隊合作,函數的釋出內建到Aone環境上了,可以很友善的在Aone上來釋出Go或者C++ Faas,Aone上也內建了一鍵生成Example代碼庫的功能。
C++和Go Faas的編譯都依賴相應的編譯環境,Aone提供了自定義編譯鏡像的功能,我們上傳了編譯鏡像到集團的公共鏡像庫,函數編譯時,在函數的代碼庫裡指定相應的編譯鏡像。編譯鏡像裡安裝了Faas的依賴庫,SDK等。
2.1.3 運維态
最後來看函數的運維監控,Runtime内部內建了鷹眼、Sunfire采集日志的功能,Runtime裡面會寫這些日志,通過Sidecar裡的Agent采集到鷹眼、或者Sunfire監控平台上去(FC是通過SLS來采集的)之後,就能使用集團現有的監控平台來做Faas的監控了。也能接入集團的GOC報警平台。
2.2 C++/Go Faas Runtime架構
上面講的是和Aone,FC/CSE,ASI內建的一個整體架構,Runtime是這個整體架構的一部分,下面具體講講Runtime的架構是怎樣的,Runtime是如何設計和實作的。
最上面部分的使用者Faas代碼隻需要依賴Faas SDK就可以了,使用者隻需要實作Faas SDK裡的Function接口就能寫自己的Faas。
然後,如果需要調用外部系統,可以通過SDK裡的Http Client來調用,如果要調用外部中間件,通過SDK裡的Diamond/Tair/HSF/Metaq Client來調用中間件就可以。SDK裡的這些接口屏蔽了底層實作的複雜性,使用者不需要關心這些調用最後是如何實作,不需要關心Runtime的具體實作。
SDK層就是上面提到的Function定義和各種中間件調用的接口定義。SDK代碼是開發給Faas使用者的。SDK做的比較輕薄,主要是接口定義,不包含具體的實作。調用中間件的具體實作在Runtime裡有兩種實作方式。
再來看上圖中間藍色的部分,是Runtime的一個整體架構。Starter是Runtime的啟動子產品,啟動之後,Runtime自身是一個Server,啟動的時候根據Function Config子產品的配置來啟動Runtime,Runtime啟動之後開啟請求和管理監聽模式。
往下是Service層,實作SDK裡定義的中間件調用的接口,包含RSocket和Dapr兩種實作方式,RSocket是通過RSocket broker的模式來調用中間件的,Runtime裡內建了Dapr(distributed application runtime) ,調用中間件也可以通過Dapr來調用,在前期Dapr試點階段,如果通過Dapr調用中間件失敗了,會降級到RSocket的方式來調用中間件。
再往下就是RSocket的協定層,封裝了調用RSocket的各種Metadata協定。Dapr調用是通過GRPC方式來調用的。最下面一層就是內建了RSocket和Dapr了。
RSocket調用還涉及到Broker選擇的問題,Upstream子產品來管理Broker cluster,Broker的注冊反注冊,Keepalive檢查等等,LoadBalance子產品來實作Broker的負載均衡選擇,以及事件管理,連接配接管理,重連等等。
最後Runtime裡的Metrics子產品負責鷹眼Trace的接入,通過Filter模式來攔截Faas鍊路的耗時,并輸出鷹眼日志。列印Sunfire日志,供Sidecar去采集。下圖是一個實際業務的Sunfire監控界面:
2.2.1 Dapr
Dapr架構見下圖所示,具體可以參考看官方文檔
Runtime裡以前調用中間件是通過RSocket方式來調用的,這裡RSocket Broker會有一個中心化問題,為了解決Outgoing流量去中心化問題,高德和集團中間件團隊合作引入了Dapr架構。隻是Runtime層面內建了Dapr,對于使用者Faas來說無感覺,不需要關心具體調用中間件是通過RSocket調用的還是通過Dapr調用的。後面Runtime調用中間件切換到Dapr之後,使用者Faas也是不需要做任何修改的。
3. 業務如何接入Serverless
如前文所述,統一在Aone上接入。我們提供了C++ Faas/Go Faas的接入文檔。提供了函數的Example代碼庫,代碼庫有各種場景的示例,包括調用集團各種中間件的代碼示例。
C++ Faas/Go Faas的接入面向整個集團開放,目前已經有一些高德以外的BU,在自己的業務中落地了C++ /Go Faas了。
Node.js Faas使用淘寶提供的Runtime和模闆來接入,Java Faas使用阿裡雲FC提供的Runtime和模闆來接入就可以了。
3.1 接入規範——穩定性三闆斧:可監控、可灰階、可復原
針對落地新技術大家可能擔心的穩定性問題,應對法寶是阿裡集團的穩定性三闆斧:可監控、可灰階、可復原。建立Faas鍊路保障群,拉通上下遊各相關業務方、基礎平台一起,按照集團的1-5-10要求,做到1分鐘之内響應線上報警,快速排查,5分鐘之内處理;10分鐘之内恢複。
為了規範接入過程,避免犯錯誤引發線上故障,我們制定了Faas接入規範和CheckList,來幫助業務方快速使用Faas。
可監控、可灰階、可復原是硬性要求,除此之前,業務方如果能做到可降級就更好了。我們的C++用戶端上雲業務,在開始試點的階段,就做好了可降級的準備,如果調用Faas端失敗,本次調用将會自動降級到本地調用。基本上對于用戶端功能無損,隻是會增加一些響應延遲。
另外,用戶端上該功能的版本,可能會比服務端稍微老一點,但是功能是向前相容的,基本不影響用戶端使用。
4. 我們目前的情況
4.1 基礎平台建設情況
- Go/C++ Faas Runtime開發完成,對接FC-Ginkgo/CSE、Aone完成,已釋出穩定的1.0版本。
- 做了大量的穩定性建設、優雅下線、性能優化、C編譯器優化,使用了阿裡雲基礎軟體部編譯器優化團隊提供的編譯方式來優化C++ Faas的編譯,性能提升明顯。
- C++/Go Faas接入鷹眼、Sunfire監控完成,函數具備了可觀測性。
- 池化功能完成,具備秒級彈性的能力。池化Runtime鏡像接入CSE,擴一個新執行個體的時間由原來的分鐘級變為秒級。
4.2 高德的Serverless業務落地情況
C++ Faas和Go Faas以及Node.js Faas在高德内部已經有大量應用落地了。舉幾個例子:
上圖中的前兩個圖是C++ Faas開發的業務:長途天氣、沿途搜。後兩個截圖是Go-Faas開發的業務:導航Tips,足迹地圖。
高德是阿裡集團内Serverless應用落地規模最大的BU,已落地的Serverless應用,日常峰值早已超過十萬QPS量級。
4.3 主要收益
高德落地了集團内規模最大的Serverless應用之後,都有哪些收益呢?首先,第一個最重要的收益是:開發提效。我們基于Serverless實作的端雲一體元件,助力了用戶端上雲,解除了需求實作時的用戶端發版依賴問題,提升了用戶端的開發疊代效率。基于Serverless開發的BFF層,提升了BFF類場景的開發疊代效率。
第二個收益是:運維提效。利用Serverless的自動彈性擴縮容技術,高德應對各種出行高峰就更從容了。例如每年的10-1出行節,5-1、清明、雙旦、春節的出行高峰,不再需要運維或者業務開發同學在節前提前擴容,節後再縮容了。
高德業務高峰的特點還不同于電商的秒殺場景。出行高峰的流量不是在一秒内突然漲起來的,我們目前利用池化技術實作的秒級彈性的能力,完全能滿足高德的這個業務場景需求。
第三個收益是:降低成本。高德的業務特點,白天流量大、夜間流量低,高峰值和低谷值差異較大,時間段區分明顯。利用Serverless在夜間流量低峰時自動縮容技術,極大的降低了伺服器資源的成本。
5. 後續計劃
- FC彈内函數計算使用優化,和FC團隊一起持續優化彈内函數計算的性能、穩定性、使用體驗。用集團内的豐富的大流量業務場景,不斷打磨好C++/Go Faas Runtime,并最終輸出到公有雲,普惠數字化轉型浪潮中的更多企業。
- Dapr落地,解決Outcoming流量去中心化問題,逐漸上線一些C++/Go Faas,使用Dapr的方式調用集團中間件。
- Faas混沌工程,故障演練,逃生能力建設。Faas在新财年也會參與我們BU的故障演練,逐一解決演練過程中發現的問題。
- 接入邊緣計算。端雲一體的場景下,Faas + 邊緣計算,能提供更低的延時,更好的使用者體驗。
以上要做的事情任重道遠,另外我們未來還會做更多雲原生的試點和落地,技術同學都知道,從技術選型、技術原型到實際業務落地,這之間還有很長的路要走。
歡迎對Serverless、雲原生、或者Go應用開發感興趣的小夥伴,想一起做點事情的同學來加入我們(不管之前是什麼技術棧,英雄不問出處,投履歷到 [email protected],郵件主題為:姓名-技術方向-來自高德技術),這裡有大規模的落地場景和簡單開放的技術氛圍。歡迎自薦或推薦。
