微服務:我們需要從單體轉到微服務嗎?
微服務或許你沒有真正實踐過,但一定聽說過,雖然已經到了 2022 年,這個詞依然很熱,可以通過搜索 google 指數看得到。
起源
“微服務”一詞源于 2011 年 5 月在威尼斯附近的一次軟件架構師研討會上進行的架構風格的討論。2012 年 5 月 討論小組決定將這種架構風格命名為“微服務”。Fred George 同年在一次技術大會上進行自己的微服務實踐分享,并說微服務是一種細粒度的 SOA ,但最終將其發揚光大的是 Martin Fowler 2014 年寫的博文《 Microservices 》,原文鏈接如下:
https://martinfowler.com/articles/microservices.html。
自此以后,微服務就家喻戶曉了,Microservices 的 Google 指數也是在 2014 年后就一路飆升。
和微服務相對應的是單體架構,先來看看單體架構是怎樣的。
單體架構
大多數人做軟件開發應該都是從單體架構開始的,以 .NET 程序員來說,從最早的 WebForm、到后來的 MVC、再到現在的前后端分離,后端使用 .NET 的 WebAPI ,都是整個項目的代碼放到一個解決方案中,發布要么直接整個目錄進行替換,或者更新有變更的 dll 文件。
包括到現在,這種單體架構的模該還占著很大的比重,凡是存在,必有道理,單體架構有著他的可取之處:
- 開發方便,.NET 程序員只需只需使用宇宙最強 IDE VS 就可以。
- 調試方便,在開發階段,所有的項目都在一個解決方案下,項目之間是可以直接引用,斷點可以到達你想要的任何地方。
- 運行方便,編碼完成,只需一個 F5 搞定。
- 部署方便,無論是之前部署 IIS ,還是現在的容器部署,都只涉及到一個發布目錄。
不過,隨著產品的功能越來越復雜,代碼也會變得越來越復雜,團隊的人數也會越來越多,這時單體架構就會帶來一些問題:
- 因為代碼庫非常的臃腫,從編譯、構建、運行到測試這個時間會越來越長。
- 技術棧幾乎是受限的,比如一個 .NET 的工程,基本就是 C# 來開發了,不太可能混雜其他的語言。
- 不方便橫向擴展,只能整套程序進行擴,滿足所有模塊的需求,對資源的利用率非常差。
- 不夠敏捷,團隊成員越來越多多時,都在同一個代碼上進行修改、提交、合并,容易引發沖突和其他問題。
- 一個很小的改動點,容易引發全身問題,導致系統崩潰,因為影響點多,測試成本也會很高。
- 缺乏可靠性,我們就碰到過因為一個序列化的問題導致 CPU 占用很高,結果整個系統癱瘓了。
微服務架構
上面提到的單體架構存在的問題,采用微服務架構可以很好地解決。微服務的核心是為了解耦,構建成一個松耦合的分布式系統。
一個龐大的單體系統拆分成若干個小的服務,每個服務可以由一個小的團隊來維護,團隊會更加敏捷,構建發布的時間更短,代碼也容易維護。
不同的微服務團隊可以采用不同的技術棧,比如工作流引擎使用 .NET ,規則引擎可以使用 Java ,一些全新的模塊更容易采用新的技術,人員流動和補充上也更加靈活。
每個服務通常采用獨立的數據庫,代碼或者數據庫層面的問題不會導致整個系統的崩潰。
擴展方便,這個很重要,如果監控發現流程引擎的壓力很大,可以只針對這個服務進行橫向擴展,服務器資源可以得到更好的利用。
上面說的都是好處,但沒有任何一種技術是銀彈,微服務解決問題的同時,也會帶來更多的問題。
1、開發調試變得困難了,需要通過日志的方式或者借助一些遠程調試工具。
2、單體架構中,模塊之間的調用都是進程內,添加類庫的引用后,就是本地方法的調用,微服務各自獨立部署,就會涉及到進程間的通信。
3、線上問題往往需要多個服務團隊一起來協作解決,會存在互相甩鍋的問題。
4、在分布式系統中,事務、數據一致性、聯合查詢等相比較單體更加復雜。
5、持續集成、部署、運維的復雜度也顯著提升。
6、隨著服務越來越多,客戶端怎樣去找這些服務呢?
7、進程內的訪問不存在網絡的問題,拆分后的服務可能在同個機器的不同進程,更多的時候是不同機器的不同進程,網絡問題導致服務不穩定怎么辦?
為了解決這些問題,各種中間件和框架就應運而生,又會帶來更多的學習成本。
在 .NET 技術棧中,會用到下面這些中間件:
- 服務注冊與發現:Consul。
- 網關:Ocelot。
- 熔斷降級:Polly。
- 服務鏈路追蹤:SkyWalking 或 Twitter 的 Zipkin。
- 配置中心:Apllo。
- 鑒權中心:IdentityServer4。
在 Java 中也有 Spring Cloud 和 Spring Cloud Alibaba 這種全家桶套件可以使用。
要不要轉微服務呢?
從單體到微服務是一個權衡和取舍的問題,切記不要跟風。以我的經驗來看,可以分為兩類:
- 做企業級系統。
- 做互聯網系統。
做企業級應用大多都是項目交付型的,客戶關系維系的好,后面可以做二期、三期,當然也有一錘子買賣的。這其中一個關鍵點是要快,單從快速來看,采用單體架構,開發、調試、部署都是最快的。
從客戶角度來說,只要能滿足業務,是單體還是微服務其實不太關心。
做互聯網應用,也就是我們常說的 SaaS,也分為兩種情況:
1、將現有的私有化部署的系統(單體架構)改造成支持 SaaS 的模式。
這種我也不建議一上來就大刀闊斧地進行微服務改造,可以在代碼的結構上做一些調整,比如按照領域去拆分目錄,不同領域之間的調用可以再進行一層抽象,目的是為了未來向微服務架構轉化。
當團隊的技術棧變得豐富了,比如原先只有 .NET ,現在有些模塊采用的是 Java ,這時已然是朝著微服務架構發展了,只是粒度比較大而已,相應的一些中間件也需要引入,比如服務網關、服務發現、服務間通信等。
2、從零開始做一個 SaaS 系統。
互聯網系統和企業級系統有很大的差別,如果說企業級系統更多關注功能性需求,那么互聯網系統除了功能性需求,還需要關注非功能性需求,比如:橫向擴展、限流降級、日志追蹤、預警、灰度發布等。
即便因為時間關系,一開始是單體架構,我覺得也應該是微服務架構的單體,隨著持續迭代和發展,根據實際情況逐步進行拆分。
如果時間上比較充裕,可以一開始就按照微服務架構進行分離,但粒度不要太小。
總結
- 解決常說的的三高問題(高并發、高性能、高可用),一個核心的思路就是拆,分而治之,所以說微服務肯定是能解決掉我們的很多問題,也是發展方向。
- 實踐微服務需要根據當前的實際情況,如果單體運行的很好,也沒什么問題,也不要為了炫技進行微服務改造。
- 如果決定要實踐微服務,先做好單體架構的設計,讓代碼遵循面向對象的設計原則,否則即便形式上變成了微服務,也不能嘗到微服務的甜頭。