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