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

来源:http://www.cnblogs.com/mindwind/archive/2016/04/24/5422053.html
-Advertisement-
Play Games

兩年前接觸到了微服務的概念,面對日益膨脹的系統感覺豁然開朗。之後的兩年逐步把系統按微服務的架構理念進行了重構,並將業務遷移到了新架構之上。感覺現在差不多是時候寫一篇關於微服務的總結文章了。 定義 在 Martin Fowler & James Lewis 的文章(參考[1])里給出了微服務架構的一個 ...


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

定義

在 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


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


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 微信支付介面文檔:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_1 首先你得知道這個jsapi是不能離開微信進行調用支付的,明白了這個道理我們好下手,頁面是在微信內顯示並通過jsapi調用微信支付組件進行支付。 可以看看我們上一 ...
  • 下載頁: http://www.rabbitmq.com/install-standalone-mac.html 1、下載頁面首部的文件(頁面下載可能比較慢,使用迅雷下載就好),之後解壓到一個合適的路徑(例如:/Users/enniu1/Desktop/zjg/)。 2、配置命令訪問路徑 cd ~ ...
  • 上一篇文末,提到非虛擬介面 NVI 的實現,即將虛函數聲明為保護型或私有型,藉由模板函數模式來實現 。 園友 @KillU 看的很仔細,提出了一個問題:虛函數是 private 類型,繼承可以麽? 答案是:完全可以 5 實現權和調用權 <Effective C++> 中給的解釋是: 重寫一個虛函數, ...
  • 圖片上傳 Index.php文件代碼: upload.php代碼: 圖片上傳步驟: 1:接收參數 2:判斷錯誤 3:判斷格式是否合法 4:判斷文件大小 5:判斷是是不是真正的圖片 6:判斷是否是http post提交 文件上傳 Index.php文件代碼: <!DOCTYPE html> <html ...
  • AWT事件處理基本概念 AWT事件處理過程中,主要涉及3類對象: ① Event(事件):用戶對組件的一個操作,稱之為一個事件,以類的形式出現,例如,鍵盤操作對應的事件類是KeyEvent。其實例在該事件發生時由系統自動產生。每一種事件都對應專門的監聽者。 ② Event Source(事件源):事 ...
  • 1. Spring MVC簡介 Spring MVC是java EE平臺請求驅動類型的輕量級Web框架,使用了MVC設計模式的思想,spring框架的主要優勢之一就是分層架構,分層架構允許選擇使用任何一個組件,同時也可以集成其它框架技術,例如:Struts2、Hibernate等 Spring框架具 ...
  • 獲取【下載地址】 QQ: 313596790 【免費支持更新】三大資料庫 mysql oracle sqlsever 更專業、更強悍、適合不同用戶群體【新錄針對本系統的視頻教程,手把手教開發一個模塊,快速掌握本系統】 A集成代碼生成器 [正反雙向(單表、主表、明細表、樹形表,開發利器)+快速構建表單 ...
  • 一.意圖 將一個複雜對象的構建與它的表示分離,使得同樣的構造過程可以創建不同的表示。 二.動機 一個複雜的對象的構造過程中,原料相同,可能會要求生產不同的產品,並且生產的產品種類還能夠方便的增加。Bulider模式期望將解析原材料的過程與利用原材料生產產品的過程分離開,以達到用戶不需要知道根據原材料 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...