資深CTO帶來的8條Serverless最佳實踐
多年來,社區一直在討論最佳實踐,但只有一小部分能夠為人們所接受。
大多數遵循這些實踐的無伺服器從業者面對的是大規模的工作場景。無伺服器架構承諾在大規模和突發性工作負載上發揮作用,所以大部分最佳實踐更關注規模化問題,例如零售行業的 Nordstrom 公司和物聯網領域的 iRobot。如果你的目標還達不到那樣的規模,可能就無需遵循這些最佳實踐。
請記住,最佳實踐並非「唯一的實踐」。最佳實踐是以一系列基本假設為前提,如果你的場景不存在這些假設,那麼這些最佳實踐可能就不合適你。
我的主要假設是所有人構建的應用程序都能夠大規模運行(即使它們可能永遠不會)。
以下是我認為的最佳實踐。
1
一個 function 應該只做一件事
這個最佳實踐與 function 的錯誤和伸縮隔離有關。
換句話說,如果在 function 中使用 switch 語句,那麼你可能是做錯了。
很多教程和框架都是基於 function 大單體,然後在單體前面加上單個代理路由,並使用 switch 語句。我不喜歡這種模式,因為它的伸縮性不好,並且往往會產生大而複雜的 function。
這樣做的問題在於,當你想要進行擴展時,需要擴展整個應用程序,而不是某些特定的元素。
假設 Web 應用程序的一部分需要處理 100 萬的流量,而另一部分只需要處理 1 千的流量,而當你需要對前者進行優化時,也不得不捎帶上後者。這是一種浪費,而且你無法輕易做到對後者的優化。所以,建議將它們分開。
2
不讓 function 調用其他 function
調用其他 function 的 function 是一種反模式。
這種模式在很少情況下是有效的,但從根本上說,還是不要這樣做。這樣會成倍增加你的成本,讓調試變得更複雜,而且抵消了隔離 function 所帶來的價值。
function 應該將數據推送到數據存儲或隊列中,然後通過觸發另一個 function 來完成其他的工作。
3
儘可能少在 function 中使用額外的庫
這點對於我來說是顯而易見的。
function 有冷啟動(function 第一次啟動)和暖啟動(function 已經啟動,並準備好被執行)兩個階段。冷啟動受到很多因素的影響,比如 zip 文件的大小(或者被上傳的代碼)和需要實例化的庫的數量。
代碼越多,冷啟動的速度就越慢。
需要實例化的庫越多,冷啟動的速度也就越慢。
例如,Java 在某些平台上算是一門實現暖啟動的高性能語言。但如果你使用太多的庫,你會發現它需要很多秒才能完成冷啟動。有些庫不是必需的,況且冷啟動性能不僅會影響啟動,還會影響伸縮。
我堅信開發人員應該只在必要的情況下才使用額外的庫。
像 express 這樣的東西是為伺服器而生的,無伺服器應用程序不需要用到它的所有元素。既然這樣,為什麼還要引入它的所有代碼和依賴項呢?為什麼要引入多餘的代碼?多餘的代碼不僅不會被運行,還會帶來安全風險。
當然,如果一個庫已經經過你的測試,而且你了解和信任它,那麼就可以引入它。
4
避免使用基於連接的服務
除非真的有必要,否則不要使用基於連接的服務。
這個會讓我陷入大麻煩。很多 Web 應用程序開發者都會陷入「我們只知道 RDBMS」的陷阱。
但重點不在於 RDBMS,而在於連接。
無伺服器最適合與服務一起協作,而不是連接。
服務旨在快速對請求做出響應,並處理數據層的複雜性。這在無伺服器領域具有巨大價值,也解釋了為什麼像 DynamoDB 這樣的資料庫非常適用於無伺服器架構。
說實話,無伺服器從業者並不反對 RDBMS,他們反對的是連接。連接需要時間,而且你試想一下,當一個 function 擴展到多個,每個 function 環境都需要一個連接,這樣就給 function 冷啟動引入了瓶頸和 I/O 等待,但其實這些是沒有必要的。
如果你一定要使用 RDBMS,可以在中間放置一個連接池服務,如果是某種可以自動伸縮的容器,那就更好了。
關鍵是,你可能需要重新思考數據層,這不是無伺服器的錯。如果你嘗試重用當前的數據層,但不奏效,那可能是因為你對無伺服器架構缺乏理解。
5
一個路由對應一個 function
儘可能避免使用單一的 function 代理。它無法進行伸縮,也無助於隔離問題。在某些情況下,你可以使用單一的代理,例如:一系列路由功能被綁定到一個表上,並且它與應用程序的其餘部分相對獨立。但在我工作過的大多數應用程序中,這種情況只是個例。
雖然避免使用單一代理會增加管理方面的複雜性,但在擴展應用程序時,它確實有助於隔離錯誤。
話說回來,你會使用某種配置管理工具來運行這些東西,不是嗎?你已經在使用某種 CI 和 CD 工具,對嗎?所以,無伺服器仍然需要 DevOps。
6
學習使用消息和隊列
如果應用程序是非同步的,無伺服器往往會帶來最佳的效果。對於那些傾向於進行請求響應和大量查詢的 Web 應用程序來說,這可能不是很明顯。
之前說過,最好不要讓 function 直接調用其他的 function,所以如何將 function 鏈接在一起是一個很重要的問題。可以將隊列作為斷路器,如果一個 function 失效,只需要清空因為故障而堆積起來的隊列,或者將失敗的消息推送到死信隊列(DLQ)。
基本上就是要了解分散式系統的工作原理。
對於帶有無伺服器後端的客戶端應用程序,最好的方法是使用 CQRS。這個模式的關鍵之處在於將獲取數據的關注點和輸入數據的關注點分離開來。
7
數據流,而不是數據湖
在無伺服器系統中,數據將流經你的系統。它們最終可能會形成數據湖,但更可能的情況是,它們會處於某種流動的狀態。因此,任何時候都要將數據視為動態的,而不是靜止的。
雖然這樣做並非總是可行的,但一定要盡量避免在無伺服器環境中查詢數據湖。
無伺服器要求你重新思考數據層。對於剛進入無伺服器領域的新手來說,他們總是傾向於以 RDBMS 的方式考慮問題,他們極有可能會碰壁,不僅是因為伸縮問題,也因為他們的數據結構變得過於僵化。
你會發現數據流會隨著應用程序的變化而發生變化,而伸縮將會改變所有的一切。如果你所要做的只是重定向一個數據流,那很容易,但要為資料庫築壩可是要難得多。
8
了解應用程序是如何伸縮的
創建第一個無伺服器應用程序很容易,然後你看著它擴展。如果你不了解自己所做的一切,那麼就很容易陷入與其他自動擴展方案相同的陷阱當中。
如果你不了解應用程序是如何伸縮的,有可能會讓自己陷入麻煩之中。如果你使用緩慢的冷啟動(依賴了很多庫並使用了 RDBMS),然後碰上突發的高峰流量,就會急劇增加 function 的並發量,讓連接數爆棚,從而拖慢了應用程序。
所以,不要認為應用程序一定會在相同的負載下運行。了解應用程序處於不同負載之下的行為仍然是工作內容的一部分。
9
結論
我可以在這裡說更多的東西,不過以上這些是我在與其他人交談時最想告訴他們的。我沒有提到過如何規劃應用程序,或者如何考慮應用程序的成本,因為它們超出了本文的討論範圍。我敢肯定,很多人會說我對 RDBMS 的看法是不對的。與容器一樣,我並不討厭 RDBMS,我只是喜歡在工作中使用對的工具。所以,先了解你的工具!
英文原文:
https://medium.com/@PaulDJohnston/serverless-best-practices-b3c97d551535
※不想硬啃理論和演算法,我還能入門深度學習嗎?
※開發要不要自己做測試?怎麼做?
TAG:InfoQ |