兩年前接觸到了微服務的概念,面對日益膨脹的系統感受豁然開朗。以後的兩年逐步把系統按微服務的架構理念進行了重構,並將業務遷移到了新架構之上。感受如今差很少是時候寫一篇關於微服務的總結文章了。html
在 Martin Fowler & James Lewis 的文章(參考[1])裏給出了微服務架構的一個定義:前端
微服務架構便是採用一組小服務來構建應用的方法。
每一個服務運行在獨立的進程中,不一樣服務經過一些輕量級交互機制來通訊, 例如 RPC、HTTP 等。
服務圍繞業務能力來構建,並依賴自動部署機制來獨立部署。java
這個定義相對仍是模糊,但仍是勾勒出了微服務的一些關鍵概念:小,獨立進程,自動化。git
從微服務的定義,咱們感受似曾相識。早在 1994 年 Mike Gancarz 曾提出了 9 條著名原則(參考[4]),其中前 4 條和微服務架構理念特別接近。微服務就像把 UNIX 哲學應用到了分佈式系統(參考[3])。程序員
Small is beautiful.github
Make each program do one thing well.數據庫
Build a prototype as soon as possible.後端
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,它們只做爲消息通道,在傳輸過程當中不會附加額外的業務智能。
去中心化包含兩層意思:
技術棧的去中心化。
數據去中心化。
每一個服務面臨的業務場景不一樣,能夠針對性的選擇合適的技術解決方案。但也須要避免過分多樣化,結合團隊實際狀況來選擇取捨,要是每一個服務都用不一樣的語言的技術棧來實現,想一想維護成本真夠高的。
每一個服務獨享自身的數據存儲設施(緩存,數據庫等),不像傳統應用共享一個緩存和數據庫,這樣有利於服務的獨立性,隔離相關干擾。
無自動化不微服務,自動化包括測試和部署。單一進程的傳統應用被拆分爲一系列的多進程服務後,意味着開發、調試、測試、監控和部署的複雜度都會相應增大,必需要有合適的自動化基礎設施來支持微服務架構模式,不然開發、運維成本將大大增長。
著名的 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
寫點文字,畫點畫兒,「瞬息之間」一切都變了。以爲不錯,可長按或掃描二維碼關注。