華爲內部如何實施微服務架構?基本就靠這5大原則

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

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

本文從微服務的生命週期全過程,闡述微服務架構的改造如何實施,以及如何避開各種陷阱,提升實施效率。 注:本文內容是華爲近幾年來的服務化經驗分享實錄,如果你看的不酸爽,可以直接調到文末報名我們的線下活動,9月華爲的同學會做一個線下的workshop,限額80人!

在實施微服務架構改造之前,我們的產品線遇到一個很大挑戰,就是需求的交付週期越來越短,採用的傳統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。

微服務架構的拆分原則

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

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

不好的實踐

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

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

建議的原則

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

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

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

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

代碼量多少不能作爲衡量微服務劃分是否合理的原則,因爲我們知道同樣一個服務,功能本身的複雜性不同,代碼量也不同。還有一點需要重點強調,在項目剛開始的時候,不要期望微服務的劃分一蹴而就。

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

微服務架構的開發原則

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

以前單體架構的時候,大家需要什麼,往往喜歡自己寫什麼,這其實是沒有太嚴重的依賴問題。但是到了微服務時代,微服務是一個團隊或者一個小組提供的,這個時候一定沒有辦法在某一個時刻同時把所有的服務都提供出來,“需求實現滯後”是必然存在的。

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

採用契約驅動開發,如果需求不穩定或者經常變化,就會面臨一個接口契約頻繁變更的問題。對於服務提供者,不能因爲擔心接口變更而遲遲不對外提供接口,對於消費者要擁抱變更,而不是抱怨和牴觸。要解決這個問題,一種比較好的實踐就是管理 + 技術雙管齊下:

  • 允許接口變更,但是對變更的頻度要做嚴格管控。

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

  • API變更的主動通知機制,要讓所有消費該API的消費者能夠及時感知到API的變更。

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

微服務架構的測試原則

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

微服務架構

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

微服務架構的部署原則

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

微服務架構

最後一起看下微服務的運行容器:微部署可以部署在Dorker容器、PaaS平臺(VM)或者物理機上。使用Docker部署微服務會帶來很多優先:

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

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

  • 降低運維團隊負擔。

  • 高性能接近裸機性能。

  • 多租戶。

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

  • 雲的彈性和敏捷。

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

微服務架構的治理原則

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

微服務常用的治理策略:

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

  • 服務降級。

  • 超時控制。

  • 優先級調度。

  • 流量遷移。

  • 調用鏈跟蹤和分析。

  • 服務路由。

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

  • SLA策略控制。

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

微服務架構

最上層是爲服務治理的UI界面,提供在線、配置化的治理界面供運維人員使用。SDK層是提供了微服務治理的各種接口,供服務治理Portal調用。最下面的就是被治理的微服務集羣,集羣各節點會監聽服務治理的操作去做實時刷新。例如:修改了流控閾值之後,服務治理服務會把新的流控的閾值刷到服務註冊中心,服務提供者和消費者監聽到閾值變更之後,獲取新的閾值並刷新到內存中,實現實時生效。由於目前服務治理策略數據量不是特別大,所以可以將服務治理的數據放到服務註冊中心(例如etcd/ZooKeeper),沒有必要再單獨做一套。

微服務最佳實踐

介紹完微服務實施之後,下面我們一起學習下微服務的最佳實踐。

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

微服務架構

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

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

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

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

微服務架構

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

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

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

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

微服務架構

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

微服務架構

具體的策略如下:

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

  • 強一致性,使用TCC框架。服務框架本身不會直接提供“分佈式事務”,往往根據實際需要遷入分佈式事務框架來支持分佈式事務。

微服務的性能三要素:

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

  • 線程調度模型。

  • 序列化方式。

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

微服務架構

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

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

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

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

作者介紹李林鋒,2007年畢業於東北大學,2008年加入華爲,從事電信軟件的架構設計和開發。8年Java NIO通信框架、網關平臺和中間件設計和開發經驗,精通Java NIO、Netty和Mina等NIO通信框架,《Netty權威指南》作者,目前從事雲平臺相關的架構設計和開發。、文章出處:聊聊架構(公衆號ID :archtime)轉載來自:運維派  華爲內部如何實施微服務架構?基本就靠這5大原則


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章