目前微店中臺團隊爲了知足公司大部分產品、運營以及部分後端開發人員的嚐鮮和試錯的需求,提供了一套基於圖形化搭建的服務端接口交付方案,利用該方案及提供的系統可生成一副包含運行時環境定義可當即運行的工程代碼,最後,經過 「某種serverless平臺」 實現生成後代碼的部署、CI、運行、反向代理、進程守、日誌上報、進程分組擴容等功能。前端
這樣,產品和運營人員可基於此種方式搭建的接口配合經常使用的cms系統實現簡單查詢需求如活動大促的自主「研發」上線,代碼的可靠性、穩定性由中臺研發側提供的「某種serverless平臺」保障,有效支撐了多個業務快速上線,節省後端開發人員的人力與硬件資源的開銷(大多數需求下,nodejs業務對虛擬機的資源開銷小於java業務)。java
此處並不講解接口搭建系統的原理與實現,只說明其與上文提到的 「某種serverless平臺」 的關係。node
這是系統的全貌,部分細節因爲敏感信息而省略。平臺使用方可基於每一個功能組件搭建出一套複雜的業務流,在搭建階段,提供在線debug和日誌功能,可用於排錯;在部署CI階段,可集成不一樣的運行時平臺,既能夠是自主實現的運行時,也但是第三方雲平臺;在運行階段,經過使用agentool工具實時監控當前服務的性能,並可經過traceId一覽請求在各系統的全貌。git
本節以資源隔離粒度爲度量,介紹了我對三種serverless方案的取捨以及最終爲什麼選擇了隔離程度更高的kubeless雲平臺。github
Parse Server提供了基礎功能:基於類與對象的權限控制、基於document的nosql存儲、簡易的用戶身份認證、基於hook的自定義邏輯等,但通過筆者的調查與論證,最終並無採用相似單進程下基於函數隔離的Parse Server及相似方案,這有幾點緣由:sql
Parse Server官網docker
爲了解決多個服務搶佔libuv的問題,我選擇了自主研發的 super-agent方案,經過其名稱即可知它是一個超級代理,但它不只是代理,仍是一個具備極簡功能且可靠的發佈系統和運行時容器;它是一個分佈式應用,節點間功能劃分明確;它同時提供實時調試功能。express
super-agent是一個多角色分佈式系統,它便可以看作node容器,也可當作serverless的node實現,它以進程爲粒度管理服務。它分爲「協調者」和「參與者」,協調者實現 應用CI部署、啓動、進程維護與管理和反向代理功能,參與者實現 業務請求代理、接受協調者調度。後端
在super-agent架構中,端口是區分服務的惟一標識,端口對客戶端而言是透明的,這層端口資源的隔離由super-agent來作掉,所以多個服務可避免在libuv層的互相競爭,提供水平擴容的可能性。super-agent最核心的功能在於反向代理。因爲每一個服務都被包裝成有單獨端口的獨立HTTP應用,所以當用戶請求流量通過前端轉發層後進入super-agent,由其根據相關規則作二次轉發,目前支持基於 「路徑、端口」規則的轉發。安全
後端應用部署須要進行 「優雅降級、流量摘除、健康檢查、應用初始化完畢檢查、流量導入、全部參與節點的部署狀態查詢」 等步驟,須要妥善處理;同時,協調者負責協調衆多參與節點所有完成部署操做,這是一個分佈式事務,須要作好事務出錯後的相關業務補償。
上圖並未畫出節點角色的區別,實際上只有參與者節點才真正接受用戶請求。
協調者流量所有來自於內部系統,包括接受 「接口搭建系統」調用或者其餘系統實現的dashboard服務;同時其會向參與者發送相關信令信息,如部署、擴容、下線、debug等。
參與者流量來自於內部系統和外部流量,其中大部分來自於外部流量。內部流量則承載協調者的信令信息。
服務的水平擴容重要性不言而喻。super-agent方案中,協調者負責管理服務的擴容與邏輯分組。
此處的服務是經過服務搭建平臺經過拖拽生成的nodejs代碼,它是一個包含複雜業務邏輯的函數,能夠是多文件。具體的,super-agent經過將該服務包裝成一個HTTP服務在單獨的進程中執行。所以,若是要對服務進行水平擴容,提供多種策略的選擇:
這些策略對下游應用透明,只需選擇相關策略便可。
水平擴容的缺點:每臺虛擬機或物理機資源有上限,一個正常的node進程最多消耗1.4GB內存,計算資源共享,在一臺8C16G的虛擬機上,最多可同時運行16個服務。及時經過分組擴容的方式,每當擴展新的虛擬機或物理機,都須要由super-agent根據分組信息實現進程守護,同時每次服務CI部署也一樣如此。運維管理上須要配合很是清晰明瞭的dashboard後臺才能快速定位問題,這點在多服務的問題上尤爲突出。
super-agent提供消息機制,由搭建平臺中組件開發人員使用提供的serverless-toolkit工具debug相關邏輯,最終可在super-agent的協調者後臺查看實時debug結果。
super-agent是符合常規的基於業務進程隔離的解決方案,它有效的支撐了微店的幾個活動及產品,雖然峯值QPS不高(100左右),但它也論證了super-agent的穩定性及可靠性(線上無事故,服務無重啓,平穩升級)。
可是,super-agent仍然存在幾個問題,它讓咱們不得不另覓他法:
基於kubeless的方案則是隔離最爲完全的解決方法,kubeless是創建在K8s之上的serverless框架,所以它能夠利用K8s實現一些很是有用的特性:
其中,自動伸縮則解決了 super-agent 的痛點。
kubeless中與咱們緊密相關的有兩個概念:「function和runtime」 ,function是一個統稱,它包括運行時代碼、依賴以及其餘配置文件;runtime則定義運行時依賴的環境,是一個docker鏡像。
若要接入kubeless平臺,咱們須要解決以下幾個問題:
所以,前進的道路仍然很曲折,並且不少需求須要本身從源碼上去尋找解決方法。
kubeless實現的serverless體系中,function所在pod中的全部容器共享網絡和存儲namespace,可是默認外網是不可訪問k8s集羣的全部pods,所以須要經過一層代理實現請求的轉發,這就是「Service」。Service負責服務發現及轉發(iptables四層),所以在Kubeless或者K8s中不會直接經過pod IP來訪問服務,而是經過Service轉發四層流量完成。Service有K8s分配的cluserIp,clusterIp是集羣內部虛擬IP,沒法被外部尋址,而是經過Kube-Proxy在容器網絡之上又抽象了一層虛擬網絡,Kube-Proxy負責Service的路由與轉發(關於kube-proxy細節,請看參考資料)。
Service後端對應是一個或多個pods,這些pods中的一個容器則運行相同的業務代碼。那麼流量是如何路由至Service上來呢?這就涉及到Service的「發佈」,經常使用的是Ingress。Ingress包括HTTP代理服務器和ingress controller,代理服務器負責將請求按照規則路由至對應Service,這層須要Kube-Proxy實現虛擬網絡的路由;ingress controller負責從K8s API拉取最新的HTTP匹配規則。
運行在kubeless 中的函數和運行在super-agent的代碼沒有什麼不一樣,但是周邊的環境準備可大大不一樣。爲了讓kubeless中的function能夠接入公司內部中間件服務,筆者費了很多功夫,主要集中在日誌及收集部分。好在事在人爲,解決的辦法老是多於失敗的方法。
目前,super-agent方案已承載了10+個線上應用或活動,穩定運行4個月,資源使用率符合預期;
kubeless方案還未正式接入流量,等待進一步作相關異常測試。