華爲實施微服務架構的五大軍規

前言前端

隨着業務的發展,代碼量的膨脹和團隊成員的增長,傳統單體式架構的弊端愈來愈凸顯,嚴重製約了業務的快速創新和敏捷交付。爲了解決傳統單體架構面臨的挑戰,前後演進出了SOA服務化架構、RPC框架、分佈式服務框架,最後就是當今很是流行的微服務架構。java

微服務化架構並不是銀彈,它的實施自己就會面臨不少陷阱和挑戰,涉及到設計、開發、測試、部署、運行和運維等各個方面,一旦使用不當,則會致使整個微服務架構改造的效果大打折扣,甚至失敗。後端

本文從微服務的生命週期全過程,闡述微服務架構的改造如何實施,以及如何避開各類陷阱,提高實施效率。緩存

在實施微服務架構改造以前,咱們的產品線遇到一個很大挑戰,就是需求的交付週期愈來愈短,採用的傳統MVC單體架構愈來愈難知足特性快速交付和上線的需求。傳統的電信項目,團隊規模每每都很是大,甚至會跨地域。跨團隊、跨地域的分佈式協同開發,代碼的重用和共享是個難題。網絡

例如咱們的支付功能須要新增一個限額保護, 短短十幾行代碼的一個小需求,評估以後居然須要9個星期才能上線。緣由就是限額保護功能須要同時在9個不一樣的功能模塊中修改, 新增900多個測試用例用來作全量的迴歸測試,示例以下:架構

經過對已有的MVC單體架構進行分析,咱們發現主要存在以下幾個問題:框架

  • 研發成本高:代碼重複率高,需求變動困難,沒法知足新業務快速上線和敏捷交付。運維

  • 測試、部署成本高:業務運行在一個進程中,所以系統中任何程序的改變,都須要對整個系統從新測試並部署。異步

  • 可伸縮性差:水平擴展只能基於整個系統進行擴展,沒法針對某一個功能模塊按需擴展。分佈式

  • 可靠性差:某個應用BUG,例如死循環、OOM等,會致使整個進程宕機,影響其它合設的應用。

  • 代碼維護成本高:本地代碼在不斷的迭代和變動,最後造成了一個個垂直的功能孤島,只有原來的開發者才理解接口調用關係和功能需求,新加入人員或者團隊其它人員很難理解和維護這些代碼。

  • 依賴關係沒法有效管理:服務間依賴關係變得錯蹤複雜,甚至分不清哪一個應用要在哪一個應用以前啓動,架構師都不能完整的描述應用的架構關係。

以上問題的應對策略,就是服務化。

首先,須要對業務進行拆分。當業務量大了之後,特別是當不一樣的功能耦合在一塊兒的時候,任何一個地方的改動都是很是困難的,必須對業務進行拆分,拆分的策略有兩種:

  • 橫向拆分。按照不一樣的業務域進行拆分,例如訂單、商品、庫存、號卡資源等。造成獨立的業務領域微服務集羣。

  • 縱向拆分。把一個業務功能裏的不一樣模塊或者組件進行拆分。例如把公共組件拆分紅獨立的原子服務,下沉到底層,造成相對獨立的原子服務層。這樣一縱一橫,就能夠實現業務的服務化拆分。

其次,要作好微服務的分層:梳理和抽取核心應用、公共應用,做爲獨立的服務下沉到核心和公共能力層,逐漸造成穩定的服務中心,使前端應用能更快速的響應多變的市場需求。

完成服務的拆分和分層工做以後,就會涉及到分佈式的部署和調用。如何透明化、高效的發現服務,須要一個服務註冊中心,經過服務化和訂閱、發佈機制對應用調用關係解耦,支持服務的自動註冊和發現。

服務化架構的演進歷史

在實施微服務架構以前,咱們一塊兒回顧下服務化架構的演進歷史。

MVC

MVC架構大部分人都用過,它主要用來解決先後端、界面、控制邏輯和業務邏輯分層問題。比較流行的技術堆棧就是Spring Struts iBatis(Hibernate) Tomcat(JBoss)。

RPC

隨着業務特別是互聯網的發展,業務規模的擴大,模塊化逐步成爲一種趨勢,此時解決模塊之間遠程調用的RPC框架應運而生。RPC須要解決模塊之間跨進程通訊的問題,不一樣的團隊開發不一樣的模塊,經過一個RPC框架實現遠程調用,RPC框架幫業務把通訊細節給屏蔽掉,可是RPC框架也有自身的缺點。

RPC自己不負責服務化,例如:服務的自動發現無論、服務的應用和發佈無論、服務的運維和治理也無論。沒有透明化、服務化的能力,對整個應用層的侵入仍是比較深的。

SOA

SOA服務化架構,企業級資產重用和異構系統間的集成對接,SOA架構的現狀:在傳統企業IT領域,主要是解決異構系統之間的互通和粗粒度的標準化(WebService)。互聯網領域,提供一套高效支撐應用快速開發迭代的服務化架構。例如各個互聯網公司自研或者開源的分佈式服務框架。

微服務架構

首先看一下微服務架構的定義:微服務(MSA)是一種架構風格,旨在經過將功能分解到各個離散的服務中以實現對解決方案的解耦。它有以下幾個特徵:

  • 小,且只幹一件事情。

  • 獨立部署和生命週期管理。

  • 異構性

  • 輕量級通訊,RPC或者Restful。

1.微服務架構的拆分原則

微服務架構的實施過程當中,首先遇到的最大的難題,就是它的拆分原則。

微服務拆分原則:圍繞業務功能進行垂直和水平拆分。大小粒度是難點,也是團隊爭論的焦點。

很差的實踐

  • 以代碼量做爲衡量標準,例如500行之內。

  • 拆分的粒度越小越好,例如以單個資源的操做粒度爲劃分原則。

建議的原則

  • 功能完整性、職責單一性。

  • 粒度適中,團隊可接受。

  • 迭代演進,非一蹴而就。

  • API的版本兼容性優先考慮。

代碼量多少不能做爲衡量微服務劃分是否合理的原則,由於咱們知道一樣一個服務,功能自己的複雜性不一樣,代碼量也不一樣。還有一點須要重點強調,在項目剛開始的時候,不要指望微服務的劃分一蹴而就。

微服務架構的演進,應該是一個按部就班的過程。在一個公司、一個項目組,它也須要一個按部就班的演進過程。一開始劃很差,沒有關係。當演進到一個階段時,微服務的部署、測試和運維等成本都很是低的時候,這對於你的團隊來講就是一個好的微服務。

2.微服務架構的開發原則

微服務的開發還會面臨依賴滯後的問題。例如:A要作一個身份證號碼校驗,依賴服務提供者B。因爲B把身份證號碼校驗服務的開發優先級排的比較低,沒法知足A的交付時間點。A會面臨要麼等待,要麼本身實現一個身份證號碼校驗功能。

之前單體架構的時候,你們須要什麼,每每喜歡本身寫什麼,這實際上是沒有太嚴重的依賴問題。可是到了微服務時代,微服務是一個團隊或者一個小組提供的,這個時候必定沒有辦法在某一個時刻同時把全部的服務都提供出來,「需求實現滯後」是必然存在的。

一個好的實踐策略就是接口先行,語言中立,服務提供者和消費者解耦,並行開發,提高產能。不管有多少個服務,首先須要把接口識別和定義出來,而後雙方基於接口進行契約驅動開發,利用Mock服務提供者和消費者,互相解耦,並行開發,實現依賴解耦。

採用契約驅動開發,若是需求不穩定或者常常變化,就會面臨一個接口契約頻繁變動的問題。對於服務提供者,不能由於擔憂接口變動而遲遲不對外提供接口,對於消費者要擁抱變動,而不是抱怨和抵觸。要解決這個問題,一種比較好的實踐就是管理 技術左右開弓:

  • 容許接口變動,可是對變動的頻度要作嚴格管控。

  • 提供全在線的API文檔服務(例如Swagger UI),將離線的API文檔轉成全在線、互動式的API文檔服務。

  • API變動的主動通知機制,要讓全部消費該API的消費者可以及時感知到API的變動。

  • 契約驅動測試,用於對兼容性作迴歸測試。

3.微服務架構的測試原則

微服務開發完成以後須要對其進行測試。微服務的測試包括單元測試、接口測試、集成測試和行爲測試等,其中最重要的就是契約測試:

利用微服務框架提供的Mock機制,能夠分別生成模擬消費者的客戶端測試樁和提供者的服務端測試樁,雙方能夠基於Mock測試樁對微服務的接口契約進行測試,雙方都不須要等待對方功能代碼開發完成,實現了並行開發和測試,提升了微服務的構建效率。基於接口的契約測試還能快速的發現不兼容的接口變動,例如修改字段類型、刪除字段等。

4.微服務架構的部署原則

測試完成以後,須要對微服務進行自動化部署。微服務的部署原則:獨立部署和生命週期管理、基礎設施自動化。須要有一套相似於CI/CD的流水線來作基礎設施自動化,具體能夠參考Netflix開源的微服務持續交付流水線Spinnaker:

最後一塊兒看下微服務的運行容器:微部署能夠部署在Dorker容器、PaaS平臺(VM)或者物理機上。使用Docker部署微服務會帶來不少優先:

  • 一致的環境,線上線下環境一致。

  • 避免對特定雲基礎設施提供商的依賴。

  • 下降運維團隊負擔。

  • 高性能接近裸機性能。

  • 多租戶。

相比於傳統的物理機部署,微服務能夠由PaaS平臺實現微服務自動化部署和生命週期管理。除了部署和運維自動化,微服務雲化以後還能夠充分享受到更靈活的資源調度:

  • 雲的彈性和敏捷。

  • 雲的動態性和資源隔離。

5.微服務架構的治理原則

微服務部署上線以後,最重要的工做就是服務治理。微服務治理原則:線上治理、實時動態生效。

微服務經常使用的治理策略:

  • 流量控制:動態、靜態流控制。

  • 服務降級。

  • 超時控制。

  • 優先級調度。

  • 流量遷移。

  • 調用鏈跟蹤和分析。

  • 服務路由。

  • 服務上線審批、下線通知。

  • SLA策略控制。

微服務治理模型以下所示:

最上層是爲服務治理的UI界面,提供在線、配置化的治理界面供運維人員使用。SDK層是提供了微服務治理的各類接口,供服務治理Portal調用。最下面的就是被治理的微服務集羣,集羣各節點會監聽服務治理的操做去作實時刷新。

例如:修改了流控閾值以後,服務治理服務會把新的流控的閾值刷到服務註冊中心,服務提供者和消費者監聽到閾值變動以後,獲取新的閾值並刷新到內存中,實現實時生效。因爲目前服務治理策略數據量不是特別大,因此能夠將服務治理的數據放到服務註冊中心(例如etcd/ZooKeeper),沒有必要再單獨作一套。

微服務最佳實踐

介紹完微服務實施以後,下面咱們一塊兒學習下微服務的最佳實踐。

服務路由:本地短路策略。關鍵技術點:優先調用本JVM內部服務提供者,其次是相同主機或者VM的,最後是跨網絡調用。經過本地短路,能夠避免遠程調用的網絡開銷,下降服務調用時延、提高成功率。原理以下所示:

服務調用方式:同步調用、異步調用、並行調用。一次服務調用,一般就意味着會掛一個服務調用線程。採用異步調用,能夠避免線程阻塞,提高系統的吞吐量和可靠性。可是在實際項目中異步調用也有一些缺點,致使使用不是特別普遍:

  • 須要寫異步回調邏輯,與傳統的接口調用使用方式不一致,開發難度大一些。

  • 一些場景下須要緩存上下文信息,引入可靠性問題。

並行調用適用於多個服務調用沒有上下文依賴,邏輯上能夠並行處理,相似JDK的Fork/Join, 並行服務調用涉及到同步轉異步、異步轉同步、結果匯聚等,技術實現難度較大,目前不少服務框架並不支持。採用並行服務調用,能夠把傳統串行的服務調用優化成並行處理,可以極大的縮短服務調用時延。三種服務調用方式的原理圖以下:

微服務故障隔離:線程級、進程級、容器級、VM級、物理機級等。關鍵技術點:

  • 支持服務部署到不一樣線程/線程池中。

  • 核心服務和非核心服務隔離部署。

  • 爲了防止線程膨脹,支持共享和獨佔兩種線程池策略。

談到分佈式,就繞不開事務一致性問題:大部分業務能夠經過最終一致性來解決,極少部分須要採用強一致性。

具體的策略以下:

  • 最終一致性,能夠基於消息中間件實現。

  • 強一致性,使用TCC框架。服務框架自己不會直接提供「分佈式事務」,每每根據實際須要遷入分佈式事務框架來支持分佈式事務。

微服務的性能三要素:

  • I/O模型,這個一般會選用非堵塞的,Java裏面可能用java原生的。 

  • 線程調度模型。

  • 序列化方式。

公司內部服務化,對性能要求較高的場景,建議使用異步非阻塞I/O(Netty) 二進制序列化(Thrift壓縮二進制等) Reactor線程調度模型。

最後咱們一塊兒看下微服務的接口兼容性原則:技術保障、管理協同。

  • 制定並嚴格執行《微服務前向兼容性規範》,避免發生不兼容修改或者私自修改不通知周邊的狀況。

  • 接口兼容性技術保障:例如Thrift的IDL,支持新增、修改和刪除字段、字段定義位置無關性,碼流支持亂序等。

  • 持續交付流水線的每日構建和契約化驅動測試,可以快速識別和發現不兼容。

相關文章
相關標籤/搜索