微服務架構談系列(1):切忌匆忙服務化
微服務大行其道之時,不少有識之士大聲疾呼 “致傳統企業朋友:不夠痛就別微服務,有坑”,“能不能拆分服務就不拆分”,但仍然無法阻擋對於微服務實施的熱情和嚮往。
一則,開源全家桶用了之後,找工作方便一點。
二則,“上面領導” 讓用的,我們 coding 發現寫代碼測試麻煩了,我們無能爲力。
本文僅僅探討一下你選擇什麼,獲得什麼,承受什麼。如果沒有做好評估,則 “得無所得”,可能陷入一地雞毛的泥潭。
爲什麼要做服務化?
筆者習慣把單體架構和服務化架構作爲對照,“微服務” 在微上面容易陷入爭議和費解。
一位朋友說他覺得公司很折騰。
“幾個開發,微服務數量有 30 個之多,數據訪問 DAO 層和應用邏輯層也是獨立的進程,寫代碼麻煩”!
克里斯 · 理查森在**《微服務架構設計模式》**一書中,對於單體架構和微服務做了一個對比,筆者用表格表達如下:
從表格可以看到,微服務架構並不是代表領先,而是取決於應用的複雜度,越複雜,單體架構鐵板一塊(同頻研發、同頻發佈)遭遇的挑戰越大,而微服務架構越有優勢。
from (秦金衛:微服務架構深度解析與最佳實踐)
結論:
1、服務化架構(微服務)更適合複雜領域的應用系統。
2、服務化架構(微服務)並不代表業務交付效率更高。
對於這 2 個結論的細節,後面酌情補充。
業務高速發展的早期形態 1: 臃腫單體架構
潘志偉老師曾經總結在傳統的軟件開發中遇到下面的 “痛”,標誌着應該從單體架構走向服務化架構:
1、代碼衝突加劇
多個人或者一個團隊一起維護一個模塊,共同開發。當提交代碼的時候發現大量衝突,每次提測或者發版的時候需要花大量的時間來解決衝突。隨着團隊規模的增大以及項目複雜程度增加,代碼衝突的現象越嚴重;
2、模塊耦合嚴重
模塊之間通過接口或者 DB 相互依賴,耦合越來越嚴重。而且不同的人,寫代碼的風格不一樣,代碼質量也不一樣,上線前需要協調多個團隊,任何小模塊的異常都會導致整個項目發佈失敗;
3、項目質量下降
由於所有的代碼都是在一個服務裏面,做一次改動,可能會牽一髮而動全身,代碼衝突以及耦合嚴重,導致測試覆蓋範圍不充分,經常會出現沒有更改的模塊在線上突然出現問題,查詢後發現是由於工程師不小心做了某種改動,但是測試用例並沒有覆蓋;
4、團隊效率下降
由於大量時間在處理代碼衝突,消耗了研發人員大量的時間;而測試人員爲了提高項目質量,不得不在每次發版之前做全方位的迴歸測試,本身一次小的迭代結果項目時間卻很長。
業務高速發展的早期形態 2: 煙囪型架構
以頭哥分享的傳統金融的架構演進爲例,煙囪型架構並不代表不能支持業務。甚至應對業務的效率不低。比如發展一塊新業務,就有一個團隊去支持,沒有人甩鍋,大家 all-in。
隨着業務規模發展到,人員的增長不能按照線性增長去滿足業務的時候,問題就凸顯出來。
一般存在幾個問題。
1、功能的複用問題,大家都在修改用戶服務,能不能一個全功能團隊維護,更快一點。當然,我們先假設這樣是美好的。
2、人員能力問題,涉及到中間件,大家想用什麼用什麼,各團隊的 TL 和架構師存在感都很強,但存在搞不定的情況, 如果出故障多了,老闆就火大了。
還有其它問題,老王總結爲下面幾個方面:
服務的大小並不重要
微服務這個術語的一個問題是會將你的關注點錯誤地聚焦在微上。它暗示服務應該非常小。實際上,大小不是一個重要的考慮因素。
更好的目標是將精心設計的服務定義爲能夠由小團隊開發的服務,並且交付時間最短,與其他團隊協作最少。理論上,團隊可能只負責單一服務,因此服務絕不是微小的。相反,如果服務需要大型團隊或需要很長時間進行測試,那麼拆分團隊或服務可能是有意義的。另外,如果你因爲其他服務的變更而不斷需要同步更新自己負責的服務,或者你所負責的服務正在觸發其他服務的同步更新,那麼這表明服務沒有實現松耦合。你構建的甚至可能是一個分佈式的單體。
微服務架構把應用程序通過一些小的、松耦合的服務組織在一起。結果,這樣的架構提升了開發階段的效率,特別是可維護性、可測試性和可部署性,這也就讓組織的軟件開發速度更快。微服務架構也同時提升了應用程序的可擴展性,儘管這不是微服務的主要目標。
進入服務化架構的誤區
業務早期進行服務化階段要慎重
筆者旗幟鮮明的反對早期就進行過度服務化的考慮。比如以一個代駕業務爲例。我的想法,服務端程序早期一個 war 就夠了;移動端涉及到安卓、ios 甚至小程序需要考慮多端問題。至於用戶服務、用戶選擇代駕、代際服務入駐等都可以慢慢來。說不定,一年,這條業務線又關了呢。
淘寶和支付寶往往是幾百人維護一個前臺和後臺系統,才進行服務化拆分。當然當時還沒進入移動時代,就需求上線特性的速度來講,也不是太慢。按周進行發佈。在一個單體架構中,進行較好的模塊化,按照團隊分而治之。研發態的團隊組織關係和發佈態的可以辯證看待。不是說那段經歷是完美,是說明可以容忍,甚至不是最關鍵的阻礙,在支持業務上。
建議在單體架構階段採取較好的架構決策,而不是匆忙進行服務拆分
同樣,在 Medium,他們在早期的單體應用程序中做出了一些很好的架構決策。
他們的單體應用程序由組件高度模塊化,即使它已經發展成爲一個非常複雜的應用程序,包括 Web 服務器,後端服務和離線事件處理器。這使得將一大塊業務邏輯剝離到單獨的服務相對容易,只要新服務提供與原始實現相同(高級)的接口即可。
整體應用程序在較低級別封裝了數據存儲詳細信息。每種數據類型(例如,數據庫表)具有兩層實現:數據層和服務層。
-
數據層處理對一種特定類型數據的 CRUD 操作。
-
服務層處理一種特定類型數據的高級邏輯,併爲系統的其餘部分提供公共 API。服務不共享它們之間的數據存儲。
-
這有助於我們採用微服務架構,因爲一種類型數據的實現細節完全隱藏在代碼庫的其餘部分。創建新服務來處理某些類型的數據相對容易且安全。
單體應用程序還可以幫助我們對微服務進行建模,並使我們能夠靈活地專注於系統中最重要的部分,而不是從頭開始爲所有微服務建模。
一些 bad case 供參考
一:組織和服務劃分配套。
曾經有一個國外的 case,沒有做對應的改變,導致微服務沒有 owner。他們大約有 12 個開發人員分佈在兩個功能團隊和一個支持團隊。工作波動性很大,沒有專職負責團隊。所有團隊同時接觸同一批代碼很正常,不能將某個微服務指定給一個團隊。
考慮架構時候一定要記得 Conway's Law,其意思是軟件架構會模仿組織和團隊架構增長。微服務架構對於不同團隊負責不同業務邏輯是比較有效的,然而,共享代碼功能的工作模式最好採用單體式架構。
二:謹慎引入新的技術棧
某一個創業團隊,由於技術負責人的喜好,引入了 go 語言做微服務。後來又由於招聘困難,同時維護了 java 語言的一套服務,分別取名 V1.0,V2.0。目前升級 V3.0 暫時還沒有把 V1.0 下線。後續的維護成本是一個問題。
三:過猶不及的服務數量
Uber 支付體驗平臺的工程經理 Gergely Orosz 稱其所在的團隊正將許多微服務轉移到宏服務(macroservice,即大小適中的服務)。
他們聲稱在構建新平臺時,在新服務方面做的規劃要周到得多。這些服務不僅僅只做一件事:服務於一個業務職能部門。它們由一個團隊(5 至 10 位工程師)構建和維護。與那些早期的微服務相比,它們更具彈性,並且在開發和維護方面獲得多得多的投入。
我的意思是當大家在學 Uber 的時候,最好一開始就想好服務粒度。
總結:
可能進入服務化階段的幾個徵兆:
1、開發人員龐大,比如大於 100 人。衆多人維護一個系統變得不可行,代碼衝突和代碼分支衆多可能導致成本。
2、代碼邏輯複雜,缺少層次。改動代碼成本高,系統脆弱。如早期蘑菇街採用 php ,後轉向 java,同時實現了服務化。
3、業務多元化發展,共享業務服務逐步凸顯
我們說服務化,便於服務 / 能力共享,總要回答共享什麼嘛。多業務發展讓服務共享具備可能性。否則也就是沉澱一些會員服務。
4、擴展性瓶頸
比如數據庫鏈接,系統共用的底層資源隨着機器增加而大幅度增加。比如對於單體應用中的支付模塊,訂單模塊需要不同的 tps/qps 要求。
當我們應用微服務 / 服務化,我們大致從這些維度進行評估。只有想清楚了,才能評估實施後的收益和成本支出。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s?__biz=MzIxMzEzMjM5NQ==&mid=2651042743&idx=1&sn=bea3c17d6267151dea94ba18c1dd9afc&chksm=8c4c66b3bb3befa54a260f436b6f0ae6f4742b460614d7d6b6d3002e4e9ef0694d11efa29639&scene=178&cur_album_id=1343963749467717633#rd