從0開始學微服務:02 從單體應用走向服務化

從0開始學微服務:02 從單體應用走向服務化

專欄上一期,我給你講述了什麼是微服務,以及微服務架構的由來。簡單回顧一下,微服務就是將龐雜臃腫的單體應用拆分成細粒度的服務,獨立部署,並交給各個中小團隊來負責開發、測試、上線和運維整個生命週期。

那麼到底什麼時候應該拆分單體應用?拆分單體應用有哪些標準可依呢?

為了解答這兩個問題,今天我將通過具體案例來闡述,希望你能夠學會單體應用拆分成微服務的正確姿勢。

什麼時候進行服務化拆分?

從我所經歷過的多個項目來看,項目第一階段的主要目標是快速開發和驗證想法,證明產品思路是否可行。這個階段功能設計一般不會太複雜,開發採取快速迭代的方式,架構也不適合過度設計。所以將所有功能打包部署在一起,集中地進行開發、測試和運維,對於項目起步階段,是最高效也是最節省成本的方式。當可行性驗證通過,功能進一步迭代,就可以加入越來越多的新特性。

比如做一個社交 App,初期為了快速上線,驗證可行性,可以只開發首頁信息流、評論等基本功能。產品上線後,經過一段時間的運營,用戶開始逐步增多,可行性驗證通過,下一階段就需要進一步增加更多的新特性來吸引更多的目標用戶,比如再給這個社交 App 添加個人主頁顯示、消息通知等功能。

一般情況下,這個時候就需要大規模地擴張開發人員,以支撐多個功能的開發。如果這個時候繼續採用單體應用架構,多個功能模塊混雜在一起開發、測試和部署的話,就會導致不同功能之間相互影響,一次打包部署需要所有的功能都測試 OK 才能上線。

不僅如此,多個功能模塊混部在一起,對線上服務的穩定性也是個巨大的挑戰。比如 A 開發的一個功能由於代碼編寫考慮不夠全面,上線後產生了內存洩漏,運行一段時間後進程異常退出,那麼部署在這個服務池中的所有功能都不可訪問。一個經典的案例就是,曾經有一個視頻 App,因為短時間內某個付費視頻訪問量巨大,超過了服務器的承載能力,造成了這個視頻無法訪問。不幸的是,這個網站付費視頻和免費視頻的服務部署在一起,也波及了免費視頻,幾乎全站崩潰。

根據我的實際項目經驗,一旦單體應用同時進行開發的人員超過 10 人,就會遇到上面的問題,這個時候就該考慮進行服務化拆分了。

服務化拆分的兩種姿勢

那麼服務化拆分具體該如何實施呢?一個最有效的手段就是將不同的功能模塊服務化,獨立部署和運維。以前面提到的社交 App 為例,你可以認為首頁信息流是一個服務,評論是一個服務,消息通知是一個服務,個人主頁也是一個服務。

這種服務化拆分方式是縱向拆分,是從業務維度進行拆分。標準是按照業務的關聯程度來決定,關聯比較密切的業務適合拆分為一個微服務,而功能相對比較獨立的業務適合單獨拆分為一個微服務。

還有一種服務化拆分方式是橫向拆分,是從公共且獨立功能維度拆分。標準是按照是否有公共的被多個其他服務調用,且依賴的資源獨立不與其他業務耦合。

繼續以前面提到的社交 App 舉例,無論是首頁信息流、評論、消息箱還是個人主頁,都需要顯示用戶的暱稱。假如用戶的暱稱功能有產品需求的變更,你需要上線幾乎所有的服務,這個成本就有點高了。顯而易見,如果我把用戶的暱稱功能單獨部署成一個獨立的服務,那麼有什麼變更我只需要上線這個服務即可,其他服務不受影響,開發和上線成本就大大降低了。

服務化拆分的前置條件

一般情況下,業務系統引入新技術就必然會帶來架構的複雜度提升,在具體決策前,你先要認識到新架構會帶來哪些新的問題,這些問題你和你的團隊是否能夠解決?如何解決?是自己投入人力建設,還是採用業界開源方案?

下面幾個問題,是從單體應用遷移到微服務架構時必將面臨也必須解決的。

服務如何定義。對於單體應用來說,不同功能模塊之前相互交互時,通常是以類庫的方式來提供各個模塊的功能。對於微服務來說,每個服務都運行在各自的進程之中,應該以何種形式向外界傳達自己的信息呢?答案就是接口,無論採用哪種通訊協議,是 HTTP 還是 RPC,服務之間的調用都通過接口描述來約定,約定內容包括接口名、接口參數以及接口返回值。

服務如何發佈和訂閱。單體應用由於部署在同一個 WAR 包裡,接口之間的調用屬於進程內的調用。而拆分為微服務獨立部署後,服務提供者該如何對外暴露自己的地址,服務調用者該如何查詢所需要調用的服務的地址呢?這個時候你就需要一個類似登記處的地方,能夠記錄每個服務提供者的地址以供服務調用者查詢,在微服務架構裡,這個地方就是註冊中心。

服務如何監控。通常對於一個服務,我們最關心的是 QPS(調用量)、AvgTime(平均耗時)以及 P999(99.9% 的請求性能在多少毫秒以內)這些指標。這時候你就需要一種通用的監控方案,能夠覆蓋業務埋點、數據收集、數據處理,最後到數據展示的全鏈路功能。

服務如何治理。可以想象,拆分為微服務架構後,服務的數量變多了,依賴關係也變複雜了。比如一個服務的性能有問題時,依賴的服務都勢必會受到影響。可以設定一個調用性能閾值,如果一段時間內一直超過這個值,那麼依賴服務的調用可以直接返回,這就是熔斷,也是服務治理最常用的手段之一。

故障如何定位。在單體應用拆分為微服務之後,一次用戶調用可能依賴多個服務,每個服務又部署在不同的節點上,如果用戶調用出現問題,你需要有一種解決方案能夠將一次用戶請求進行標記,並在多個依賴的服務系統中繼續傳遞,以便串聯所有路徑,從而進行故障定位。

針對上述問題,你必須有可行的解決方案之後,才能進一步進行服務化拆分。專欄後面的文章,我會給你逐一講解相應的解決方案。

總結

無論是縱向拆分還是橫向拆分,都是將單體應用龐雜的功能進行拆分,抽離成單獨的服務部署。

但並不是說功能拆分的越細越好,過度的拆分反而會讓服務數量膨脹變得難以管理,因此找到符合自己業務現狀和團隊人員技術水平的拆分粒度才是可取的。我建議的標準是按照每個開發人員負責不超過 3 個大的服務為標準,畢竟每個人的精力是有限的,所以在拆分微服務時,可以按照開發人員的總人數來決定。

思考題

想想你現在的業務場景,如果是單體應用的話,是否需要進行服務化拆分?如果需要的話,你覺得縱向拆分還是橫向拆分合適?具體可以拆分到什麼粒度?

歡迎你在留言區寫下自己的思考,與我一起討論。


分享到:


相關文章: