微服務架構有毒,什麼時候不使用微服務?

在過去的四年中,使用微服務來構建應用程序彷佛成了一種標準。大多數我所合做過的團隊也對此表現出了不一樣程度的興趣。前端

微服務

微服務所承諾的彈性、高可用、低耦合、敏捷,以及可以解決單體架構帶來的問題,這些都是它流行的主要緣由。程序員

可是近段時間來,對於微服務的一些保留意見和注意事項彷佛引發了人們的注意。數據庫

在這篇文章中,我重點想討論的是微服務的應用,它的缺點是什麼,以及在什麼狀況下應該慎重考慮使用微服務架構。後端

什麼是微服務安全

在工業級別,關於微服務基本特徵的定義比較一致。服務器

這些特徵能夠總結以下:網絡

  • 微服務是一種應用於組件設計(服務如何分組)和部署架構(服務如何部署和通訊)的模式。
  • 微服務適用於建立具備「必定功能複雜性」的分佈式應用程序。
  • 各個服務必須小。
  • 各個服務按功能劃分,實現關注點分離。
  • 各個服務保持自治和相互解耦,能夠獨立進行部署、版本控制和伸縮。
  • 各個服務之間經過輕量級 API 和異步通道相結合的方式進行通訊。
  • 各個服務擁有獨立的狀態,而且只能經過服務自己來對其進行訪問。

一個典型的微服務實現模式以下圖:架構

典型的微服務實現模式

圖 1:典型的微服務實現模式框架

從上圖中咱們能夠看到:異步

  • 微服務中的每組服務有本身的前端(由一個 API 和一個可選的 UI 組件組成)、一個實現自身服務領域邏輯的域層以及獨立的數據存儲。
  • 前端複合。將全部前端組件(UI 組件或 API)組合成一致前端(複合 UI 或 API 網關)。
  • 一條事件總線,做爲異步通訊的骨幹。

主要問題是,對於那些適用採用微服務架構的用例,人們對微服務的見解趨於一致。

這就是爲何我想採起相反的方法,並試圖說明在哪些狀況下,微服務可能不是最佳選擇。

微服務的種種挑戰

程序員知道種種優點,卻對代價一無所知。

—— Rich Hickey (Clojure設計者)

實現微服務須要權衡利弊。因爲本文的重點不是抨擊微服務的缺陷,因此儘可能簡明扼要。

1. 微服務很難被正確設計

這裏有專門的一本書《Microservices AntiPatterns and Pitfalls》來記錄它的缺陷。它須要很是很是多的迭代來完成一個使人滿意的領域設計。

同時幾個基本的和結構化問題沒有直接的答案,每每須要調整和迭代,例如:如何水平切分關注點,如何共享數據以及以什麼方式進行數據複製,如何管理報告,是否應該在服務中包括 UI 組件等。

2. 微服務引入複雜性

微服務引入了必定程度上的複雜性,這些複雜性已經被詳細地記錄下來,其中最著名的是「微服務——不是免費午飯」。

成倍的增長了 API 的數量

圖 2:成倍的增長了 API 的數量

微服務帶來的挑戰包括:

  • 成倍的增長了 API 的數量。這使得變動代碼變得困難,並引入了版本控制的複雜性,增長了服務功能性分解的難度。
  • 引入了網絡延遲。在組合服務時須要在可伸縮性和響應時間增長之間作出權衡。
  • 鑑於 CAP 理論,處理橫跨多個服務的事務很是複雜。和擁有單一數據庫的單體架構不一樣,這些事務一般不是由基礎設施處理。
  • 調試分佈式系統是複雜的(參見「微服務—不是免費的午飯」)。異步系統、服務間鎖和競態條件中產生的錯誤很難進行定位和排除。

儘管這些複雜性經過技術手段均可以克服,可是這須要技術人員付出額外的精力,不能讓他們專一於實現那些更具價值的業務功能。

3. 微服務須要組織架構發生轉變

微服務須要組織轉向自治的、跨職能的團隊。根據康威定律,這是相當重要的一步。

這意味着前端和後端開發人員、數據平臺工程師、QA、產品經理和操做人員必須在一個團隊中互相合做。

微服務須要組織架構發生轉變

圖 3:微服務須要組織架構發生轉變

這樣的組織運做起來很是平滑。這是由於大多數依賴關係都存在於團隊內部,並且因爲優先級是相同的,所以都可以快速解決。

4. 微服務須要過程和實踐的改變

微服務須要過程和實踐的改變。從偶爾發佈幾個大版本,到常常發佈許多小版本。

從手動的資源供給,到基礎設施即代碼等自動化形式的資源供給。微服務架構的成功依賴於組織和流程改變的能力,而這每每是最難的。

圖 4:微服務須要過程和實踐的改變

5. 微服務須要深刻的技術棧

上面討論的這些技術挑戰意味着團隊的技術集須要更加全面的拓展。

團隊成員須要理解分佈式系統、DevOps、基礎架構即代碼(IaC)、不一樣類型的數據庫、前端組件化和複合化、單元測試、全自動發佈、迭代、小版本發佈計劃、測試工具、多版本管理等等。

何時不該該使用微服務

1. 應用程序規模過小

應用程序規模過小不足以證實微服務的合理性。固然,這個應用在將來可能會出現增加,直到整個領域添加到其中。

在這種狀況下,當接近 RoI 閾值時,使用微服務。一樣的道理也適用於那些小型團隊。

代碼行數與維護成本

圖 5:代碼行數與維護成本

2. 領域不明確

領域不明確或不肯定,使得領域模型不肯定。好比,當產品被描述爲「門戶」時、當你開始創業準備作一個應用時、當一個 CRM 系統要管理訂單甚至是有郵遞外送時,這種問題就會凸顯。

在這種狀況下,單體結構要靈活得多。在晚上,當你獨自將 CRM 領域轉換成邏輯解決方案的時候,你可能會驚訝於利用 IDE 來進行重構所帶來的便利性以及單元測試套件帶來的安全感。

3. 組織不能作出改變

組織不能改變以適應微服務。它仍然包含一個數據組、一個前端組、一個後端組等等。

康韋定律有利於將服務組成一個分層的微服務體系結構。你能夠將圖 1 與圖 6 進行比較。

傳統的組織形式來作微服務

圖 6:傳統的組織形式來作微服務

因爲不一樣的團隊有不一樣的優先級,致使跨團隊的依賴關係環環相扣,形成延遲和衝突。

4. 缺少理解

團隊缺少對微服務概念、DDD 或概念設計的經驗和理解。雖然這可能算不上關鍵,但你應該仔細閱讀相關文檔並向有經驗的人尋求建議。

一個體繫結構設計不良的的產物每每是一個高耦合的分佈式「單體架構」系統,以及隨之而來的一切問題:網絡的通訊性和延遲、複雜性、隱藏的依賴、部署時產生耦合等等。

咱們大多數人都喜歡學習新事物,但並不是全部人都喜歡,何況學習須要時間和精力。

有時候甚至要不斷地犯錯誤,包括大錯誤,而後纔可能學到一些東西。甚至在某些狀況下須要廢棄初始的版本,而後從頭開始。這些都是潛在的成本,必需要在作出決定以前考慮清楚。

管理層也須要儘早適應重構,在某些極端狀況下甚至要接受從頭開始一個項目。

常常失敗。早點失敗。快速失敗。擁抱失敗是走向成功的一種方式。不要懼怕失敗,要學會接受失敗。

——Gary Burnison, CEO of Korn Ferry

接受失敗不是一件容易的事情,由於沉沒成本每每會錯誤指導你的下一步決策。

5. 其餘

團隊不成熟,技術棧不適應微服務或者人員流動率高。由於系統的無序性(熵)會隨着時間的推移而不斷增大,代碼的維護性也會隨着時間的推移而降低。

並且因爲一個更復雜的系統更難維護,這可能會加重第 3.4 帶來的問題。

困惑和壓力每每會讓人們退回到他們所熟悉的圈子。他們會「抄近路」把東西弄出來,或者走捷徑來規避複雜性。

很快,這樣產生的軟件架構可能會被污染到技術組件、「核心」庫、服務與服務之間的引用、編排器甚至「CSV 導入服務」,而後這些服務開始進入彼此的數據庫。

接下來,有人會問「咱們應該如何編排部署以管理服務之間的依賴關係?」這無異因而軟件版本的地獄,這種系統也被稱爲分佈式「單體架構」。

組件依賴

圖 7:組件依賴

運行和調試的複雜性可能會下降開發的總體效率。跨服務的 Bug 調查和日誌分析是很是複雜的。

這會帶來一個問題,那就是這些工做只能交給那些團隊中技術經驗更加豐富的成員。

可是這些成員的關注點應該是如何保持系統長期穩定運行,而不是救火。簡而言之,在這種狀況下,微服務不但沒有帶來優點,反而會讓整個團隊爲消極結果買單。

應該如何抉擇?

全部軟件系統均可以分解爲兩個主要元素:策略和細節。策略元素包含全部業務規則和過程。策略是系統的真正價值所在。

而細節是令人類、其餘系統和程序員可以與策略進行通訊的必備基礎,可是這些細節都不會影響策略的行爲。細節包括 IO 設備、數據庫、Web 系統、服務器、框架、通訊協議等等。

架構師的目標是爲系統建立一個外形。這個外形將策略看作是系統中最重要的元素,同時作到細節與策略無關。這使得有關細節的決策能夠延遲和推後。

—— Robert C. Martin, Clean Architecture

若是您正在構建的應用程序有一個至關清晰的領域,將來會演進到一個至關的規模,在項目開始就會配置大型的團隊,而且你對團隊的技術有信心,你在分佈式設計方面有一些經驗或者至少有一些素養,同時又能得到管理層方面對於失敗和學習的支持和容忍,那麼微服務會是一個很好的選擇。

可是要注意有時佈局候微服務可能會拔苗助長。若是你所處的場景與前面的描述相相似,那麼使用一些更簡單的架構做爲開始可能更加明智。

好比一個單體架構或者一個分層架構(自己可能包含一些專門的服務)。大部分微服務架構可以解決的問題,其餘方案也能解決。

低耦合、可伸縮性和前瞻性的系統來自於精心設計的應用程序架構。這種架構每每具備明肯定義的邊界和專門的數據存儲。

微服務只能經過提供物理限制來知足這種場景。另外一種建立物理限制的方法是經過組件(DLL、JAR)。組件架構和部署架構的選擇應該儘量的慎重。

容器和基礎結構即代碼(IaS)能夠與微服務架構一塊兒配合使用。事實上,它們每每更容易實現,由於網絡是直接的,配置的數量不那麼重要。同時容器也能讓搭建和銷燬環境變得更加容易,並能夠加速開發環境的部署。

構建自動化和頻繁發佈能夠經過增長關注點和減小在製品(Reduced WIP)、小批量(Small Batches)、原子化更改流(Atomic Change Flow)和減小協做來實現。

對於複雜的分佈式系統,微服務無疑是一個很好的選擇。但微服務並非惟一的選擇,對於微服務的訴求每每會促令人們作出採用它們的決定,而忽略了它帶來的種種問題。

一我的應該考慮各類選擇,進而作出一個有意識的、有素養的、理性的選擇。

感興趣的能夠本身來個人Java架構羣,能夠獲取免費的學習資料,羣號:855801563對Java技術,架構技術感興趣的同窗,歡迎加羣,一塊兒學習,相互討論。

相關文章
相關標籤/搜索