Microservice 微服務的理論模型和現實路徑


兩年前接觸到了微服務的概念,面對日益膨脹的系統感覺豁然開朗。之后的兩年逐步把系統按微服務的架構理念進行了重構,並將業務遷移到了新架構之上。感覺現在差不多是時候寫一篇關於微服務的總結文章了。

定義

在 Martin Fowler & James Lewis 的文章(參考[1])里給出了微服務架構的一個定義:

微服務架構即是采用一組小服務來構建應用的方法。
每個服務運行在獨立的進程中,不同服務通過一些輕量級交互機制來通信, 例如 RPC、HTTP 等。
服務圍繞業務能力來構建,並依賴自動部署機制來獨立部署。

這個定義相對還是模糊,但還是勾勒出了微服務的一些關鍵概念:小,獨立進程,自動化。

起源

從微服務的定義,我們感覺似曾相識。早在 1994 年 Mike Gancarz 曾提出了 9 條著名原則(參考[4]),其中前 4 條和微服務架構理念特別接近。微服務就像把 UNIX 哲學應用到了分布式系統(參考[3])。

  1. Small is beautiful.
  2. Make each program do one thing well.
  3. Build a prototype as soon as possible.
  4. Choose portability over efficiency.
  • 小即是美:小的服務代碼少,bug 也少,易測試,易維護,也更容易不斷迭代完善的精致進而美妙。
  • 一個程序只做好一件事:一個服務也只需要做好一件好,專注才能做好。
  • 盡可能早地創建原型:盡可能早的提供服務 API,建立服務契約,達成服務間溝通的一致性約定,至於實現和完善可以慢慢再做。
  • 可移植性比效率更重要:服務間的輕量級交互協議在效率和可移植性二者間,首要依然考慮兼容性和移植性。

可見微服務其實不是憑空產生的,它自有其歷史的淵源。而在微服務之前的十年,大家經常談論的是一個叫 SOA(面向服務)的架構模式,它和微服務又是什么關系?在 Sam Newman 的《Building Microservices》(參考[2])一書中,作者對 SOA 和 Micorservices 的區別給出了定義:

You should instead think of Microservices as a specific approach for SOA in the same way that XP or Scrum are specific approaches for Agile software development.

你可以把微服務想成是 SOA 的一種實踐方式,正如 XP 或 Scrum 是敏捷軟件開發的實踐方式。我對這個定義是認同的,面向服務架構(SOA)的概念已有十多年,它提出了一種架構設計思想, 但沒有給出標准的參考實現,而早期企業軟件業界自己摸索了一套實踐方式 —— 企業服務總線(ESB)。 但歷史證明 ESB 的實現方案甚至在傳統企業軟件行業也未取得成功,Martin Fowler 在文中說正是因為 ESB 當年搞砸了很多項目, 投入幾百萬美金,產出幾乎為零,因此 SOA 這個概念也蒙上了不詳的標簽,所以當微服務架構出現時, 其擁護者開始拒絕使用包裹着失敗陰影的 SOA 這個標簽,而直接稱其為微服務架構(Microservices Architecture Style), 讓人以為是一套全新的架構思想,但事實上它的本質依然是 SOA 的一種實踐方式。

特征

一個按微服務架構理念構建的系統應該具備什么樣的特征呢?Martin 在其文章(參考[1])中做了詳盡的闡述,我這里簡單歸納下。

組件服務化

傳統實現組件的方式是通過庫(library),庫是和應用一起運行在進程中,庫的局部變化意味着整個應用的重新部署。 通過服務來實現組件,意味着將應用拆散為一系列的服務運行在不同的進程中,那么單一服務的局部變化只需重新部署對應的服務進程。

按業務能力組織服務

按業務能力組織服務的意思是服務提供的能力和業務功能對應,比如:訂單服務和數據訪問服務,前者反應了真實的訂單相關業務,后者是一種技術抽象服務不反應真實的業務。所以按微服務架構理念來划分服務時,是不應該存在數據訪問服務這樣一個服務的。

Melvin Conway 在 1967 年觀察到一個現象並總結出了一條著名的康威定律(參考[5]):

Organizations which design systems are constrained to produce designs which are copies of the communication structures of these organizations.

設計系統的組織,最終產生的設計等價於組織的溝通結構。傳統開發方式中,我們將工程師按技能專長分層為前端層、中間層、數據層,前端對應的角色為 UI、頁面構建師等,中間層對應的角色為后端業務開發工程師,數據層對應着 DBA 等角色。

事實上傳統應用設計架構的分層結構正反應了不同角色的溝通結構。所以若要按微服務的方式來構建應用,也需要對應調整團隊的組織架構。每個服務背后的小團隊的組織是跨功能的,包含實現業務所需的全面的技能。

服務即產品

傳統的應用開發都是基於項目模式的,開發團隊根據一堆功能列表開發出一個軟件應用並交付給客戶后,該軟件應用就進入維護模式,由另一個維護團隊負責,開發團隊的職責結束。 而微服務架構建議避免采用這種項目模式,更傾向於讓開發團隊負責整個產品的全部生命周期。Amazon 對此提出了一個觀點:

You build it, you run it.

開發團隊對軟件在生產環境的運行負全部責任,讓服務的開發者與服務的使用者(客戶)形成每日的交流反饋,來自直接客戶的反饋有助於開發者提升服務的品質。

智能終端與啞管道

微服務架構拋棄了 ESB 過度復雜的業務規則編排、消息路由等。 服務作為智能終端,所有的業務智能邏輯在服務內部處理,而服務間的通信盡可能的輕量化,不添加任何額外的業務規則。所以這里的智能終端是指服務本身,而啞管道是通信機制,可以是同步的 RPC,也可以是異步的 MQ,它們只作為消息通道,在傳輸過程中不會附加額外的業務智能。

去中心化

去中心化包含兩層意思:

  1. 技術棧的去中心化。
  2. 數據去中心化。

每個服務面臨的業務場景不同,可以針對性的選擇合適的技術解決方案。但也需要避免過度多樣化,結合團隊實際情況來選擇取舍,要是每個服務都用不同的語言的技術棧來實現,想想維護成本真夠高的。

每個服務獨享自身的數據存儲設施(緩存,數據庫等),不像傳統應用共享一個緩存和數據庫,這樣有利於服務的獨立性,隔離相關干擾。

基礎設施自動化

無自動化不微服務,自動化包括測試和部署。單一進程的傳統應用被拆分為一系列的多進程服務后,意味着開發、調試、測試、監控和部署的復雜度都會相應增大,必須要有合適的自動化基礎設施來支持微服務架構模式,否則開發、運維成本將大大增加。

容錯設計

著名的 Design For Failure 思想,微服務架構采用粗粒度的進程間通信,引入了額外的復雜性和需要處理的新問題,如網絡延遲、消息格式、負載均衡和容錯,忽略其中任何一點都屬於對“分布式計算的誤解”。

兼容設計

一旦采用了微服務架構模式,那么在服務需要變更時我們要特別小心,服務提供者的變更可能引發服務消費者的兼容性破壞,時刻謹記保持服務契約(接口)的兼容性。一條普適的健壯性原則(伯斯塔爾法則,參考[6])給出了很好的建議:

Be conservative in what you send, be liberal in what you accept.

發送時要保守,接收時要開放。按照伯斯塔爾法則的思想來設計和實現服務時,發送的數據要更保守,意味着最小化的傳送必要的信息,接收時更開放意味着要最大限度的容忍冗余數據,保證兼容性。

實施

前提

微服務似乎是一個近年很熱門的架構選擇,但什么時候該選擇微服務架構,這是有一定前提的。

上面的圖來自 Martin Fowler 的文章(參考[7]),揭示了生產率和復雜度的一個關系。在復雜度較小時采用單體應用(Monolith)的生產率更高,復雜度到了一定規模時,單體應用的生產率開始急劇下降,這時對其進行微服務化的拆分才是合算的。

圖上標明了復雜度和生產率拐點的存在,但並沒有量化復雜度的拐點到底是多少?或者換種說法系統或代碼庫的規模達到具體多大才適合開始進行微服務化的拆分。在一篇有趣的文章《程序員職業生涯中的 Norris 常數》(參考[9])中提到大部分普通程序員成長生涯的瓶頸在 2 萬行代碼左右。

當代碼是在 2,000 行以下,你可以寫任何混亂骯臟的代碼並依靠你的記憶拯救你。深思熟慮的類和包分解會讓你的代碼規模達到 20,000 行。

兩萬行是作者經歷過並反復碰到的一個瓶頸點,於我也有同感。

初級程序員,學會了爬行,接着蹣跚學步,然后行走,然后慢跑,然后再跑步,最后沖刺,他認為,“以這樣加速度前進我可以趕上超音速噴氣式飛機的速度!“ 但他跑進了 2,000 行的極限,因為他的技能不會再按比例增加。他必須改變移動方式,比如開車去獲得更快的速度。然后,他就學會了開車,開始很慢,然后越來越快,但又進入到了 20,000 行的極限。駕駛汽車的技術不會讓你能夠開噴氣式飛機。

所以每一個瓶頸點的突破意味着需要新的技能和技巧,而結合我自己的經歷和經驗,微服務的合適拆分拐點可能就在兩萬行代碼規模附近,而每個微服務的規模大小最好能控制在一個普通程序員的舒適維護區范圍內。借用前面的比喻,一個受過職業訓練的普通程序員就像一個拿到駕照的司機,一般司機都能輕松駕馭 100 公里左右的時速,但很少有能輕松駕馭 200 公里或以上時速的司機,即使能夠風險也是很高的。而能開噴氣式飛機的飛行員級別的程序員恐怕在大部分的團隊里一個也沒有。

另外一個實施前提是基礎設施的自動化,把 1 個應用進程部署到 1 台主機,部署復雜度是 1 x 1 = 1,若應用規模需要部署 200 台主機,那么部署復雜度是 1 x 200 = 200。 把 1 個應用進程拆分成了 50 個微服務進程,則部署復雜度變成了 50 x 200 = 10000,缺乏自動化設施,光部署就會把人搞死。所以前面微服務的特征才有基礎設施自動化,這和規模也是有關的,這也是因為其運維復雜度的乘數級飆升, 從開發之后的構建、測試、部署都需要一個高度自動化的環境來支撐才能有效降低邊際成本。

維度

實施微服務架構,可以從下面一些維度來做全面考量。

建模

服務圍繞業務能力建模,下圖是我在《京東咚咚架構演進》(參考[10])一文中寫到的咚咚向微服務架構演進中對服務拆分后得到的一個服務矩陣圖。從服務名稱就可以很容易看出服務比較清晰的反應了業務能力。

協作

采用微服務架構模式后,開發和運行的協作模式都會發生變化,還是以我們實踐的經驗為例來講下。

按微服務的組織方式,不同人或小團隊負責一個或一組微服務,服務之間可能存在相互調用關系,所以在服務之間也完全采用了像面向外部開放的契約化開發模式。

每一個服務都提供了一份契約文檔,發布到公開的內部 wiki,方便服務干系人可自由獲取查看。契約文檔要求至少對服務的幾個基本方面作出說明,如下:

  • API,具體接口的 API 接入技術說明。
  • 能力,服務能力的描述。
  • 契約,提供這些能力所約定的一些限制條件說明。
  • 版本,支持的最新和歷史的版本說明。

使用契約文檔來減少多余且可能反復重復的口頭溝通,降低協作成本。

采用微服務后一個業務功能的調用會涉及多個服務間的協同工作,由於服務間都是跨進城的調用通信,一個業務功能的完成涉及的服務調用鏈條可能較長,這就涉及到服務間需遵循一些規則來確保協作的可靠性和可用性。我們采用的原則是:長鏈條的內部服務之間的調用異步化。若一個調用鏈條中的個別服務變慢或阻塞可能導致整個鏈條產生雪崩效應,采用異步化來規避調用阻塞等待導致的雪崩情形。

上圖展示了咚咚請求調用鏈的一個異步化過程,若終端的請求是需要同步等待響應結果的(比如 HTTP 請求),只在最外層的接入點持有請求連接,內部服務的傳遞過程依然是異步化的。

測試

測試從不同的維度可以划分(參考[2])如下四個象限,四個象限從不同維度視角對測試做了觀察和判斷,從中可以看出除了體驗和探索性測試需要人工介入,其他維度的測試都可以通過自動化來實現,以降低測試人工成本和重復性工作。

而從測試所處的層次,又可以得到下面這樣個一個測試金字塔:

而微服務的測試,服務開發和運營人員專注於做好服務實現層面的單元測試和服務契約層面的接口測試。而面向業務功能的端到端測試,更多是依賴自動化腳本完成。而為了維護好這些自動化測試腳本,也需要保持服務接口和契約的兼容性和穩定性,這些自動化測試腳本也屬於服務的消費方之一。

部署

借助於虛擬化或容器等隔離技術,每個服務感覺都是獨享資源,不必考慮額外的資源使用沖突。

監控

大量松耦合的微服務通過相互協作來完成業務功能的流程處理,在這樣一個復雜的生產環境中,出現異常或錯誤是很難迅速定位的。這就需要一套成體系的監控基礎設施,在我們的實踐中借助了公司統一的監控基礎設施,對監控進行了分層,頂層的監控站在用戶視角,底層的監控站在系統視角,形成更完善的反饋鏈路。

原則

在實施微服務架構的過程中,通過不斷的迭代、摸索和修正得到了一些良好的實踐模式,對這些良好的實踐模式進行抽象提煉總結就得到了架構原則。而對架構原則的把控是為了更好的服務於業務的戰略目標。原則的普及帶來整體效率的提升和邊際成本的下降,以便更有效的支持組織業務戰略目標的快速達成。下面這個圖結合了微服務架構實施過程中,演示了關於「交付實踐」-「架構原則」-「戰略目標」之間的一個升維演化和支撐關系。

角色

實施微服務后關於團隊人員角色會發生什么樣的變化?

按微服務拆分系統后,按照「服務即產品”」的思路,人員角色將發生變化。 普通工程師從僅僅開發功能轉變為開發、運營服務,工作性質的轉變將帶來思路和關注點的變化。 每個服務至少有一個工程師作為負責人,當然能力更強的人可能會負責更多的服務。 大量拆分的微服務帶來開發人員交集的減少,對於大規模的團隊並行開發好處明顯。 而服務負責制對個人能力要求更高,自驅動和自學習能力更強的人會得到更多的成長機會,個人成長路線的發展也打開了空間。

這時團隊的構成會變得類似 NBA 球隊的組成,工程師的角色類似球員,架構師或技術經理類似教練,而部門經理則是球隊經理。 球員只管打好球,教練負責球員訓練、培養、戰術安排和比賽全場把控,經理則掌握着人事權,控制着球員的薪水升遷,招聘到優秀的球員以及想辦法帶領球隊去更受歡迎的比賽上打球。

總結

從接觸微服務的概念到今天寫下本文正好兩年了。本文從微服務的定義出發,追溯它的起源,分析它的特征,然后到實施微服務的前提、維度和原則,最后是實施微服務過程中帶來的一些人員角色屬性的變化,比較全面的梳理總結微服務架構的各方面。

微服務是一個近年的新概念,但卻真不是一個原創性的新東西。它幫助大型應用打散和轉移了復雜性,使其可以被更高效的並行解決,但並沒有減少任何復雜性,甚至還引入了額外的分布式計算固有的復雜性。我們需有一個清晰的認識,才能更好的認識和實踐微服務架構。

參考

[1] Martin Fowler & James Lewis. Microservices. 2014.03
[2] Sam Newman. Building Microservices. 2014.12
[3] Peter Lawrey. Micro-services for performance. 2016.03
[4] Mike Gancarz. The UNIX Philosophy. 1994
[5] Melvin Conway. Conway's law. 1967
[6] Jon Postel. Robustness principle. 1980
[7] Martin Fowler. MicroservicePremium. 2015.05
[8] Martin Fowler. MicroservicePrerequisites. 2014.08
[9] 左手的靈魂. 程序員職業生涯中的 Norris 常數. 2014.06
[10] mindwind. 京東咚咚架構演進. 2015.12


寫點文字,畫點畫兒,「瞬息之間」一切都變了。覺得不錯,可長按或掃描二維碼關注。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM