微服務架構談系列(1):切忌匆忙服務化

微服務大行其道之時,不少有識之士大聲疾呼 “致傳統企業朋友:不夠痛就別微服務,有坑”,“能不能拆分服務就不拆分”,但仍然無法阻擋對於微服務實施的熱情和嚮往。

一則,開源全家桶用了之後,找工作方便一點。

二則,“上面領導” 讓用的,我們 coding 發現寫代碼測試麻煩了,我們無能爲力。

本文僅僅探討一下你選擇什麼,獲得什麼,承受什麼。如果沒有做好評估,則 “得無所得”,可能陷入一地雞毛的泥潭。

爲什麼要做服務化?

筆者習慣把單體架構和服務化架構作爲對照,“微服務” 在微上面容易陷入爭議和費解。

一位朋友說他覺得公司很折騰。

“幾個開發,微服務數量有 30 個之多,數據訪問 DAO 層和應用邏輯層也是獨立的進程,寫代碼麻煩”!

克里斯 · 理查森在**《微服務架構設計模式》**一書中,對於單體架構和微服務做了一個對比,筆者用表格表達如下:

從表格可以看到,微服務架構並不是代表領先,而是取決於應用的複雜度,越複雜,單體架構鐵板一塊(同頻研發、同頻發佈)遭遇的挑戰越大,而微服務架構越有優勢。

from (秦金衛:微服務架構深度解析與最佳實踐)

結論:

1、服務化架構(微服務)更適合複雜領域的應用系統。

2、服務化架構(微服務)並不代表業務交付效率更高。

對於這 2 個結論的細節,後面酌情補充。

業務高速發展的早期形態 1: 臃腫單體架構

潘志偉老師曾經總結在傳統的軟件開發中遇到下面的 “痛”,標誌着應該從單體架構走向服務化架構:

1、代碼衝突加劇

多個人或者一個團隊一起維護一個模塊,共同開發。當提交代碼的時候發現大量衝突,每次提測或者發版的時候需要花大量的時間來解決衝突。隨着團隊規模的增大以及項目複雜程度增加,代碼衝突的現象越嚴重;

2、模塊耦合嚴重

模塊之間通過接口或者 DB 相互依賴,耦合越來越嚴重。而且不同的人,寫代碼的風格不一樣,代碼質量也不一樣,上線前需要協調多個團隊,任何小模塊的異常都會導致整個項目發佈失敗;

3、項目質量下降

由於所有的代碼都是在一個服務裏面,做一次改動,可能會牽一髮而動全身,代碼衝突以及耦合嚴重,導致測試覆蓋範圍不充分,經常會出現沒有更改的模塊在線上突然出現問題,查詢後發現是由於工程師不小心做了某種改動,但是測試用例並沒有覆蓋;

4、團隊效率下降

由於大量時間在處理代碼衝突,消耗了研發人員大量的時間;而測試人員爲了提高項目質量,不得不在每次發版之前做全方位的迴歸測試,本身一次小的迭代結果項目時間卻很長。

業務高速發展的早期形態 2: 煙囪型架構

以頭哥分享的傳統金融的架構演進爲例,煙囪型架構並不代表不能支持業務。甚至應對業務的效率不低。比如發展一塊新業務,就有一個團隊去支持,沒有人甩鍋,大家 all-in。

隨着業務規模發展到,人員的增長不能按照線性增長去滿足業務的時候,問題就凸顯出來。

一般存在幾個問題。

1、功能的複用問題,大家都在修改用戶服務,能不能一個全功能團隊維護,更快一點。當然,我們先假設這樣是美好的。

2、人員能力問題,涉及到中間件,大家想用什麼用什麼,各團隊的 TL 和架構師存在感都很強,但存在搞不定的情況, 如果出故障多了,老闆就火大了。

還有其它問題,老王總結爲下面幾個方面:

服務的大小並不重要

微服務這個術語的一個問題是會將你的關注點錯誤地聚焦在微上。它暗示服務應該非常小。實際上,大小不是一個重要的考慮因素。

更好的目標是將精心設計的服務定義爲能夠由小團隊開發的服務,並且交付時間最短,與其他團隊協作最少。理論上,團隊可能只負責單一服務,因此服務絕不是微小的。相反,如果服務需要大型團隊或需要很長時間進行測試,那麼拆分團隊或服務可能是有意義的。另外,如果你因爲其他服務的變更而不斷需要同步更新自己負責的服務,或者你所負責的服務正在觸發其他服務的同步更新,那麼這表明服務沒有實現松耦合。你構建的甚至可能是一個分佈式的單體。

微服務架構把應用程序通過一些小的、松耦合的服務組織在一起。結果,這樣的架構提升了開發階段的效率,特別是可維護性、可測試性和可部署性,這也就讓組織的軟件開發速度更快。微服務架構也同時提升了應用程序的可擴展性,儘管這不是微服務的主要目標。

進入服務化架構的誤區

業務早期進行服務化階段要慎重

筆者旗幟鮮明的反對早期就進行過度服務化的考慮。比如以一個代駕業務爲例。我的想法,服務端程序早期一個 war 就夠了;移動端涉及到安卓、ios 甚至小程序需要考慮多端問題。至於用戶服務、用戶選擇代駕、代際服務入駐等都可以慢慢來。說不定,一年,這條業務線又關了呢。

淘寶和支付寶往往是幾百人維護一個前臺和後臺系統,才進行服務化拆分。當然當時還沒進入移動時代,就需求上線特性的速度來講,也不是太慢。按周進行發佈。在一個單體架構中,進行較好的模塊化,按照團隊分而治之。研發態的團隊組織關係和發佈態的可以辯證看待。不是說那段經歷是完美,是說明可以容忍,甚至不是最關鍵的阻礙,在支持業務上。

建議在單體架構階段採取較好的架構決策,而不是匆忙進行服務拆分

同樣,在 Medium,他們在早期的單體應用程序中做出了一些很好的架構決策。

他們的單體應用程序由組件高度模塊化,即使它已經發展成爲一個非常複雜的應用程序,包括 Web 服務器,後端服務和離線事件處理器。這使得將一大塊業務邏輯剝離到單獨的服務相對容易,只要新服務提供與原始實現相同(高級)的接口即可。

整體應用程序在較低級別封裝了數據存儲詳細信息。每種數據類型(例如,數據庫表)具有兩層實現:數據層和服務層。

單體應用程序還可以幫助我們對微服務進行建模,並使我們能夠靈活地專注於系統中最重要的部分,而不是從頭開始爲所有微服務建模。

一些 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