關於雲函式冷啟動優化的思考

Kindear發表於2021-12-04

關於雲函式冷啟動優化的思考

​ 隨著容器技術的廣泛應用,XaaS形式的概念層出不窮。從IaaS(Infrastructure as a Service)、PaaS(Platform as a Service)、SaaS(Software as a Service)到容器雲引領的CaaS(Containers as a Service),再到火熱的微服務架構,它們都在試著將各種軟、硬體資源等抽象為一種服務提供給開發者使用,讓他們不再擔心基礎設施、資源需求、中介軟體等等,在減輕心智負擔的同時更好地專注於業務。FaaS是Functions as a Service的簡稱,它往往和無服務架構(Serverless Architecture)一同被提起。

​ 小程式開發雲函式正是FaaS形式的架構,微信官方對其推崇至極。但是實際的應用情況我們有目共睹,雲函式的冷啟動對客戶端帶來的是高延遲的糟糕體驗。一個雲函式冷啟動,需要經過資源排程,程式碼下載,程式碼部署幾個步驟。還沒等到執行程式碼邏輯,使用者已經退出程式了。如果僅僅從雲函式現在的表現出發進行分析,想要去撼動現在市場格局是遠遠不夠的。

​ 本人技術水平有限,也不知道雲開發的完整的技術框架,只從可能的幾個角度進行分析,找尋可能存在的優化方向,如果錯誤,希望各位不吝斧正。

# 思路一

​ 在雲函式中呼叫另一個雲函式邏輯,假設執行 \(A\) 雲函式邏輯需要 \(T_1\) 時長,冷啟動需要 \(C_1\) 時長,執行 \(B\) 雲函式邏輯需要 \(T_2\) 時長,冷啟動需要 \(C_2\) 時長。

那麼執行這個邏輯的需要總時長大概是 \(T_1 + C_1 + T_2 + C_2\)

​ 那麼是否可以對上傳的雲函式程式碼進行上下文分析,如果雲函式中存在對其他雲函式(如 \(B\) 雲函式)的呼叫,在冷啟動 \(A\) 雲函式時,也排程資源給 \(B\) 雲函式。

思路簡述如下:

  1. 對上傳程式碼分析,將上下文出現的對其他雲函式的呼叫記錄下來,記作 link_container_list
  2. 在呼叫雲函式之前,檢查該雲函式的 link_container_list,冷啟動該雲函式同時,對link_container_list中的雲函式也進行冷啟動(資源排程)。

那麼執行這個邏輯的需要的總時長大概是 \(T_1 + T_2 + max\{C_1,C_2\}\)

該思路可以進行擴充,即使有\(N\) 個相關的雲函式,那麼理想情況下最終執行的邏輯時長,也是 \(\sum_{i=1}^{n}T_i + max\{C_1,...,C_n\}\)

# 思路二

​ 雲函式建立對應資源容器時,裝載的資源包括號稱比黑洞更重的node_modules依賴檔案等。這或許是影響冷啟動速度的原因之一。

那麼服務提供商是否可以維護這樣一個容器池,容器池中存放著已經裝載完依賴環境的半完成態容器。

如何維持半完成態的容器?

​ 使用者第一次呼叫雲函式時,以nodejs雲函式為例,判斷package.json檔案中的依賴,容器池中是否有滿足的半完成態容器,將對應容器直接分配該使用者,半完成態容器直接裝載業務邏輯程式碼,跳過裝載依賴檔案和環境這一步。

# 思路三

​ 考慮業務上的相關聯,比如說對於購物小程式來說,當使用者呼叫查詢商品詳情雲函式 \(A\) 時,那麼下一步使用者可能就要呼叫 統一下單雲函式\(B\) 。顯然,在呼叫 \(A\) 雲函式時,對 \(B\) 雲函式進行資源容器預裝載是合理的,一般習慣稱這種方法叫預熱。 這是業務邏輯上的關聯,然而不同的程式有不同的關聯邏輯,服務提供商是否可以提供一個配置檔案,由開發者指定預熱的雲函式資源容器。

​ 例如對於查詢商品詳情的雲函式\(A\) , 假定其關聯預熱雲函式檔名為trigger.json

{
	"uniOrder",//統一下單
	"addCart",//加入購物車
	"addFavor"//加入手冊
}

​ 當呼叫雲函式 \(A\) 時,就會預熱 uniOrder等雲函式。

​ 現在對於這種預熱方法的實現方式,是在呼叫雲函式 \(A\) 的時候,在執行程式碼邏輯內部 cloud.callFunction() 來提前預熱雲函式,這種寫法方式不夠優雅,而且如果對正常觸發和預熱觸發邏輯處理不夠完善,還可能會引起其他問題。

# 思路四

​ 既然冷啟動的原因是因為資源容器會被銷燬,再次觸發需要重新建立,那麼為什麼不能一次建立長期維持呢?保持最小的資源消耗的情況下,使得雲函式容器不被銷燬,相比較於每次冷啟動對使用者端明顯的互動影響,這些微不足道的資源消耗簡直不值一提。服務商可以給願意付出資源消耗量的開發者提供配置,由開發者指定每次建立容器的存活時間。

​ 例如在config.json檔案中新增配置項keep_alive:60,就代表容器如果60分鐘內無操作才會被銷燬。配置為 0 代表永不銷燬,然後為開發者提供個主動銷燬容器的方法呼叫。

​ 現階段,開發者們常用維護容器狀態的思路是配置定期器,每隔一段時間觸發一次,以維持容器不被銷燬,這樣子對資源的消耗量其實是比較大的。而且是不夠優雅,屬於空邏輯,還需要為觸發器實現專門的空邏輯處理部分,防止對業務程式碼產生干擾。

# 思路五

​ 既然客戶端開發可以使用外掛,可以依賴於第三方服務,那麼為什麼雲函式不可以呢?雲服務商可以提供常駐的通用的雲函式服務,如提供一個使用者角色許可權管理雲函式,不需要使用者自己設計部署,由官方提供呼叫方式即可。

亦或者是提供一個地址管理雲函式,與官方資料打通,使用雲函式提供呼叫方法等等,不勝列舉。

​ 總而言之,言而總之,我是很喜歡FaaS架構的開發形式,如果能解決冷啟動對互動體驗的影響,我相信會有更多的開發者投身於這個生態中。

參考文獻

[1] 苗立堯. Faas,又一個未來? [EB/OL] 求知

[2] Linux中國. 如何提升你的雲函式效能 [EB/OL] 小程式官方社群

相關文章