天天看點

資深CTO帶來的8條Serverless最佳實踐

多年來,社群一直在讨論最佳實踐,但隻有一小部分能夠為人們所接受。

\\

大多數遵循這些實踐的無伺服器從業者面對的是大規模的工作場景。無伺服器架構承諾在大規模和突發性工作負載上發揮作用,是以大部分最佳實踐更關注規模化問題,例如零售行業的Nordstrom公司和物聯網領域的iRobot。如果你的目标還達不到那樣的規模,可能就無需遵循這些最佳實踐。

\\

請記住,最佳實踐并非“唯一的實踐”。最佳實踐是以一系列基本假設為前提,如果你的場景不存在這些假設,那麼這些最佳實踐可能就不合适你。

\\

我的主要假設是所有人建構的應用程式都能夠大規模運作(即使它們可能永遠不會)。

\\

以下是我認為的最佳實踐。

\\

一個function應該隻做一件事

\\

這個最佳實踐與function的錯誤和伸縮隔離有關。

\\

換句話說,如果在function中使用switch語句,那麼你可能是做錯了。

\\

很多教程和架構都是基于function大單體,然後在單體前面加上單個代理路由,并使用switch語句。我不喜歡這種模式,因為它的伸縮性不好,并且往往會産生大而複雜的function。

\\

這樣做的問題在于,當你想要進行擴充時,需要擴充整個應用程式,而不是某些特定的元素。

\\

假設Web應用程式的一部分需要處理100萬的流量,而另一部分隻需要處理1千的流量,而當你需要對前者進行優化時,也不得不捎帶上後者。這是一種浪費,而且你無法輕易做到對後者的優化。是以,建議将它們分開。

\\

不讓function調用其他function

\\

調用其他function的function是一種反模式。

\\

這種模式在很少情況下是有效的,但從根本上說,還是不要這樣做。這樣會成倍增加你的成本,讓調試變得更複雜,而且抵消了隔離function所帶來的價值。

\\

function應該将資料推送到資料存儲或隊列中,然後通過觸發另一個function來完成其他的工作。

\\

盡可能少在function中使用額外的庫

\\

這點對于我來說是顯而易見的。

\\

function有冷啟動(function第一次啟動)和暖啟動(function已經啟動,并準備好被執行)兩個階段。冷啟動受到很多因素的影響,比如zip檔案的大小(或者被上傳的代碼)和需要執行個體化的庫的數量。

\\

代碼越多,冷啟動的速度就越慢。

\\

需要執行個體化的庫越多,冷啟動的速度也就越慢。

\\

例如,Java在某些平台上算是一門實作暖啟動的高性能語言。但如果你使用太多的庫,你會發現它需要很多秒才能完成冷啟動。有些庫不是必需的,況且冷啟動性能不僅會影響啟動,還會影響伸縮。

\\

我堅信開發人員應該隻在必要的情況下才使用額外的庫。

\\

像express這樣的東西是為伺服器而生的,無伺服器應用程式不需要用到它的所有元素。既然這樣,為什麼還要引入它的所有代碼和依賴項呢?為什麼要引入多餘的代碼?多餘的代碼不僅不會被運作,還會帶來安全風險。

\\

當然,如果一個庫已經經過你的測試,而且你了解和信任它,那麼就可以引入它。

\\

避免使用基于連接配接的服務

\\

除非真的有必要,否則不要使用基于連接配接的服務。

\\

這個會讓我陷入大麻煩。很多Web應用程式開發者都會陷入“我們隻知道RDBMS”的陷阱。

\\

但重點不在于RDBMS,而在于連接配接。

\\

無伺服器最适合與服務一起協作,而不是連接配接。

\\

服務旨在快速對請求做出響應,并處理資料層的複雜性。這在無伺服器領域具有巨大價值,也解釋了為什麼像DynamoDB這樣的資料庫非常适用于無伺服器架構。

\\

說實話,無伺服器從業者并不反對RDBMS,他們反對的是連接配接。連接配接需要時間,而且你試想一下,當一個function擴充到多個,每個function環境都需要一個連接配接,這樣就給function冷啟動引入了瓶頸和I/O等待,但其實這些是沒有必要的。

\\

如果你一定要使用RDBMS,可以在中間放置一個連接配接池服務,如果是某種可以自動伸縮的容器,那就更好了。

\\

關鍵是,你可能需要重新思考資料層,這不是無伺服器的錯。如果你嘗試重用目前的資料層,但不奏效,那可能是因為你對無伺服器架構缺乏了解。

\\

一個路由對應一個function

\\

盡可能避免使用單一的function代理。它無法進行伸縮,也無助于隔離問題。在某些情況下,你可以使用單一的代理,例如:一系列路由功能被綁定到一個表上,并且它與應用程式的其餘部分相對獨立。但在我工作過的大多數應用程式中,這種情況隻是個例。

\\

雖然避免使用單一代理會增加管理方面的複雜性,但在擴充應用程式時,它确實有助于隔離錯誤。

\\

話說回來,你會使用某種配置管理工具來運作這些東西,不是嗎?你已經在使用某種CI和CD工具,對嗎?是以,無伺服器仍然需要DevOps。

\\

學習使用消息和隊列

\\

如果應用程式是異步的,無伺服器往往會帶來最佳的效果。對于那些傾向于進行請求響應和大量查詢的Web應用程式來說,這可能不是很明顯。

\\

之前說過,最好不要讓function直接調用其他的function,是以如何将function連結在一起是一個很重要的問題。可以将隊列作為斷路器,如果一個function失效,隻需要清空因為故障而堆積起來的隊列,或者将失敗的消息推送到死信隊列(DLQ)。

\\

基本上就是要了解分布式系統的工作原理。

\\

對于帶有無伺服器後端的用戶端應用程式,最好的方法是使用CQRS。這個模式的關鍵之處在于将擷取資料的關注點和輸入資料的關注點分離開來。

\\

資料流,而不是資料湖

\\

在無伺服器系統中,資料将流經你的系統。它們最終可能會形成資料湖,但更可能的情況是,它們會處于某種流動的狀态。是以,任何時候都要将資料視為動态的,而不是靜止的。

\\

雖然這樣做并非總是可行的,但一定要盡量避免在無伺服器環境中查詢資料湖。

\\

無伺服器要求你重新思考資料層。對于剛進入無伺服器領域的新手來說,他們總是傾向于以RDBMS的方式考慮問題,他們極有可能會碰壁,不僅是因為伸縮問題,也因為他們的資料結構變得過于僵化。

\\

你會發現資料流會随着應用程式的變化而發生變化,而伸縮将會改變所有的一切。如果你所要做的隻是重定向一個資料流,那很容易,但要為資料庫築壩可是要難得多。

\\

了解應用程式是如何伸縮的

\\

建立第一個無伺服器應用程式很容易,然後你看着它擴充。如果你不了解自己所做的一切,那麼就很容易陷入與其他自動擴充方案相同的陷阱當中。

\\

如果你不了解應用程式是如何伸縮的,有可能會讓自己陷入麻煩之中。如果你使用緩慢的冷啟動(依賴了很多庫并使用了RDBMS),然後碰上突發的高峰流量,就會急劇增加function的并發量,讓連接配接數爆棚,進而拖慢了應用程式。

\\

是以,不要認為應用程式一定會在相同的負載下運作。了解應用程式處于不同負載之下的行為仍然是工作内容的一部分。

\\

結論

\\

我可以在這裡說更多的東西,不過以上這些是我在與其他人交談時最想告訴他們的。我沒有提到過如何規劃應用程式,或者如何考慮應用程式的成本,因為它們超出了本文的讨論範圍。我敢肯定,很多人會說我對RDBMS的看法是不對的。與容器一樣,我并不讨厭RDBMS,我隻是喜歡在工作中使用對的工具。是以,先了解你的工具!

\\

英文原文:https://medium.com/@PaulDJohnston/serverless-best-practices-b3c97d551535

\\

感謝張婵對本文的審校。