最終,我們放棄了微服務

微服務被認爲是一種理想的架構模式,因此,Steven Lemon所在公司的領導層決定從單體架構向微服務架構遷移,這讓整個開發團隊在隨後的的日子裏苦不堪言,七大現實問題擺在面前無法解決,微服務架構的好處也沒有享受到,並發現這不單單是一個技術問題。最終,整個團隊決定放棄。

領導決定:遷移微服務

最近,我所在的開發團隊在緊張的交付週期結束後,有了短暫的休息機會。領導層認爲可以利用這段時間將單體架構遷移至微服務。經過一個月的調研和準備之後,我們最終放棄遷移計劃,繼續使用原先的單體架構。在我們看來,微服務不僅不會幫到我們,反而會對開發流程造成嚴重影響。

微服務被認爲是一種理想的架構模式,但並不適合我們。我們公司的情況是這樣的:一共有200多名開發人員,不過我們團隊只有5個人,大概有5%的後端開發工作涉及公司層面的單體系統,這是一個巨大的C#應用程序。剩下的時間,我們開發了自己的兩個Node服務。

我們團隊負責的這兩個服務都很小巧,完全可以控制開發、架構和部署整個流程。遇到性能問題時,我們會把生產環境中的實例數量增加一倍,直到把底層問題解決。我們幾乎不與其他團隊合作,因爲這些服務是用TypeScript開發的,所以我們團隊(主要是前端開發人員)能夠在前端和後端使用相同的編程語言。最重要的是,我們可以在客戶端及後端的驗證和報告服務中包含複雜的規則計算引擎。總而言之,我們整個團隊專注於特定業務。

首先需要聲明:我們不喜歡開發單體系統,因爲增加新功能、編譯和運行測試都很慢,而且架構經常發生變化,在構建過程中總會出現難以預料的東西。所以,當領導提出遷移至微服務架構時,我們也同意了。

爲什麼選擇放棄?

然而, 在整個調研過程中,我們發現瞭如下七大難以解決的問題,這些問題讓我們最終選擇放棄。

嚴重依賴第三方

我們的整體應用程序是一個建立在外部產品之上的自定義UI層,集成了自定義業務規則,並提供了用於交互的界面。客戶端是一個UWP應用程序,還有一些後端服務,用於在我們和第三方域之間進行轉換。

因爲大量依賴第三方,我們在進行微服務劃分時遇到了一些問題,例如,爲了讓第三方的某個域起作用,應用程序必須在域之間做一些轉換工作,讓第三方域看起來像是我們的域的一部分。如果前端和第三方之間只有一個服務,那麼這種轉換還是可行的。當我們試圖將域劃分成多個獨立的微服務時,域之間的轉換工作帶來了很多麻煩。比如,微服務劃分是否要跟第三方保持一致,並在兩邊服務之間重複實現前端需求?或者根據自己的原則來劃分微服務,並通過一個微服務從第三方的多個域獲取數據?這兩種方法都違反了微服務原則,並且會導致額外的耦合。

此外,我們經常要與外部方協同工作,因爲一些特性要求雙方都做出改動。實際上,外部方成了我們之外的另一個開發團隊。如此緊密的合作意味着我們的發佈流程必須與他們保持同步。微服務的一個好處是每個團隊都可以獨立發佈自己的服務,不需要與其他團隊進行協調但跨團隊甚至是跨公司的協調發布流程導致我們無法享受到這些好處。

微服務的核心思想之一是打破“不同層由不同團隊負責開發”的模式。在微服務架構中,每個團隊需要處理與其業務相關的整個技術棧。對於我們來說,因爲外部方是一家完全獨立的公司,所以進行這種重構是不現實的。

無法有效拆分微服務

我們無法在單體系統中找到可以被明顯拆分成微服務的部分。於是,我們隨意挑了幾個領域模型,得到了一個需要創建的微服務清單,但在着手調研時,我們發現這些微服務之間存在很多共享的業務邏輯和隱式耦合。我們又進一步嘗試將這些微服務再細分爲更小的服務,但這樣卻帶來了更多耦合、無處不在的消息總線,以及潛在的通信大爆炸——一個服務需要與十個甚至更多的微服務通信。

這些微服務之所以耦合得很厲害而且難以拆分,主要是因爲我們原先的單體架構只爲一個業務提供服務。UI應用程序的主要設計目標是將第三方基礎應用程序的數據聚合在一起。爲了方便用戶,我們創建了跨領域的工作流,將分散的功能聚合在一起。

在整個過程,我們並沒有正確理解應該怎樣拆分微服務,而且低估了正確選擇微服務邊界的重要性。如果按照我們的方式來拆分,那麼實現一個標準的功能需要同時修改多個微服務。每個功能都需要不同的微服務團隊參與開發,這就導致單個微服務無法只由某個團隊負責。

不同團隊共享微服務

我們大約有12名開發人員在做這件事情,分佈在兩個功能團隊和一個支持團隊。但我們負責的工作是波動的,一個團隊不會只負責開發應用程序的某個部分,兩個團隊同時修改同一處代碼的情況並不少見,所以不能將某個微服務的所有權賦予某個團隊。

康威定律指出,軟件架構將以一種與組織和團隊結構類似的方式增長。如果有很多獨立的團隊,這些團隊可以負責不同的業務關注點,那麼可以考慮採用微服務架構。但是,如果只有很少的團隊,並且開發的是同樣的功能,那麼還是不要這麼做。

平臺還沒做好準備

因爲有各種各樣的問題,至少在6個月內,我們必須同時部署舊的單體應用和新開發的微服務,無法使用與微服務相關的工具,例如容器、Kubernetes、服務總線、API網關等。沒有這些工具,微服務之間的通信變得更加困難。

因此,我們在每個微服務中都包含了共享邏輯。因爲未能正確拆分,所以出現了很多重複工作。例如,有一個特別複雜但很重要的業務邏輯,我們不得不在四個微服務中複製、粘貼和維護。

前路渺茫

開發團隊只對接下來6個月做什麼有粗略想法,除此之外就沒有其他東西了。業務經常發生變化,需求突然發生變化的情況並不少見。這種不確定性使微服務的開發變得更加困難,因爲無法預測會出現什麼新狀況。例如,微服務之間的關係和耦合會一直增長嗎?幾個月後,我們需不需要花時間把它們重新連接在一起?

今年早些時候,我們已經試着進行微服務概念驗證,但隨着業務需求的變化,這被否決了。

時間太緊

時間安排得很緊,領導留的那點時間也就夠把單體拆分成計劃好的微服務,根本沒有多餘時間反思自己做了什麼或者在必要時調整方向。我們在計劃階段就發現了很多問題和挑戰,在實現階段就更不用說了,開發團隊因此陷入一片焦灼。

缺乏經驗

除了面臨風險和時間壓力外,負責設計和實現微服務的人之前沒有相關經驗。由於沒有足夠的標準工具可用,導致情況更加惡化,我們不得不自己實現基礎設施平臺。在與一些有微服務經驗但沒有參與我們項目的人交流之後,引發了更大的恐慌。他們建議的基礎設施我們沒有,他們還指出了我們在領域模型之間劃分界限可能帶來的後果。

到目前爲止,我們的計劃中包含了很多不得已的妥協,多少都偏離了標準的微服務模式。時間緊迫,沒有專家指導,犯錯成了家常便飯,我們以極高的代價換來血的教訓。

反思:微服務解決痛點了嗎?

當這些事情變得越來越困難,清晰的前行之路開始變得模糊。我們才意識到當初都不知道爲什麼要做這些事情,我們沒有列出痛點是什麼,也不知道做這些事情是否可以解決問題。更糟糕的是,微服務可能會帶來新的問題。

我們開始分析這些問題:應該從重構中得到什麼好處?要解決什麼問題?我們試圖通過無休止的會議搞清楚這些問題。在每一次休息時間,開發人員之間的每一次對話都在討論和質疑微服務,但仍然無法得到答案。

事實證明,相比於微服務,我們確實有其他更緊迫的痛點需要解決,只是這些痛點在我們考慮遷移到微服務的過程中被忽視了,但我們沒有足夠的時間來解決這些痛點,所以我們最後既沒有得到微服務的好處,也沒能解決其他痛點。

微服務的好處是什麼?

在意識到並不清楚採用微服務的目的之後,我們開始研究微服務能夠帶來哪些好處。

自治

在採用微服務架構時,開發團隊擁有交付特性所需的整個技術棧的控制權,好處是可以減少與其他團隊之間的協調工作,互不影響。

開發團隊可以專注某些領域

在採用單體架構時,開發任務的分配是不固定的,任何人都有可能分配到任意的任務。但如果每個團隊可以擁有自己的服務,就可以在特定業務領域積累專業知識,理解特定領域的業務規則和需求。他們對自己的技術棧十分了解,在做出變更時更有信心。

伸縮性

在採用微服務時,開發者可以根據每個服務的性能需求進行伸縮。而在採用單體架構時,雖然也可通過添加更多服務器進行水平伸縮,但卻不能讓單體的每個組件進行獨立伸縮。此外,細粒度的微服務可以更容易根據需要進行垂直伸縮。例如,有時可能希望多處理一些負載,而在處理性能問題時又需要一些額外的機會。

更容易回滾

如果回滾某個功能,只需要修改單個微服務就可以直接回滾,不會影響其他團隊的工作。此外,微服務架構有助於降低因單個微服務故障導致整個系統宕機的風險。

更高的發佈頻率

如果是一個大型系統,每次版本發佈都很耗時,且伴隨着風險。迴歸測試需要覆蓋很多東西,從而限制發佈節奏。開發人員可能需要經過很多人准許,並在所有參與版本發佈的團隊之間進行協調。微服務縮小了變更範圍,減少了團隊之間的協調工作量。開發團隊可以根據自己的時間表發佈版本,而不是被一個整體的節奏所束縛。

使用最合適的技術

微服務的各個團隊可以爲要解決的問題選擇最合適的技術,可以使用最新的技術,而單體系統則很難升級,只能停留在過時的技術平臺上。

升級更簡單

給大型應用程序升級框架從來都不是件有趣的事情,而且通常都伴有風險。當需要在多個團隊間協調相互關聯的變更時,一切都變得更加困難。而在採用微服務架構時,可以只升級必要服務,每次只讓一個團隊升級一個服務。

縮小變更影響範圍

應用程序的不同部分以不同的速度發生變化,大部分組件可能幾個月甚至幾年都不需要改動,將很少發生變化的代碼與頻繁發生變化的代碼分開可以降低意外迴歸帶來的風險。

易於重構

較小的服務更容易理解。一個服務只由一個團隊負責開發,服務的設計風格就能夠保持一致。小巧的微服務更容易進行重構。相比之下,單體架構可能會出現不一致,因爲隨着時間的推移,不同的團隊會向單體系統中加入不一樣的設計想法。

這些好處跟我們有什麼關係?

採用微服務有很多潛在的好處,但我們能撈到這些好處嗎?

最終,單體架構中無法變更的部分和我們不得不做出的妥協導致無法獲得這些好處。開發團隊需要在不同的微服務之間協調,一些功能分散在多個共享的微服務中,這說明我們並沒有獲得微服務的隔離性好處:減少協調和專門化。

微服務之間的差異變成了缺點,而不是優點。開發每一個新功能都需要了解新的微服務以及需要其他團隊做出哪些改動。我們對第三方的依賴嚴重阻礙了開發進程,讓我們無法獲得微服務伸縮性的優勢。

權衡利弊

大材小用

採用微服務架構並不是沒有代價,需要解決很多問題,而大部分在單體系統中已經解決過了,例如:日誌、監控、異常處理、容錯、回退服務間通信、消息格式、容器化、服務發現、備份、遙測、警報、跟蹤、構建管道、發佈管道、工具、共享基礎設施代碼、文檔、伸縮、時區支持、API版本控制、網絡延遲、健康檢查、負載均衡、CDC測試、容錯、在本地開發環境調試和開發多個微服務等。

更糟糕的是,因爲沒有現成的微服務平臺,我們不得不自己完成上面這些事情。要轉向微服務,我們確實存在痛點和困難,也確信無法從微服務架構獲得任何好處,如果要支持微服務,還需要做一長串額外工作。

名義上的微服務

下圖分別是我們當前的單體架構、計劃中的架構和微服務架構。從結構上看,新的架構跟當前的單體架構很像,所有東西仍然緊密耦合在一起。

單體架構很糟糕嗎?

自從微服務架構大火之後,“單體”成了一個不太好的名詞,好像“單體”就是糟糕的東西,而“微服務”就是好東西。但回望過去,我們的開發團隊在開發單體系統時並沒有遇到什麼問題。開發和擴展都非常簡單,已經有一個非常好的CI/CD管道,部署和回滾都非常容易。我們的分支管理和測試策略確保了很少會有問題進入到生產環境。

微服務更多與技術無關

我們對微服務研究得越多,就越覺得它與技術無關,更多的是與團隊的結構和工作模式有關。我們把微服務視爲純粹的技術問題,或許是我們錯了?

除此之外,還有很多全局性的問題無法得到解答。

  • 讓不同的團隊負責處理不同的業務是否切合實際?
  • 我們能否在領域和微服務之間對功能進行清晰劃分?
  • 是否所有團隊都有足夠的工作量,會不會出現某些團隊很清閒的情況?
  • 個別團隊會不會被堆積如山的高優先級工作壓得喘不過氣?
  • 阻礙我們拆分單體系統的問題是否也會讓領導層難以分配工作?
  • 領導層對這種轉變感興趣嗎?

微服務遷移是件大事情,在幾個月的時間裏,所有開發人員都停止開發新功能,並在很多先決條件都還不滿足的情況下開始拆解單體系統。爲了做這件事而做,我們並沒有想過是否真的有必要。

這不僅不是從A到B的問題,反而是一種倒退。我們先是創建微服務,然後搭建基礎設施,還忽略了重組團隊結構。如果我們先根據業務關注點重組團隊,然後準備好基礎設施,這就爲微服務的自然出現做好了準備。一旦出現任何新的業務問題,就可以將它們直接放到新的服務中。

在拆分微服務時,我們必須預先確定每個微服務的大小。關於微服務大小這個問題,有很多相互矛盾的建議。有人建議微服務應該足夠大,大到可以由一個團隊負責開發;另一些人則建議微服務應該足夠小,小到可以在腦子裏浮現出服務結構,甚至小到可以在兩週內重寫;還有一些人建議,應該與業務大小相仿。

領導層決定基於我們的領域模型來拆分微服務,如果還有問題,就繼續把它們拆分成更小的服務。這導致了上面提到的一些問題。事後看來,如果我們先把先決條件準備好,並讓微服務自然而然地出現,最終可能會得到切合實際的微服務大小。

取消計劃

隨着微服務發佈日子的臨近,我們的團隊發現了越來越多問題。我們做出了更多妥協,微服務帶給我們的好處也進一步消失殆盡。從開始實現微服務的第一個sprint開始,已經過去了四天,但我們仍然看不到什麼收穫,反而問題越來越多。我們召開了一次會議,不管領導層想要什麼,關於這條路是否要繼續走下去,答案都寫在每個開發人員的臉上。最終,我們取消了轉向微服務的計劃。

做什麼來代替微服務?

因爲之前把所有精力都放在瞭如何轉向微服務上,所以沒有花時間研究其他替代方案。但在放棄微服務之後,我們開始研究其他替代方案。最終,我們沒有將單體拆分成微服務,而是將它拆分成多個項目。這種拆分爲我們提供了一些額外的結構,我們可以更容易地看出哪裏存在耦合和重複,沒有額外的負擔,也不需要面對微服務架構中存在的問題。

此外,這種結構讓我們的領域模型變得更加清晰,能夠更容易地評估哪些部分可以被拆分成微服務。如果某些部分被證明是一個合適的微服務候選對象,這個部分就可以從單體中剝離出來,成爲一個微服務。

結論

領導層決定轉向微服務,但沒有考慮到現狀和需要面對的挑戰。經過評估,我們發現微服務並不適合,我們需要做出大量妥協。這些妥協導致無法獲得微服務的好處,所以轉向微服務對我們來說是一種損失。

在決定轉向微服務時,我們並沒有評估團隊結構等非技術方面的問題。經過幾個月的調研和努力,我們最終放棄了這個想法,並用剩下的時間對“單體”進行了一些小的重構。

英文原文:Why our team cancelled our move to microservices

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章