微服務理論與實踐[1]-什麼是微服務

微服務理論與實踐[1]-什麼是微服務

什麼是微服務

image1.jpg
  • 微服務 (Microservices) 是一種軟件架構風格,將應用程序構造爲圍繞業務的小型自治服務的集合

  • 微服務以專注於單一責任與功能的小型功能區塊 (Small Building Blocks) 爲基礎。每個服務都是獨立的,並實現單個業務功能

  • 微服務利用模塊化的方式組合出複雜的大型應用程序,各功能區塊使用與語言無關的 API 集相互通信

  • 微服務運用了以業務功能爲主導的設計概念,應用程序在設計時就能先以業務功能或流程設計先行分割,將各個業務功能都獨立實現成一個能自主運行的個體服務,然後再利用相同的協議將所有應用程序需要的服務都組合起來,形成一個應用程序

微服務例子1

  • 以購物車應用程序爲例,當打開購物車應用程序時,您看到的只是一個網站。但是,在後臺,購物車應用程序具有用於接受付款服務,客戶服務等

  • 假設此應用程序的開發人員使用了單體框架,架構如下圖

2.png

  • 如圖,在單體架構中,所有功能都放在一個代碼庫中,並在一個基礎數據庫下

  • 現在,假設市場上出現了一個新品牌,並且開發人員希望將即將到來的品牌的所有詳細信息放入此應用程序中

  • 此時,不僅需要處理新品牌的服務,而且還必須重新構建整個系統並相應地進行部署。爲了避免此類挑戰,開發人員決定將其應用程序從單體架構轉換爲微服務

3.png
  • 開發人員爲搜索,推薦,客戶服務等創建了單獨的微服務

  • 此微服務架構不僅可以幫助開發人員克服以前的架構所面臨的所有挑戰,而且還可以輕鬆地構建,部署和擴展購物車應用程序

微服務例子2

  • 以旅遊行業應用程序爲例
    4.jpg

  • 整體服務包括了旅客關係管理、付款、消息通知等服務

  • 傳統的單體常常採用如上圖所示的整體式架構,並採取MVC的設計模式

  • 三層架構(MVC)的具體內容如下

  • 表示層(view): 用戶使用應用程序時,看到的、聽見的、輸入的或者交互的部分。

  • 業務邏輯層(controller): 根據用戶輸入的信息,進行邏輯計算或者業務處理的部分。

  • 數據訪問層(model): 關注有效地操作原始數據的部分,如將數據存儲到存儲介質(如數據庫、文件系統)及

  • 從存儲介質中讀取數據等。

  • 雖然現在程序被分成了三層,但只是邏輯上的分層,並不是物理上的分層。也就是說,對不同層的代碼而言,經過編譯、打包和部署後,所有的代碼最終還是運行在同一個進程中
    單體架構在規模比較小的情況下工作情況良好,但是隨着系統規模的擴大,它暴露出來的問題也越來越多,主要有以下幾點:

  • 複雜性逐漸變高

  • 比如有的項目有幾十萬行代碼,各個模塊之間區別比較模糊,邏輯比較混亂,代碼越多複雜性越高,越難解決遇到的問題

  • 技術債務逐漸上升

  • 公司的人員流動是再正常不過的事情,有的員工在離職之前,疏於代碼質量的自我管束,導致留下來很多坑,由於單體項目代碼量龐大的驚人,留下的坑很難被發覺,這就給新來的員工帶來很大的煩惱,人員流動越大所留下的坑越多,也就是所謂的技術債務越來越多

  • 維護成本大

  • 當應用程序的功能越來越多、團隊越來越大時,溝通成本、管理成本顯著增加。當出現 bug 時,可能引起 bug 的原因組合越來越多,導致分析、定位和修復的成本增加;並且在對全局功能缺乏深度理解的情況下,容易在修復bug 時引入新的 bug

  • 持續交付週期長

  • 構建和部署時間會隨着功能的增多而增加,任何細微的修改都會觸發部署流水線。新人培養週期長:新成員瞭解背景、熟悉業務和配置環境的時間越來越長

  • 技術選型成本高

  • 單塊架構傾向於採用統一的技術平臺或方案來解決所有問題,如果後續想引入新的技術或框架,成本和風險都很大

  • 可擴展性差

  • 隨着功能的增加,垂直擴展的成本將會越來越大;而對於水平擴展而言,因爲所有代碼都運行在同一個進程,沒辦法做到針對應用程序的部分功能做獨立的擴展

微服務架構

5.jpg
  • 將上面的整體架構改造爲如上圖所示的微服務

  • 來自不同設備的不同客戶端嘗試使用不同的服務,例如搜索,構建,配置和其他管理功能

  • 所有服務均根據其功能進行分離,並進一步分離爲單個微服務

  • 這些微服務具有自己的負載均衡和執行環境以執行其功能,並在其自己的數據庫中捕獲數據

  • 微服務之間通過無狀態服務器(REST、GRPC或消息總線)進行通信

  • 微服務藉助服務發現來了解其通信路徑並執行自動化,監控等操作功能

  • 微服務執行的所有功能通過API網關傳達給客戶端

微服務特點

  • 解耦

  • 系統中的服務在很大程度上是解耦的。因此,整個應用程序可以輕鬆構建,更改和擴展

  • 組件化

  • 微服務被視爲獨立的組件,可以輕鬆替換和升級

  • 專注業務功能

  • 業務功能–微服務非常簡單,專注於單一功能

  • 獨立自主

  • 開發人員和團隊可以彼此獨立地工作,從而提高了速度

  • 持續交付

  • 通過自動化的構建、測試和部署,允許頻繁發佈軟件

  • 分散治理

  • 重點是使用正確的工具完成正確的工作。這意味着沒有標準化模式或任何技術模式。開發人員可以自由選擇最有用的工具來解決他們的問題

  • 敏捷開發

  • 微服務支持敏捷開發。任何新功能都可以快速開發並丟棄

微服務的優點

  • 單一職責

  • 微服務架構中的每個服務,都是具有業務邏輯的,符合高內聚、低耦合原則以及單一職責原則的單元,不同的服務通過“管道”的方式靈活組合,從而構建出龐大的系統

  • 輕量級通信

  • 服務之間通過輕量級的通信機制實現互通互聯,而所謂的輕量級,通常指語言無關、平臺無關的交互方式

  • 對於輕量級通信的格式而言,我們熟悉的 XML 和 JSON,它們是語言無關、平臺無關的;對於通信的協議而言,通常基於 HTTP,能讓服務間的通信變得標準化、無狀態化。目前大家熟悉的 REST(Representational StateTransfer)、GRPC是實現服務間互相協作的輕量級通信機制之一。使用輕量級通信機制,可以讓團隊選擇更適合的語言、工具或者平臺來開發服務本身

  • 提高容錯性(fault isolation),一個服務的內存泄露並不會讓整個系統癱瘓

  • 獨立性

  • 服務獨立測試、部署、升級、發佈

  • 在單塊架構中所有功能都在同一個代碼庫,功能的開發不具有獨立性;當不同小組完成多個功能後,需要經過集成和迴歸測試,測試過程也不具有獨立性;當測試完成後,應用被構建成一個包,如果某個功能存在 bug,將導致整個部署失敗或者回滾

  • 新技術的應用,系統不會被長期限制在某個技術棧上

  • 可以根據市場需求,靈活多變的組合出新的業務場景

  • 降低代碼耦合度

  • 服務實例水平擴展,服務單一職責,功能獨立。保證可靠性與性能,提升資源利用

  • 由於微服務是以業務功能導向的實現,因此不會受到應用程序的干擾,微服務的管理員可以視運算資源的需要來配置微服務到不同的運算資源內,或是布建新的運算資源並將它配置進去

  • 提升開發交流,每個服務足夠內聚,足夠小,代碼容易理解

  • 進程隔離、故障隔離

  • 單塊架構中,整個系統運行在同一個進程中,當應用進行部署時,必須停掉當前正在運行的應用,部署完成後再重啓進程,無法做到獨立部署 有時候我們會將重複的代碼抽取出來封裝成組件,在單塊架構中,組件通常的形態叫做共享庫(如 jar 包或者DLL),但是當程序運行時,所有組件最終也會被加載到同一進程中運行。

    • 在微服務架構中,應用程序由多個服務組成,每個服務都是高度自治的獨立業務實體,可以運行在獨立的進程中,不同的服務能非常容易地部署到不同的主機上

  • 即使應用程序的一項服務不起作用,系統仍然可以繼續運行

  • 數據分區,數據獨立,可靠性保證

微服務的缺點

  • 微服務提高了系統的複雜度

  • 開發人員要處理分佈式系統的複雜性

  • 服務之間的分佈式事務問題

  • 服務的註冊與發現問題

  • 數據隔離再來的報表處理問題

  • 不同服務實例的管理困難,持續自動化部署的要求

  • 運維要求較高

  • 對於單體架構來講,我們只需要維護好這一個項目就可以了,但是對於微服務架構來講,由於項目是由多個微服務構成的,每個模塊出現問題都會造成整個項目運行出現異常,想要知道是哪個模塊造成的問題往往是不容易的,因爲我們無法一步一步通過debug的方式來跟蹤,這就對運維人員提出了很高的要求

  • 分佈式的複雜性

  • 對於單體架構來講,我們可以不使用分佈式,但是對於微服務架構來說,分佈式幾乎是必會用的技術,由於分佈式本身的複雜性,導致微服務架構也變得複雜起來

  • 接口調整成本高

  • 比如,用戶微服務是要被訂單微服務和電影微服務所調用的,一旦用戶微服務的接口發生大的變動,那麼所有依賴它的微服務都要做相應的調整,由於微服務可能非常多,那麼調整接口所造成的成本將會明顯提高

微服務的溝通

溝通與事件廣播

微服務的規劃與單體式應用程序十分不同,微服務中每個服務都需要避免與其他服務有所牽連,且都要能夠自主,並在其他服務發生錯誤時不受干擾
倘若真有溝通,也應採用異步溝通的方式來避免緊密的相依性問題。要達到此目的,則可用下列兩種方式:

  • 事件存儲中心(Event Store)
    這可以讓你在服務集羣中廣播事件,並且在每個服務中監聽這些事件並作處理,這令服務之間沒有緊密的相依性,而這些發生的事件都會被保存在事件存儲中心裏。這意味着當微服務重新上線、部署時可以重播(Replay)所有的事件。這也造就了微服務的數據庫隨時都可以被刪除、摧毀,且不需要從其他服務中獲取數據

  • 消息隊列(Message Queue)

  • 能夠在服務集羣中廣播消息,並傳遞到每個服務中

  • 比較有名的消息中間件如:NSQ、RabbitMQ、Nats、Kafka

  • A 服務上廣播一個事件,此事件可以順帶一些數據。B 服務可以監聽這個事件並在接收到之後有所處理。這些過程都是異步處理的

  • A 服務並不需要等到 B 服務處理完該事件後才能繼續,而這也代表 A 服務無法獲取 B 服務的處理結果

  • 與事件存儲中心不同的是:消息隊列並不會保存事件。一旦事件被消化(接收)後就會從隊列中消失

服務發現


  • 單個微服務在上線的時候,會向服務註冊中心註冊自己的 IP 位置、服務內容

  • 當服務需要調用另一個服務的時候,會去詢問服務探索中心該服務的 IP 位置,得到位置後即可直接向目標服務發起調用

  • 這麼做的用意是可以統一集中所有服務的位置,就不會分散於每個微服務中

  • 服務發現中心可以每隔一段時間就向微服務進行健康檢查(TCP 調用、HTTP 調用、Ping)

  • 倘若該服務在時間內沒有迴應,則將其從服務中心移除,避免其他微服務對一個無迴應的服務進行調用

  • 即便微服務重新在其他ip上部署,其他服務也是無感知的

  • 比較常用的服務發現有:etcd,consul,普遍都採用了raft等分佈式算法

微服務其他需要考慮的因素

  • 網絡延遲

  • 分佈式事務

  • 限流

  • 例如一個服務掛掉後,上游服務或者用戶一般會習慣性地重試訪問。這導致一旦服務恢復正常,很可能因爲瞬間網絡流量過大又立刻掛掉

  • 因此服務需要能夠自我保護——限流。限流策略有很多,最簡單的比如當單位時間內請求數過多時,丟棄多餘的請求。另外,也可以考慮分區限流。僅拒絕來自產生大量請求的服務的請求

  • 熔斷

  • 當一個服務因爲各種原因停止響應時,調用方通常會等待一段時間,然後超時或者收到錯誤返回

  • 如果調用鏈路比較長,可能會導致請求堆積,整條鏈路佔用大量資源一直在等待下游響應。所以當多次訪問一個服務失敗時,應熔斷,標記該服務已停止工作,直接返回錯誤。直至該服務恢復正常後再重新建立連接

  • 服務降級

  • 當Service A調用Service B,失敗多次達到一定閥值,Service A不會再去調Service B,而會去執行本地的降級方法

  • 降級服務其實就是犧牲掉一些邏輯處理,或者停止部分依賴服務的請求。以保障服務可以提供關鍵能力

  • 權限控制

  • API網關

  • 分佈式追蹤

  • 分佈式日誌記錄

  • 配置中心

參考資料


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