基於SpringCloud分布式架構


基於SpringCloud分布式架構

為什么要使用分布式架構

  • Spring Cloud 專注於提供良好的開箱即用經驗的典型用例和可擴展性機制覆蓋
  • 分布式/版本化配置
  • 服務注冊和發現
  • 路由
  • Service-to-Service 調用
  • 負載均衡
  • 斷路器
  • 分布式消息傳遞

這是分布式的優點,這樣看起來可能比較抽象,舉個例子來說,對於單體服務來說,如果我想更新訂單中的某個功能,我是不是需要重啟整個服務。

這個時候就會導致整個項目都處於不可用狀態,或者在處理訂單的時候由於程序代碼寫的有問題,導致死鎖了,這個時候也會導致整個服務處於宕機專改,容錯率很差。

但是分布式不同,如上圖所示,訂單服務、售后服務、用戶服務都是獨立的服務,如果需要更新訂單服務或者訂單服務發生死鎖,受影響的只會是訂單服務,售后服務與用戶服務還是可以正常工作的,這就是分布式相對單體來說最大的優勢之一。

分布式基礎組件

Spring Cloud Config:配置管理工具包,讓你可以把配置放到遠程服務器,集中化管理集群配置,目前支持本地存儲、Git 以及 Subversion。

Spring Cloud Bus:事件、消息總線,用於在集群(例如,配置變化事件)中傳播狀態變化,可與 Spring Cloud Config 聯合實現熱部署。

Eureka:雲端服務發現,一個基於 REST 的服務,用於定位服務,以實現雲端中間層服務發現和故障轉移。

Hystrix:熔斷器,容錯管理工具,旨在通過熔斷機制控制服務和第三方庫的節點,從而對延遲和故障提供更強大的容錯能力。

Zuul:Zuul 是在雲平台上提供動態路由,監控,彈性,安全等邊緣服務的框架。Zuul 相當於是設備和 Netflix 流應用的 Web 網站后端所有請求的前門。

Archaius:配置管理 API,包含一系列配置管理 API,提供動態類型化屬性、線程安全配置操作、輪詢框架、回調機制等功能。

Consul:封裝了 Consul 操作,Consul 是一個服務發現與配置工具,與 Docker 容器可以無縫集成。

Spring Cloud for Cloud Foundry:通過 Oauth2 協議綁定服務到 CloudFoundry,CloudFoundry 是 VMware 推出的開源 PaaS 雲平台。

Spring Cloud Sleuth:日志收集工具包,封裝了 Dapper 和 log-based 追蹤以及 Zipkin 和 HTrace 操作,為 Spring Cloud 應用實現了一種分布式追蹤解決方案。

Spring Cloud Data Flow:大數據操作工具,作為 Spring XD 的替代產品,它是一個混合計算模型,結合了流數據與批量數據的處理方式。

Spring Cloud Security:基於 Spring Security 的安全工具包,為你的應用程序添加安全控制。

Spring Cloud Zookeeper:操作 Zookeeper 的工具包,用於使用 Zookeeper 方式的服務發現和配置管理。

Spring Cloud Stream:數據流操作開發包,封裝了與 Redis、Rabbit、Kafka 等發送接收消息。

Spring Cloud CLI:基於 Spring Boot CLI,可以讓你以命令行方式快速建立雲組件。

Ribbon:提供雲端負載均衡,有多種負載均衡策略可供選擇,可配合服務發現和斷路器使用。

Turbine:Turbine 是聚合服務器發送事件流數據的一個工具,用來監控集群下 Hystrix 的 Metrics 情況。

Feign:Feign 是一種聲明式、模板化的 HTTP 客戶端。

Spring Cloud Task:提供雲端計划任務管理、任務調度。

Spring Cloud Connectors:便於雲端應用程序在各種 PaaS 平台連接到后端,如:數據庫和消息代理服務。

Spring Cloud Cluster:提供 Leadership 選舉,如:Zookeeper,Redis,Hazelcast,Consul 等常見狀態模式的抽象和實現。

Spring Cloud Starters:Spring Boot 式的啟動項目,為 Spring Cloud 提供開箱即用的依賴管理。

我們常用的組件:

  • Spring Cloud Config
  • Spring Cloud Bus
  • Hystrix
  • Eureka
  • Zuul
  • Ribbon
  • Feign

Eureka

Eureka 屬於 Spring Cloud Netflix 下的組件之一,主要負責服務的注冊與發現,何為注冊與發現?

在剛剛我們分析的分布式中存在這一個問題,那就是訂單服務與用戶服務被獨立了,那么他們怎么進行通信呢?比如在訂單服務中獲取用戶的基礎信息,這個時候我們需要怎么辦?

如果按照上面的架構圖,直接去數據庫獲取就可以了,因為服務雖然獨立了,但是數據庫還是共享的,所以直接查詢數據庫就能得到結果,如果我們將數據庫也拆分了呢?這個時候我們該怎么辦呢?

有人想到了,服務調用,服務調用是不是需要 IP 和端口才可以,那問題來了,對於訂單服務來說,我怎么知道用戶服務的 IP 和端口呢?在訂單服務中寫死嗎?如果用戶服務的端口發生改變了呢?

這個時候 Eureka 就出來了,他就是為了解決服務的通信問題,每個服務都可以將自己的信息注冊到 Eureka 中,比如 IP、端口、服務名等信息,這個時候如果訂單服務想要獲取用戶服務的信息,只需要去 Eureka 中獲取即可。

請看下圖:

spring-cloud-micro

這就是 Eureka 的主要功能,也是我們使用中的最值得注意的,他讓服務之間的通信變得更加的簡單靈活。

Spring Cloud Config

Spring Cloud Config 為分布式系統中的外部配置提供服務器和客戶端支持。使用 Config Server,您可以在所有環境中管理應用程序的外部屬性。

客戶端和服務器上的概念映射與 Spring Environment 和 PropertySource 抽象相同,因此它們與 Spring 應用程序非常契合,但可以與任何以任何語言運行的應用程序一起使用。

隨着應用程序通過從開發人員到測試和生產的部署流程,您可以管理這些環境之間的配置,並確定應用程序具有遷移時需要運行的一切。

服務器存儲后端的默認實現使用 Git,因此它輕松支持標簽版本的配置環境,以及可以訪問用於管理內容的各種工具。可以輕松添加替代實現,並使用 Spring 配置將其插入。

簡單點來說集中來管理每個服務的配置文件,將配置文件與服務分離,這么多的目的是什么?

舉個簡單的栗子,我們配置文件中肯定會存在數據庫的連接信息,Redis 的連接信息,我們的環境是多樣的,有開發環境、測試環境、預發布環境、生產環境。

每個環境對應的連接信息肯定是不相同的,難道每次發布的時候都要去修改一下服務中的配置文件?

我能不能將這些變動較大的配置集中管理,不同環境的管理者分別對他們進行修改,就不需要再服務中做改動了,Config 就做到了。

spring-cloud-micro

這就是 Config 的大致架構,所有的配置文件都集中交給 Config 管理,拿 Config 怎么管理這些配置文件呢?

你可以將每個環境的配置文件存放再一個位置,比如 Lgitlab、SVN、本地等等,Config 會根據根據你設置的位置讀取配置文件進行管理,然后其他服務啟動的時候直接到 Config 配置中心獲取對應的配置文件即可。

這樣開發人員只需要關注 -dev 的配置文件,測試人員只需要關注 -test 的配置文件,完全和服務解耦,你值得擁有。

Netflix Zuul(網關)

路由在微服務體系結構的一個組成部分。例如,/可以映射到您的 Web 應用程序,/api/users 映射到用戶服務,並將 /api/shop 映射到商店服務。Zuul 是 Netflix 的基於 JVM 的路由器和服務器端負載均衡器。

Netflix 使用 Zuul 進行以下操作:

  • 認證 -洞察
  • 壓力測試
  • 金絲雀測試
  • 動態路由
  • 服務遷移
  • 負載脫落
  • 安全
  • 靜態響應處理
  • 主動/主動流量管理

我們在日常開發過程中並不會使用那么多,基本上就是認證、動態路由、安全等等,我畫了一張關於網關的架構圖,請看:

spring-cloud-micro

注意:Nginx 只能為我們做反向代理,不能做到權限認證,網關不但可以做到代理,也能做到權限認證、甚至還能做限流,所以我們要做分布式項目,少了他可不行。

Spring Cloud Bus

application.yml spring: datasource: username: root password: 123456 url: jdbc:mysql://localhost:3306/test driver-class-name: com.mysql.cj.jdbc.Driver 

比如上面這行配置大家都應該很熟悉,這是數據庫的連接信息,如果它發生改變了怎么辦呢?

我們都知道,服務啟動的時候會去 Config 配置中心拉取配置信息,但是啟動完成之后修改了配置文件我們應該怎么辦呢,重啟服務器嗎?

我們可以通過 Spring Cloud Bus 來解決這個問題,Spring Cloud Bus 將輕量級消息代理鏈接到分布式系統的節點。然后可以將其用於廣播狀態更改(例如,配置更改)或其他管理指令。

我們可以通過 Spring Cloud Bus 來解決這個問題,Spring Cloud Bus 將輕量級消息代理鏈接到分布式系統的節點。然后可以將其用於廣播狀態更改(例如,配置更改)或其他管理指令。

這個需要我們有一點的 MQ 基礎,不管是 RabbitMQ 還是 Kafka,都可以。

Bus 的基本原理就是:配置文件發生改變時,Config 會發出一個 MQ,告訴服務,配置文件發生改變了,並且還發出了改變的哪些信息,這個時候服務只需要根據 MQ 的信息做實時修改即可。

這是一個很簡單的原理,理解起來可能也不會怎么難,畫個圖來理解一下:

spring-cloud-micro

大致流程就是這樣,核心就是通過 MQ 機制實現不重啟服務也能做到配置文件的改動,這方便了運維工程師,不用每次修改配置文件的時候都要去重啟一遍服務的煩惱。

Feign

Feign 是一個聲明式的 Web 服務客戶端。這使得 Web 服務客戶端的寫入更加方便 要使用 Feign 創建一個界面並對其進行注釋。

它具有可插入注釋支持,包括 Feign 注釋和 JAX-RS 注釋。Feign 還支持可插拔編碼器和解碼器。

Spring Cloud 增加了對 Spring MVC 注釋的支持,並使用 Spring Web 中默認使用的 HttpMessageConverters。

Spring Cloud 集成 Ribbon 和 Eureka 以在使用 Feign 時提供負載均衡的 HTTP 客戶端。

spring-cloud-micro

Feign 基於 Rest 風格,簡單易懂,他的底層是對 HttpClient 進行了一層封裝,使用十分方便。

Netflix Hystrix(熔斷)

Hystrix 支持回退的概念:當電路斷開或出現錯誤時執行的默認代碼路徑。要為給定的 @FeignClient 啟用回退,請將 Fallback 屬性設置為實現回退的類名。

我們可以改造一下剛剛的調用架構:

spring-cloud-micro

在這里我部署了一台備用服務器,當用戶服務宕機了之后,訂單服務進行遠程調用的時候可以進入備用服務,這樣就不會導致系統崩潰。

MQ(消息中間件)

我現在這里有一個需求,修改密碼,修改密碼需要發送短信驗證碼,發送短信在短信服務中,修改密碼在用戶服務中,這個時候就會出現服務調用。

而且我們知道,發送短信一般都是調用第三方的接口,那比如阿里的,既然牽扯到調用,那么就會存在很多不確定因素,比如網絡問題。

假如,用戶再點擊發送短信驗證碼到時候用戶服務調用短信服務,但是在短信服務中執行調用阿里的接口花費了很長的時間。

這個時候就會導致用戶服務調短信服務超時,會返回給用戶失敗,但是,短信最后又發出去了,這種問題怎么解決呢?

我們可以通過消息中間件來實現,使用異步講給用戶的反饋和發送短信分離,只要用戶點了發送短信,直接返回成功,然后再啟動發送驗證碼,60 秒重發一下,就算發送失敗,用戶還可以選擇重新發送。

MQ 不但可以解耦服務,它還可以用來削峰,提高系統的性能,是一個不錯的選擇。

spring-cloud-micro

分布式事務

既然我們使用了分布式架構,那么有一點是我們必須要注意的,那就是事務問題。

如果一個服務的修改依賴另外一個服務的操作,這個時候如果操作不慎,就會導致可怕的后果。

舉個例子,兩個服務:錢包服務(用於充值提現)、交易錢包服務(用於交易),我現在想從錢包服務中轉 1000 元到交易錢包服務中,我們應該如何保證他們數據的一致性呢?

我這里有兩種方案,第一種是通過 MQ 來保證一致性,另外一種就是通過分布式事務來確保一致性。

MQ 確保一致性

  • 生成一個訂單表,記錄着轉入轉出的狀態。
  • 向 MQ 發送一條確認消息。
  • 開啟本地事務,執行轉出操操作,並且提交事務。

交易錢包服務:接收 MQ 的消息,進行轉入操作(此操作需要 Ack 確認機制的支持)。

系統中會一直定時掃描訂單中狀態,沒有成功的就做補償機制或者重試機制,這個不是唯一要求。

spring-cloud-micro

以上就是 MQ 確保分布式事務的大致思路,不是唯一,僅供參考。

Seata(分布式事務)

Seata 有三個基本組成部分:

  • 事務協調器(TC):維護全局事務和分支事務的狀態,驅動全局提交或回滾。
  • 事務管理器 TM:定義全局事務的范圍:開始全局事務,提交或回滾全局事務。
  • 資源管理器(RM):管理分支事務正在處理的資源,與 TC 進行對話以注冊分支事務並報告分支事務的狀態,並驅動分支事務的提交或回滾。

spring-cloud-micro

Seata 管理的分布式事務的典型生命周期:

  • TM 要求 TC 開始一項新的全球交易。TC 生成代表全局事務的 XID。
  • XID 通過微服務的調用鏈傳播。
  • RM 將本地事務注冊為 XID 到 TC 的相應全局事務的分支。
  • TM 要求 TC 提交或回滾 XID 的相應全局事務。
  • TC 驅動 XID 對應的全局事務下的所有分支事務以完成分支提交或回滾。

完整的分布式架構

完整的分布式架構如下圖:

spring-cloud-micro

這就是一套分布式基本的架構,請求從瀏覽器發出,經過 Nginx 反向代理到 Zuul 網關。

網關經過權限校驗、然后分別轉發到對應的服務中,每個服務都有自己獨立的數據庫,如果需要跨庫查詢的時候就需要用到分布式的遠程調用(Feign)。

雖然這里我將服務拆分了,但是有一點需要注意的是網關,網關承載着所有的請求,如果請求過大會發生什么呢?

服務宕機,所以一般情況下,網關都是集群部署,不止網關可以集群,其他的服務都可以做集群配置,比如:注冊中心、Redis、MQ 等等都可以。

那我們將這個流程圖再改良一下:

spring-cloud-micro

現在這套架構就是比較程數的一套了,不管是性能還是穩定能,都是杠杠的,技術選擇性的會也開得差不多了,最后技術總監做了一個總結。

總結

單體服務與分布式服務區別

區別 傳統單體架構 分布式服務架構
新功能開發 需要時間 容易開發和實現
部署 不經常且容易部署 經常發布,部署復雜
隔離性 故障影響范圍大 故障影響范圍小
架構設計 難度小 難度級數增大
系統性能 響應時間快,吞吐量小 響應時間慢,吞吐量大
系統運維 運維簡單 運維復雜
新手上手 學習曲線大(業務邏輯) 學習曲線大(構架邏輯)
技術 技術單一且封閉 技術多樣且開放
測試和查錯 簡單 復雜
系統擴展性 擴展性差 擴展性很好
系統管理 重點在於開放成本 重點在於服務治理和調度

什么時候使用分布式/集群?

總結如下幾點:

  • 單機無法支持的時候。
  • 想要更好的隔離性(功能與功能)。
  • 想要更好用戶體驗的時候。
  • 想要更好的擴展性。
  • 想要更快的響應,更搞得吞吐量。

使用分布式注意事項

雖然現在分布式技術已經十分成熟,但是里面的坑不是一點兩點,比如:==如何保證分布式事務的一致性、如何保證服務調用的冪等性、如何保證消息的冪等性、如何設置熔斷(服務的降級),如何保證服務的健壯性等等,==這些都是一直需要關注的問題,只有解決了這些問題,你的分布式架構才能真正的立於不敗之地。

關於組件停更消息

目前注冊中心 Eureka、網關 Zuul,Feign 都相繼停更了,停更不代表不能使用,只是除了 Bug 可能不會主動修復,所以這個時候我們可能就需要選擇另外的組件了。

注冊中心可以使用 Consul、Nacos,Zookeeper,網關則可以通過 Gateway 替換,OpenFeign 替換 Fiegn。

所以也沒必要聽到組件停更的消息就擔心 Cloud 會不會涼,放心,它至少最近幾年是不會涼的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM