騰訊云無服務器云函數架構精解
繼虛擬機,容器技術,無服務器化成為新的行業熱點,無服務器云函數可以讓用戶無需關心服務器的部署運營,只需開發最核心的業務邏輯,即可實現上線運營,具備分布容災能力,可依據負載自動擴縮容,按照實際調用次數與時長計費。本次主要分享騰訊云無服務器云函數在技術實現上的挑戰及架構實現原理。
主要從以下四個方面來分享一下無服務器云函數:
- 云函數的價值及使用場景
- 云函數架構原理
- 云函數關鍵技術點
- 云函數行業進展趨勢
無服務器云函數(Serverless Cloud Function)是騰訊云提供的無服務器(serverless)執行環境,幫助用戶在沒有購買和管理服務器時仍能運行代碼。用戶只需要使用云平臺支持的語言編寫核心代碼及設置代碼運行的條件,代碼即可在騰訊云基礎設施上彈性、安全地運行,并可完全管理底層計算資源,包括服務器CPU、內存、網絡、代碼部署、彈性伸縮、負載均衡等服務。
使用無服務器云函數將可免除所有運維性操作,企業和開發者可以更加專注于核心業務的開發,實現快速上線和迭代,把握業務發展的節奏。
一、云函數的價值及使用場景
隨著云計算服務市場的成熟,用戶對云計算接受程度逐漸提高,借助各類基礎云組件,將業務上線時間從月級縮短到天級,但對比傳統模式,用戶仍需基于云組件重構非功能性需求。
云函數嘗試將業務算法和流程提煉出來交由用戶實現,打通各種云服務,并實現通用的負載均衡、自動伸縮、故障容災、安全監管等通用功能,真正使得用戶像搭積木一樣打造個性化服務,將業務上線時間從天級縮短到分鐘級。
相比云主機,云函數更適合于支持微服務架構業務場景。以圖片多規格壓縮服務為例,該服務在用戶上傳圖片至COS時,自動將原始圖片壓縮成適配手機、平板、電腦等多種大小的規格。如利用云函數實現該服務,用戶只需創建函數,定義函數觸發條件為“圖片上傳”,在線編輯或使用IDE完成代碼編寫后上傳,服務即構建完成。用戶上傳圖片時,自動調用定義的函數完成圖片的多規格壓縮,云函數平臺根據上傳并發量自動擴縮容函數實例,并最終按照實際調用消耗計費。
從該示例可以看出,云函數為用戶帶來的主要價值為:
- 加快用戶服務上線時間,用戶只需實現業務算法及流程,上線時間縮短為分鐘級;
- 減少用戶的運營負擔,用戶無須承擔服務擴容,故障恢復運維工作;
- 消除用戶的資源成本,用戶無需承擔資源閑置費用,只為實際調用消耗付費
二、云函數架構原理
云函數平臺整體架構原理如圖所示。
云函數為用戶提供SDK/WEBUI兩種使用方式,并通過事件注冊與回調機制與其它云組件打通,提供標準的API接口;調用分發根據函數所屬的區域,用戶,名字,版本號,鑒權等信息申請函數實例,并將調用均勻的分發到可用函數實例;函數管理負責創建/修改/刪除函數,并提供函數代碼管理,版本管理等功能;函數調度根據函數資源需求選擇合適的位置創建/銷毀函數實例;函數實例部署用戶定義的函數,負責函數的執行及監管。
從云函數的定位及架構原理看,衡量云函數平臺的關鍵技術指標可概括為:
- 不僅支持業務快速上線,且能實現持續發展;
- 不僅支持業務按需取用,且能釋放閑置資源;
- 不僅支持業務永不中斷,且能擴展運行范圍;
- 不僅支持業務自由運行,且能避免干擾入侵;
下文將展開詳述。
三、支持業務快速上線,且能實現持續發展
支持業務分鐘級上線,需要盡可能的減少用戶研發工作量,云函數用戶僅需提供簡單的函數配置及代碼即可完成上線。以圖片壓縮為例,用戶自行編輯python代碼如下,即可實現一個圖片壓縮服務:
其中第1行引入依賴庫,第4~9行解析輸入參數,第11行調用庫完成圖片壓縮,12~15行判斷結果及返回。用戶可在線完成代碼的編輯并提交,也可像開發本地程序一樣使用喜歡的IDE編輯,調試通過后打成zip包通過SDK提交,提交成功服務即上線。
支持業務可持續發展,需提供用戶函數平滑升級及版本變更能力,當用戶更新函數代碼或配置后,新調用請求被分發至新函數實例,原調用請求執行完成后,舊函數實例自動消亡,服務在客戶不感知情況下平滑更新。即將支持用戶函數多版本管理,將函數別名映射至用戶指定版本,在客戶不感知情況下實現多版本間平滑切換。
函數運行過程中間,用戶打印日志,標準輸出/錯誤輸出日志分類上傳至騰訊云日志服務平臺,用戶可實時監控函數運行情況。
四、支持業務按需取用,且能釋放閑置資源
要支持云函數真正按需取用,需實現用戶第一次調用時延遲分配資源,函數調用過程如下圖所示:
云函數平臺在調用分發時,會判斷是否有函數實例存在,如若不存在,則實時啟動實例,實例啟動完成后,才開始執行函數調用。為了達到第一次調用足夠快的目標,在調用過程中需分階段逐層優化:
- 分發調用階段:需減少調用分發層級,比如對于用戶主動發起的http同步調用,正常路徑可免去存入持久化隊列過程;
- 鏡像及代碼下載階段:需盡量預部署以減少下載時間,比如對新提交函數,并行啟動預加載,使得第一次調用發起時無須再去實時下載;
- 容器啟動過程:需簡化容器啟動腳本,使得啟動過程盡量輕量,對于對延時敏感的業務,提供實例預留機制,用戶可選擇預留少量實例以減少第一次調用的額外延時;
- 執行函數調用:需盡量減少函數參數,返回數據及日志傳遞導致的內存拷貝次數;
- 返回調用:需盡量減少返回層級;
通過逐層優化,第一次調用平臺耗時可控制在2s左右,后續調用平臺耗時控制在5ms左右。隨著客戶請求量的增加或減少,函數實例隨著自動擴縮容,一般算法如下:
- If 當前請求數/當前實例數 > 擴容閾值:擴容實例
- else 當前請求數/當前實例數 < 縮容閾值:縮容實例
當縮容至最后一個函數實例時,為避免函數實例短時間內重復啟動/停止導致客戶調用延時增加,需保留一段時間延遲釋放。
五、支持業務永不中斷,且能擴展運行范圍
要支持云函數永不中斷,需實現2個容災目標:
- 硬件故障時服務不中斷
- 平臺升級時服務不中斷
為實現這三個容災目標,整體架構需實現set化,且在各層均需對應的支持:
- 接入層:基于騰訊云CLB實現橫向擴展,負載均衡,7層路由能力;
- 邏輯層:實現模塊無狀態化,模塊內部無狀態數據,可隨意啟停替換;
- 數據層:采用一致性存儲倉庫存儲關鍵數據;
- 節點層:實現快速節點故障檢測及替換恢復。
比如平臺內部Invoker模塊實例硬件故障時,如下圖所示,由于invoker模塊無狀態,故障時可由接入層CLB模塊自動剔除,剔除后新請求分發至剩余invoker模塊實例,已接收的異步事件可由其它invoker重試完成,同步http調用會直接返回給用戶錯誤請求,由用戶重試,在故障invoker實例恢復后,自動添加至CLB中,繼續分擔負載。
當平臺需要升級API接口時,采用只增不改策略,提供新版本API接口,保持用戶原有服務兼容性,用戶采用新接口時,CLB通過7層路由,路由至新版本invoker模塊實例,舊版本實例隨著負載的降低逐步縮容,新版本實例隨著負載升高逐步擴容,以此實現了用戶透明的版本平滑升級。
要實現云函數需與各類云組件打通,需要云組件提供事件注冊及回調機制,云組件提供可注冊事件及對應的回調接口,云函數確保云組件通信的用戶權限打通傳遞。當前云函數實現了與騰訊云COS存儲組件的打通,馬上將實現與騰訊云CMQ、云監控等其它云產品的打通,并將運行范圍擴展至CDN節點及IOT設備網關,實現邊緣計算。
六、支持業務自由運行,且能避免干擾入侵
云函數需支持用戶本地測試通過的代碼無縫在云函數平臺,需具備足夠的兼容性,及用戶函數運行時環境,需要具備和用戶開發測試環境類似的軟件包,安全等配置;同時避免函數間干擾,防止惡意入侵。
為了避免用戶函數間干擾,云函數使用了Docker容器來封裝函數實例,通過docker的名字隔離、空間隔離、權限限制等機制實現用戶間隔離,輔以實時沖突監控調度等措施及時處理干擾。
為了避免用戶執行代碼影響整個云函數平臺,如下圖所示,實現了云函數管理平臺與用戶函數的隔離,用戶函數無法感知管理平臺的網絡地址,運行日志等信息,從而無從影響云函數平臺的運行。
為了避免用戶惡意代碼對網絡的探測和入侵,如下圖所示,用戶函數實例被限制到了受限的公共VPC網絡,需通過網關實現與外網服務、其它函數實例、云組件的互訪,同時,為了支持用戶函數實例與個人CVM虛擬機的集成,云函數平臺通過彈性網卡打通了與其私有VPC的網絡通信。
七、云函數行業進展趨勢
近年Serverles、微服務等理念逐步深入人心,云函數開始被用戶了解接受。為了滿足用戶對于更快速上線、更低成本、更優架構的求索,騰訊云推出了云函數產品。用戶不妨從解決實際問題開始試用云函數,比如實現一個簡單的服務撥測工具,實現一個定時任務,實現存儲于COS的圖片、視頻、文件的計算等。。隨著云函數可聯動云組件的拓展,支持語言的豐富,調試工具,流程引擎等逐步完善,云函數會逐步成為整個云平臺的粘合劑,將各種云組件融合一起,讓云成為你的公共后臺,到時可支持更為復雜的狀態服務場景,成為用戶通用體貼厚實的后盾。
歡迎試用騰訊云無服務器云函數產品,云函數解決安全接入、故障容災、自動伸縮、成本優化、版本管理等后臺通用問題,用戶可更省心專注的投入到業務創新。希望通過云函數能更深入的開放騰訊多年在海量服務耕耘修煉的能力,共享給廣大用戶使用,與大家一起成長。
Q&A
Q:請問代碼怎么部署到docker中?
A:直接將代碼下載至母機,再將代碼目錄掛載至Docker
Q:云函數是通用的 還是只能在云平臺運行?
A:云提供了云函數服務,自己也可搭建,目前github上有不少開源云函數平臺,比如openlambda,iron.io等,建議直接使用云的服務,因為可以和多個云產品打通,單靠云函數自身難以構建完整服務。
Q:事件傳遞使用的是隊列嗎?
A:異步事件用了CMQ消息隊列持久化存儲,同步事件未使用
Q:請問云函數對開發語言有限制否?如果有,目前對Go語言的支持如何?
A:目前支持python 2.7/3.6, node.js 4.3/6.10, Java8,如果有通用的用戶需求,可以支持其它語言,比如php,go等
Q:有系統函數調用嗎?自定義函數的顆粒度有何建議?
A:絕大部分的系統調用都可調用,除了一些危險操作,比如關機,重啟,網絡服務監聽等,函數顆粒度可參考微服務的設計原則,將功能盡量拆細
Q:可落地嗎?
A:已有不少用戶案例,后續會做些分享,不妨親自試試,當前是免費的,會一直提供免費包,有需求直接給我們提
Q:云函數支持kotlin語言嗎?
A:之前沒用戶反饋需要這種語言的支持,不過我個人挺看好,會持續保持關注
Q:請問將請求調度函數實例,這個調度算法的實現?
A:其實這里就是通用的負載均衡和擴縮容算法,這里比較復雜的是提前預測需要擴容,后續會詳細分享。
Q:能介紹下 將請求調度到函數實例的實現嗎?
A:這里有個invoker模塊對每個函數維持有一個請求隊列,目前沒設置優先級,按照先來先到的順序依次調度,調度時會從函數所有可用的函數實例中,選擇一個下發。函數實例里有個循環接受請求,收到時傳遞參數調用用戶函數。
Q:代碼可以下云落地嗎?
A:代碼里一般會涉及其它云產品的調用,所以一般對云平臺有一些依賴,可以關注下開源的serverless框架,在公有云云函數上封裝了一層,用來解除依賴,實現在各個云平臺的平滑遷移。
Q:云函數的代碼有哪些限制?比如什么樣的函數不可以調用,什么樣的庫不能import?
A:可以基本認為無限制,但會禁止惡意行為,比如關機,重啟,端口掃描等;也會禁止端口監聽,因為常駐進程不符合云函數按需啟用的原則。如果預裝庫不符合要求,可以自行將依賴庫打包至zip里上傳。
Q:下層的容器編排是基于什么做的?k8s么?
A:基于騰訊云的容器平臺,其底層是K8S
分享人:陳杰,騰訊云架構平臺部技術專家,10年云計算經驗,現供職于騰訊架構平臺部,負責彈性計算及云函數技術研發,致力于提供領先的基礎設施平臺以提升資源利用率及優化提升程序員開發運維效率。