微服務架構是一顆銀彈嗎?
如今微服務架構正逐漸演變成一種主流的架構風格,那么微服務架構是一顆銀彈嗎?我們提倡微服務架構的目的是什么?
1987 IBM大型機之父Fred Brooks在《沒有銀彈:軟件工程的本質性與附屬性工作》中提出軟件工程包括本質性工作和附屬性工作。本質性工作是創造出一種由抽象的軟件實體所組成的復雜概念結構;附屬性工作是用程序語言來表達抽象概念,并在空間和時間的限制下,翻譯成機器語言。《沒有銀彈》主張并斷言在未來的十年之內(從1986年文章發表后開始計算),不會有任何單一軟件工程上的突破,能夠讓程序開發的生產力得到一個數量級(10倍)的提升。
我們討論或推廣一項軟件實踐或技術的時候,實際上是在談如何提高生產力。本文試圖利用《沒有銀彈》對本質性工作四個原因的歸類,去認識微服務架構的生產力。《沒有銀彈》認為本質性工作大部分的活動是發生在人們的腦海里,具有四大難題:復雜性、隱匿性、配合性和易變性。
軟件工程的本質性難題
1、復雜性
軟件要解決的問題通常牽扯到多種元素和計算步驟,這是一種人為的、抽象的智能活動,多半是復雜的。隨著“軟件吞噬世界”不斷深入,軟件所對應的社會活動越來越多,也越來越復雜。
單體架構系統的困境
系統往往是承載的業務越成功,越容易失敗。因為系統會隨著業務的發展,增加越來越多的特性和功能,使得系統復雜到沒有一個人能全面理解,沒有一個人敢去修改原有的功能或代碼。
微服務的救贖
微服務提出以業務邊界作為模塊劃分原則,每個模塊獨立進程。一個業務由很多獨立的小業務組合而成,系統也是由獨立的小系統組合而成,這樣的好處是每個小系統都很容易被理解,一個大系統可以根據業務組合微服務,或者逐漸發展獨立的微服務。
微服務救贖的代價
但是微服務架構真的降低了系統的復雜性嗎? 其實并沒有, 而且是增加了系統的總體復雜性!
微服務之間的連接更加復雜,網絡通訊不可靠和性能損耗,協議匹配,接口對接和轉換,版本協作,微服務注冊和發現,編排和調度,分布式業務和數據一致性等等復雜性都是單體架構不需要考慮的。
微服務為了降低單個微服務的復雜性,導致整體系統的復雜性急劇增加。
如果單體架構根據業務進行模塊劃分,每個模塊之間根據宿主語言接口進行交互,就像OSGi那樣模塊化/插件架構完全可以做到模塊化開發。
那么為了降低系統復雜性,是不是放棄使用微服務? 答案既是肯定也是否定。
我們剛才發現微服務架構帶來的復雜性,大多是附屬性問題。對于本質性復雜性,微服務使用上下文界限實踐,可以更好的隔離依賴業務概念的復雜性,從而降低單個微服務的復雜性。
利弊權衡
既然有得有失,我們是否需要做個權衡?
《沒有銀彈》的主張只說對了一半,10年內對于本質性問題確實是不會有十倍生產力的提高。但歷史上來看,附屬性問題是有十倍生產力提高的。 而我們在軟件工程實踐中,往往本質性問題和附屬行問題混合在一起,我們需要不斷的加深認識,區分兩者,并相互改進。
微服務架構帶來的附屬性復雜性必須要有一個功能齊全的PaaS進行轉移。
微服務推廣初期(包括現在)所面臨的很多問題,其實是缺乏一個功能齊全的PaaS,比如AWS/Azue,Rancher/OpenShrift,用以解決附屬性問題。
所以我們不需要做太多的利弊權衡,因為PaaS日趨成熟,成本將降到幾乎可以忽略不計。微服務架構利用PaaS對附屬性問題的轉移,降低一點點本質性問題的復雜性,也是非常價值的。只是發揮這種價值,需要掌握DDD設計實踐,利用好上下文界限來降低單個微服務的本質性復雜性。
2、隱匿性
軟件在沒有應用到業務之前,各種信息和思考大多在每個人的腦海里,很難完全呈現和想象出來。客戶只是模糊的知道自己想要什么,但并不知道要怎樣的軟件;項目經理有把握軟件開發進度的能力,但不知道軟件每個階段后能長成什么樣;業務分析員能把業務分析清楚但不能確認轉變成最終軟件會成為什么樣;開發設計人員知道怎么做軟件,但又不能完全理解業務需求。
單體架構系統的困境
單體架構中的各個模塊隱藏在大系統的頁面下,在交付之前對外界是不可見的。 更麻煩是單體架構往往是按技術維度進行分層設計,導致沒有人能看清全貌,各自都想把事情做到最好,但組合起來卻不是客戶想要的東西。
微服務的救贖
微服務強調小、獨立業務價值,獨立進程獨立部署交付,使軟件盡快盡早得交付到最終用戶手中,來交付和驗證業務價值。
微服務架構并沒有改變軟件開發過程中的隱匿性,而是通過縮短從需求到交付這段軟件開發周期,減少隱匿時間,來降低軟件工程總體的隱匿性。
利弊權衡
聽起來快速交付很好,但會有什么問題嗎?
組織必須要具備自動部署持續交付能力。假如一個系統上線需要3個小時進行部署,如果我們要持續部署,每天都部署一次,那就需要每天拿出3小時做部署,我想這個成本是不能接受的。一個全自動化的持續部署平臺是必須的,而且還需要保證每次交付都是高質量的,就需要做到全流程內建質量。
這里就引出另外一個問題,由于要求快速交付,就需要打通或模糊軟件開發過程的需求、設計、實現、測試、驗收、運維、運營等環節,對照以往按照單體架構組織的軟件開發流程會發現打通這些過程是有生產力損耗的。比如可以專門做需求分析一個月,不用考慮開發實現,這樣更加專注在需求分析當然效率更高了,我們為什么要拉通需求、開發、測試,使得各個環節不專注,生產效率反而下降呢?
3、配合性
在大型軟件環境中,各子系統的接口必須協同一致。考慮到時間和環境的演變,要維持這樣的一致性通常十分困難。
單體架構系統的困境
一個系統在最初開發的時候往往是最舒服的,雖然沒有現成的可重用組件,但也沒有沉重的歷史包袱。假如系統從零開始做的話,頭三個月開發會比較慢,因為需要搭建和熟悉一些開發、測試、部署基礎設施,隨著基礎設施和公共組件的完善,接下來的半年到一年開發會加速,但是再往后開發速度又會逐漸降低。因為那些一開始提高開發效率的接口、共享表、依賴組件都變成了復雜網絡纏繞在一起,變成了所謂的牽一發而動全身,改一行代碼都不知道會影響到什么地方。重構也變得非常困難,因為需要相互配合的地方太多了,協同成本極速占據開發成本的比例。
微服務的救贖
既然一個系統在初步開發、規模不大的時候生產效率最高,要想使得生產效率維持在一個較高的水平,那就保持系統總是很小。這樣因為系統本身很小,微服務系統的配合性問題總是在一個可控的范圍內。比如微服務獨立數據庫表結構,那我們根據業務需要改表結構的時候就不需要去考慮會不會影響到其他業務,因為其他業務和這個表結構完全沒關系。
我們區別看待微服務對外和對內的配合。剛才討論的單體架構配合性問題都是對內的問題,但微服務架構因為把系統做小,從而把一些原本對內的配合問題變成對外的配合了,極大增加了對外配合性問題。
然而單純從接口協同一致上來說,微服務架構非常糟糕。 單體架構的接口之間配合是相同的編程語言,基本上在編譯時就能發現錯誤。而微服務的接口往往是遠程服務,在開發時沒法對齊。
利弊權衡
微服務控制了對內配合性問題,增加了對外配合性。版本依賴怎么管理、公共組件怎么共享、事務一致性如何協調都是讓人糾結的問題。所以微服務的劃分就變得非常重要,總體的指導思想是減少對外配合,把復雜的配合性問題留在微服務內部。
4、易變性
軟件所應用的環境常是由人群、法規、硬件設備、應用領域等各因素匯集而成,而這些因素皆會快速變化。
單體架構系統的困境
單體架構往往需要將所有的模塊都整合在一起才能發布,所有模塊必須要步調一致。但需求的變化卻是不同節奏的,單體架構系統只能強制的把對需求的變化響應放在一個時間點發布,進而使需求得不到及時響應。
單體架構也不能很好的響應性能變化的需求。比如某個模塊的流量突然增加,或者需要大內存,單體架構只能為極少的模塊增加整個系統的計算資源,又因為增加整個系統的計算資源成本很高、實施時間長,導致性能需求遲遲不能得到滿足。
微服務的救贖
微服務要求獨立進程,可以完全根據需求定制不同類型的計算資源,更精細化分類的利用內存、IO、CPU。因為小,可以更快水平擴展響應性能需求變化。
更關鍵是,微服務小,強調獨立業務價值。根據康威定律,系統架構和組織架構相互影響,微服務小組需要是獨立特性的全功能團隊,面向最終用戶需求直接對戰。小團隊直接面對客戶需求做決策,所有信息和想法在小范圍內快速交流,業務價值流動更容易可見,更快速的響應變化。
利弊權衡
微服務架構需要改變組織結構小團隊充分授權、業務交付模式。
對于傳統組織而言,這點是最難的,尤其是大公司往往采用層級組織結構,要求把權力下放到小團隊,這會觸動已有的權力結構不說,還會引起組織的不安全感。
微服務的交付模式也會挑戰客戶接受軟件更新的習慣,這也是成功的傳統企業面對傳統客戶需要面對的挑戰。
結論: 微服務的終極價值
微服務架構解放小團隊生產力,提高市場響應力。
微服務是顆子彈,需要PaaS作槍,瞄準的是快速變化的目標。