微服務時代組件化和服務化的抉擇
作者:vivo 互聯網服務器團隊 - Yao Wenyu
隨着業務系統的複雜性越來越高,系統之間的調用也越來越多,在微服務拆分和迭代過程中,是不斷的拆分出新的獨立的服務還是封裝獨立的組件以 jar 包依賴的方式提供服務是我們經常需要面對的問題,本文將詳細探討這兩種不同的方式區別、各自的優劣勢及適用的場景,希望能夠對大家有所啓發。
一、組件化 & 服務化定義
隨着公司互聯網業務發展越來越迅速,系統的複雜性越來越高,系統之間的調用也越來越多,在微服務拆分和迭代過程中,經常會遇到兩種場景問題:
-
自己系統內部的一些公共功能模塊到底以什麼形式提供服務,是封裝好所有邏輯和方法然後以 jar 包的形式提供,還是獨立拆分出一個服務然後通過接口的方式來提供;
-
涉及對外部系統服務的調用,系統內部可能有很多的服務都需要調用外部服務,但是調用邏輯都是一樣的,那麼針對外部系統的接口調用邏輯和方法是封裝成一個 jar 包給內部各個服務依賴調用,還是把對外部系統的接口調用邏輯和方法獨立拆分成一個服務,然後內部各服務通過調用這個獨立拆分出來的服務去調用外部系統服務。
針對以上兩種場景,我們可以總結概括爲組件化和服務化兩種不同的服務提供形式:
**組件化定義:**即把系統內部的一些公共功能模塊或者對外部系統調用的一些邏輯方法封裝成一個獨立 jar 包,有需要的系統直接依賴該 jar 包來使用相應的服務,在此我們稱之爲組件化;
系統內部公共功能模塊組件化示例,服務 A、B、C 都獨立依賴的組件 D 來使用相關功能。
圖 1 - 系統內部公共功能模塊組件化示例
外部系統服務接口調用組件化示例,服務 A、B、C 都通過組件 D 去調用外部服務 E
圖 2 - 外部系統服務調用組件化示例
**服務化定義:**即把系統內部的一些公共功能模塊或者對外部系統調用的一些邏輯方法獨立拆分爲一個服務,該服務再對外暴露統一的接口供所有有需要的服務去調用,在此我們稱之爲服務化。
系統內部公共功能模塊服務化示例,對應就是把示例圖 1 中組件 D 獨立拆分爲服務 D,服務 D 再提供接口給服務 A、B、C 去調用。
圖 3 - 系統內部公共功能模塊服務化示例
外部系統服務接口調用服務化示例,對應的就是把示例圖 2 中的組件 D 獨立拆分爲服務 D,服務 A、B、C 通過調用服務 D 去調用外部系統服務 E。
圖 4 - 外部服務調用服務化示例
那麼在實際工作中,面對不同的場景和問題,我們具體該選擇哪一種方式呢?是否相關的參考標準,有哪些問題是需要我們特別關注和考慮的,接下來我們會詳細介紹下組件化和服務化各自的優劣勢及適用的場景。
二、組件化的優劣勢及適用場景
組件化這種通過 jar 依賴的方式去調用第三方服務到底存在哪些優勢和劣勢呢?
2.1 組件化存在的優勢
-
服務調用性能高,因爲都是直接通過調用 jar 包裏的方法來調第三方服務,性能損耗較少,對性能要求較高的場景使用該方式會有一定優勢;
-
節省服務器機器成本,因爲不需要獨立部署服務,可以節省服務器資源,尤其在服務器請求量大 QPS 高需要部署大量服務器資源的場景下能夠節省的服務器資源也越多。
2.2 組件化存在的劣勢
-
可維護性較差,一旦調用其他服務的邏輯方法需要變動,或者第三方提供的 jar 包需要升級的話,除了該組件本身需要維護升級,我們自己系統內部依賴了該組件的服務都需要跟着一起升級,隨着時間的推移,梳理維護起來會很麻煩;
-
組件升級成本高且風險較大,系統內部依賴了該組件的服務如果很多的話升級成本會很高,這裏面的成本包括了開發維護升級各個服務的成本、測試驗證的成本及運維發佈的成本,需升級維護的服務越多,成本越高,對應的風險也越大。
2.3 組件化適用的場景
那麼具體哪些場景適合使用組件化的方式來部署呢?根據我們的經驗來看,符合以下場景特點的建議使用組件化的方式:
-
自己系統內部一些公共功能處理場景,不涉及到數據庫資源層面的連接和調用,適合組件化的方式;
-
對外部系統服務調用場景,服務併發量大對服務性能的要求很高,主要是一些 to C 的服務,要求高性能低延時,需要儘量減少服務調用鏈路,這種情況比較適合把對外部系統調用邏輯和方法以組件化的方式來提供,如果業務本身對性能要求極高,在很多情況下會優先考慮性能問題而容忍組件化帶來的一些劣勢;
-
公司對於服務器資源成本控制要求較爲嚴格,儘量降低成本,這種情況對於初創公司或者項目較爲常見些,經常是要求是低成本快速試錯。
2.4 使用組件化的案例
案例一
應用商店月活用戶 2.4 億,日活 6000 萬 +,對商店服務器性能要求非常高,商店內部很多服務都涉及到了大量的外部系統服務調用,比如 CPD、遊戲、DMP 等等,在用戶體驗和性能優先的前提下,我們都是通過組件化的方式來集成對外部系統的調用,容忍一些在維護和升級上的不便。
圖 5 - 外部服務調用組件化案例
2.5 組件化使用的反面案例
案例二
再分享一個商店使用組件化方式的一個反面案例,商店內很多服務模塊都涉及到一些運營資源位的管理,很多服務都需要向客戶端下發一些運營位的資源素材,在最初沒有充分考慮各類場景問題,最明顯的就是這些資源素材的獲取都涉及到數據庫資源的連接和調用,在使用組件化後會導致我們開發維護成本高,迭代效率低。
圖 6 - 組件化使用反面案例
三、服務化的優劣勢及適用場景
3.1 服務化存在的優勢
-
服務化後可做到資源隔離,互不影響,對調用方隱藏內部細節,可獨立進行開發部署,提升開發效率;
-
相比組件化來說可維護性更好,服務化之後各個模塊服務之間是解耦的,不管是調用其他服務的邏輯方法需要變動,還是第三方提供的 jar 包需要升級,只需要該服務本身升級即可,只要接口協議不發生變化,調用了該服務的其他服務都不需要變動,維護起來非常的方便;
-
服務升級成本低且風險可控,不管依賴了該服務的系統有多少,我們只需要處理好這一個服務的升級,開發維護升級成本、測試驗證的成本及運維的成本相對組件化來說都極大的降低,風險也小,在現在各類 jar 包安全問題頻發需要及時升級修復的情景下,服務化的優勢顯得更爲明顯。
3.2 服務化存在的劣勢
-
服務性能相對組件化來說較差一些,服務化拆分的越多,服務之間的相互調用越複雜,調用鏈路也會變的更長,服務之間的網絡請求調用越多性能越差;
-
服務化後多服務多節點部署,會帶來一些天然的分佈式系統固有的問題,比如一致性、分佈式事務處理等,另外就是節點變多、服務鏈路變長帶來的服務整體穩定性下降問題等;
-
服務化後會增加更多的服務器資源成本,在服務調用鏈路上每獨立化部署一個服務,爲了確保服務性能,對應的就會增加原有服務相應的機器資源數量或者更多,服務拆分越細成本越高;
3.3 服務化適用的場景
那麼哪些場景適合使用服務化的方式來部署呢?符合以下場景特點的建議使用服務化的方式:
-
針對自己系統內部的一些公共功能模塊,如果涉及到了數據庫層面的資源調用,建議使用服務化的方式提供,避免所有依賴該公共功能模塊的服務都要配置維護對應的數據庫資源信息,後面維護起來會非常痛苦,比如數據庫變更、機房遷移等;
-
針對外部的系統服務調用,如果有很多內部系統都對外部服務有依賴,但是服務併發量較小對性能要求不高,服務調用鏈路變長影響也不大,對併發量和性能要求不高的業務通暢也不需要太多的服務器資源,這種情況下建議把對外部系統接口調用封裝成獨立的服務,當對外部系統調用邏輯發生變化或相關 jar 包升級場景下我們只需要升級這一個服務,不需要自己系統內部所有相關服務都升級。
3.4 服務化使用案例
案例一
系統內部公共功能模塊服務化的案例,應用商店各個模塊在返回信息給客戶端之前經常會有一些公共的過濾邏輯,而這些公共過濾邏輯的處理還涉及到跟 mysql 及 redis 進行交互,因此把這些公共過濾邏輯直接獨立拆分爲一個獨立的服務,目前該服務不僅對項目內提供服務,還會給公司內其他部門很多業務使用。
可能有同學會有疑問,針對用戶量大,對服務併發量和性能要求較高的服務,多拆分一個服務出來解決了數據資源隔離的問題,但是如何解決服務調用鏈路變長導致性能下降的問題,比如上文提到的那個運營資源組件化的反面案例(示例圖 6),針對這種我們可以通過在調用方增加緩存的方式來解決性能問題,因爲這個業務場景對數據的實時性要求並不高。
圖 7 - 系統內部公共模塊服務化案例
可能有同學會有疑問,針對用戶量大,對服務併發量和性能要求較高的服務,多拆分一個服務出來解決了數據資源隔離的問題,但是如何解決服務調用鏈路變長導致性能下降的問題,比如上文提到的那個運營資源組件化的反面案例(示例圖 6),針對這種我們可以通過在調用方增加緩存的方式來解決性能問題,因爲這個業務場景對數據的實時性要求並不高。
**案例二
**外部系統服務調用服務化案例,我們有一個開放平臺系統,該系統主要是服務於開發者,對系統的性能要求不高,其中有一個需求涉及到外部系統服務調用,且開放平臺系統內有多個工程都需要調用該外部系統服務,爲了便於後續的服務維護和升級,就把對外部系統服務的調用邏輯統一封裝到了一個專門用於外部系統調用的內部服務裏,然後通過該內部服務來調用外部系統。
圖 8 - 外部系統調用服務化案例
四、總結
總結下組件化和服務化各自優劣:
綜上所述,組件化跟服務化兩種方式沒有絕對的好壞,各有優劣,具體該使用哪一種方式跟我們的真實的問題場景有關係,大家可以參考以上的分析,結合自己的實際項目情況去選擇符合自己的方式,技術最終是要服務於業務,大多數情況下沒有最完美的解決方案,只有最適合的解決方案。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/pLoWbsPJnvXO5jRoyHCx9Q