Spring Cloud筆記

Spring Cloud 是一個基於 SpringBoot 實現的雲原生應用開發工具,它爲基於JVM的雲原生應用開發中涉及的配置管理、服務發現、熔斷器、智能路由、微代理、控制總線、分佈式會話和集羣狀態管理等操作提供了一種簡單的開發方式。

爲開發人員提供了快速構建分佈式系統的一些工具,包括配置管理、服務發現、斷路器、路由、微代理、事件總線、全局鎖、決策競選、分佈式會話等等。

 

單體架構

1、複雜性高

整個項目包含的模塊非常多、模塊的邊界模糊、依賴關係不清晰、代碼質量參差不齊、混亂地堆砌在一起。使得整個項目非常複雜。每次修改代碼都心驚膽戰,甚至添加一個簡單的功能,或者修改一個Bug都會帶來隱含的缺陷。

2、技術債務

隨着時間推移、需求變更和人員更迭,會逐漸形成應用程序的技術債務, 並且越積越多。“不壞不修(Not broker, don't fix"),這在軟件開發中非常常見,在單體應用中這種思想更甚。已使用的系統設計或代碼難以被修改,因爲應用程序中的 其他模塊可能會以意料之外的方式使用它。

3、部署頻率低

隨着代碼的增多,構建和部署的時間也會增加。而在單體應用中,每次功能的變更或缺陷的修復都會導致需要重新部署整個應用。全量部署的方式耗時長、影響範圍大、風險高,這使得單體應用項目上線部署的頻率較低。而部署頻率低又導致兩次發佈之間會有大量的功能變更和缺陷修復,出錯概率比較高。

4、可靠性差

某個應用Bug,例如死循環、OOM等,可能會導致整個應用的崩潰。

5、擴展能力受限

單體應用只能作爲一個整體進行擴展,無法根據業務模塊的需要進行伸縮。例如:應用中有的模塊是計算密集型的,它需要強勁的CPU;有的模塊則是IO密集型的,需要更大的內存。由於這些模塊部署在一起,不得不在硬件的選擇上做出妥協。

6、阻礙技術創新

單體應用往往使用統一的技術平臺或方案解決所有的問題,團隊中的每個成員都必須使用相同的開發語言和框架,要想引人新框架或新技術平臺會非常困難。例如:一個使用 Struts2 構建的、有100萬行代碼的單體應用,如果想要換用 Spring MVC,毫無疑問切換的成本是非常高的。

 

微服務架構

微服務架構風格是一種將一個單一應用程序開發爲一組小型服務的方法,每個服務運行在自己的進程中,服務間通信採用輕量級通信機制(通常用HTTP API)這些服務圍繞業務能力構建並且可通過全自動部署機制獨立部置。這些服務共用一個最小型的集中式的管理,服務可用不同的語言開發,使用不同的數據存儲技術。

架構特徵

  • 每個微服務可獨立運行在自己的進程裏。
  • 一系列獨立運行的微服務共同構建起整個系統。
  • 每個服務爲獨立的業務開發,一個微服務只關注某個特定的功能,例如訂單管理、用戶管理等。
  • 微服務之間通過一些輕量的通信機制進行通信,例如通過 RESTFUL API 進行調用。
  • 可以使用不同的語言與數據存儲技術。
  • 全自動的部署機制。

架構特點

  • 約定優於配置。
  • 適用於各種環境。開發、部署在 PC Server 或各種雲環境(例如阿里雲、AWS等)均可。
  • 隱藏了組件的複雜性,並提供聲明式、無xml的配置方式。 開箱即用,快速啓動。
  • 輕量級的組件。 例如 Eureka、Zuul 等,都是各自領域輕量級的實現。
  • 組件豐富,功能齊全。 爲微服務架構提供了非常完整的支持。例如:配置管理、服務發現、斷路器、微服務網關等。
  • 選型中立、豐富。例如:支持使用 Eureka、 Zookeeper 或 Consul 等實現服務發現。
  • 靈活,Spring Cloud 的組成部分是解耦的,開發人員可按需靈活挑選技術選型。

 

我們使用 Spring Cloud Netflix 中的 Eureka 作爲服務註冊中心完成服務註冊與發現;而服務間通過 Feign 和 Ribbon 實現服務的消費以及負載均衡;通過 Spring Cloud Config 實現了應用多環境的外部化配置以及版本管理。爲了使得服務集羣更爲健壯,使用 Hystrix 的融斷機制來避免在微服務架構中個別服務出現異常時引起的故障蔓延。

 

Spring Cloud 核心組件

1、Eureka:服務治理組件

Eureka 是微服務架構中的註冊中心,專門負責服務的註冊與發現。

Eureka Client:是一個java客戶端,用於簡化與 Eureka Server 的交互,負責將這個服務的信息註冊到 Eureka Server 中。

Eureka Server:註冊中心,提供服務註冊服務,各個節點啓動後,會在 Eureka Server 中進行註冊,這樣 Eureka Server 中的服務註冊表中將會存儲所有可用服務節點的信息,服務節點的信息可以在界面中直觀的看到。

在應用啓動後,通過 Eureka Client 向 Eureka Server 發送心跳,默認週期爲30秒,如果 Eureka Server 在多個心跳週期內沒有接收到某個節點的心跳,Eureka Server 將會從服務註冊表中把這個服務節點移除(默認90秒),收到響應後,就可以發送請求過去調用相應的服務接口。

Eureka Server 之間通過複製的方式完成數據的同步,Eureka 還提供了客戶端緩存機制,即使所有的 Eureka Server 都掛掉,客戶端依然可以利用緩存中的信息消費其他服務的 API。綜上,Eureka 通過心跳檢查、客戶端緩存等機制,確保了系統的高可用性、靈活性和可伸縮性。

Eureka 的高可用(Eureka集羣):搭建 Eureka 集羣非常簡單,只要啓動多個 Eureka Server 服務並且讓這些 Server 端之間彼此進行註冊即可實現。

打個比方:庫存服務、倉儲服務、積分服務中都有一個 Eureka Client 組件,這個組件專門負責將這個服務的信息註冊到 Eureka Server 中。說白了,就是告訴 Eureka Server,自己在哪臺機器上,監聽着哪個端口。訂單服務裏也有一個 Eureka Client 組件,這個 Eureka Client 組件會找 Eureka Server 問一下:庫存服務在哪臺機器啊?監聽着哪個端口啊?倉儲服務呢?積分服務呢?然後就可以把這些相關信息從 Eureka Server 的註冊表中拉取到自己的本地緩存中來。這時如果訂單服務想要調用庫存服務,不就可以找自己本地的 Eureka Client 問一下庫存服務在哪臺機器?監聽哪個端口嗎?收到響應後,緊接着就可以發送一個請求過去,調用庫存服務扣減庫存的那個接口!同理,如果訂單服務要調用倉儲服務、積分服務,也是如法炮製。

 

2、Ribbon:客戶端負載均衡的服務調用組件

Ribbon 是 Netflix 發佈的負載均衡器,它有助於控制 HTTP 和 TCP 客戶端的行爲。爲 Ribbon 配置服務提供者地址列表後,Ribbon 就可基於某種負載均衡算法,自動地幫助服務消費者去請求。 Ribbon 默認爲我們提供了很多的負載均衡算法,例如輪詢、隨機等。當然,我們也可爲 Ribbon 實現自定義的負載均衡算法。

 

3、Hystrix:容錯保護組件,實現了熔斷器

是隔離、熔斷以及降級的一個框架。

Hystrix 是由 Netflix 開源的一個延遲和容錯庫,用於隔離訪問遠程系統、服務或者第三方庫,防止級聯失敗,從而提升系統的可用性與容錯性。 Hystrix 主要通過以下幾點實現延遲和容錯。

包裹請求:使用 Hystrixcommand(或 Hystrixobservablecommand)包裹對依賴的調用邏輯,每個命令在獨立線程中執行。這使用到了設計模式中的“命令模式”。

跳閘機制:當某服務的錯誤率超過一定閾值時,Hystrix 可以自動或者手動跳閘,停止請求該服務一段時間。

資源隔離:Hystrix 爲每個依賴都維護了一個小型的線程池(或者信號量)。如果該線程池已滿,發往該依賴的請求就被立即拒絕,而不是排隊等候,從而加速失敗判定。

監控:Hystrix 可以近乎實時地監控運行指標和配置的變化,例如成功、失敗、超時以及被拒絕的請求等。

回退機制:當請求失敗、超時、被拒絕或當斷路器打開時執行回退邏輯,回退邏輯可由開發人員自行提供。 

自我修復:斷路器打開一段時間後,會自動進人“半開”狀態。斷路器打開、關閉、半開的邏輯轉換。

打個比方:現在假設訂單服務自己最多隻有 100 個線程可以處理請求,然後呢,積分服務不幸的掛了,每次訂單服務調用積分服務的時候,都會卡住幾秒鐘,然後拋出—個超時異常。然後就會導致別人請求訂單服務的時候,發現訂單服務也掛了,不響應任何請求了。現在很不幸,積分服務掛了,會咋樣?當然會導致訂單服務裏那個用來調用積分服務的線程都卡死不能工作了啊!但由於訂單服務調用庫存服務、倉儲服務的這兩個線程池都是正常工作的,所以這兩個服務不會受到任何影響。這個時候如果別人請求訂單服務,訂單服務還是可以正常調用庫存服務扣減庫存,調用倉儲服務通知發貨。只不過調用積分服務的時候,每次都會報錯。但是如果積分服務都掛了,每次調用都要去卡住幾秒鐘幹啥呢?有意義嗎?當然沒有!所以我們直接對積分服務熔斷不就得了,比如在 5 分鐘內請求積分服務直接就返回了,不要去走網絡請求卡住幾秒鐘,這個過程,就是所謂的熔斷!那人家又說,兄弟,積分服務掛了你就熔斷,好歹你乾點兒什麼啊!別啥都不幹就直接返回啊?沒問題,咱們就來個降級:每次調用積分服務,你就在數據庫裏記錄一條消息,說給某某用戶增加了多少積分,因爲積分服務掛了,導致沒增加成功!這樣等積分服務恢復了,你可以根據這些記錄手工加一下積分。這個過程,就是所謂的降級。

 

4、Feign:聲明式服務調用組件

Feign是 Netflix 開發的聲明式、模板化的HTTP客戶端,其靈感來自 Retrofit、JAXRS-20 以及 Websocket.Feign 可幫助我們更加便捷、優雅地調用 HTTP API。

在 Spring Cloud 中,使用 Feign 非常簡單一創建一個接口,並在接口上添加一些註解,,代碼就完成了。Feign 支持多種註解,例如 Feign 自帶的註解或者 JAX-RS 註解等。

Spring Cloud 對 Feign 進行了增強,使 Feign 支持了 Spring MVC 註解,並整合了 Ribbon 和 Eureka,從而讓 Feign 的使用更加方便。

Feign Client 會在底層根據你的註解,跟你指定的服務建立連接、構造請求、發起請求、獲取響應、解析響應,等等。

對某個接口定義了 @FeignClient 註解,Feign 就會針對這個接口創建一個動態代理。

接着你要是調用那個接口,本質就是會調用 Feign 創建的動態代理,這是核心中的核心。

Feign 的動態代理會根據你在接口上的 @RequestMapping 等註解,來動態構造出你要請求的服務的地址。

針對這個地址,發起請求、解析響應。

 

5、Zuul:服務網關組件,提供智能路由、訪問過濾等功能

微服務網關。這個組件是負責網絡路由的。客戶端請求微服務時,先經過 Zuul 之後再請求,這樣就可以將一些類似於校驗的業務邏輯放到 Zuul 中完成。而微服務自身只需要關注自己的業務邏輯即可。當然在 Zuul 上層也可以搭建 Nginx、F5等負載均衡設施。

服務網關是微服務架構中一個不可或缺的部分。通過服務網關統一向外系統提供 REST API 的過程中,除了具備服務路由、負載均衡功能之外,它還具備了權限控制等功能。Spring Cloud Netflix 中的 Zuul 就擔任了這樣的一個角色,爲微服務架構提供了前門保護的作用,同時將權限控制這些較重的非業務邏輯內容遷移到服務路由層面,使得服務集羣主體能夠具備更高的可複用性和可測試性。

Zuul 是 Netflix 開源的微服務網關,它可以和 Eureka、 Ribbon、 Hystrix 等組件配合使用 Zuul 的核心是一系列的過濾器,這些過濾器可以完成以下功能。

身份認證與安全:識別每個資源的驗證要求,並拒絕那些與要求不符的請求。

審查與監控:在邊緣位置追蹤有意義的數據和統計結果,從而帶來精確的生產視圖。

動態路由:動態地將請求路由到不同的後端集羣。

壓力測試:逐漸增加指向集羣的流量,以瞭解性能。

負載分配:爲每一種負載類型分配對應容量,並棄用超出限定值的請求。

靜態響應處理:在邊緣位置直接建立部分響應,從而避免其轉發到內部集羣。

多區域彈性:跨越 AWS Region 進行請求路由,旨在實現 ELB( Elastic_ Load Balancing)使用的多樣化,以及讓系統的邊緣更貼近系統的使用者。

Spring Cloud 對 Zuul 進行了整合與增強。目前,Zuul 使用的默認 HTTP 客戶端是 Apache HTTP Client,也可以使用 Restclient 或者 okhttp3.Okhttpcliento 如果想要使用 Restclient,可以設置 ribbon.restclientenabled=true 想要使用 okhttp3.okhttpclient,可以設置 rib bon.okhttp.enabled=true。

打個比方:假設你後臺部署了幾百個服務,現在有個前端兄弟,人家請求是直接從瀏覽器那兒發過來的。人家要請求一下庫存服務,你難道還讓人家記着這服務的名字叫做 inventory-service?部署在 5 臺機器上?就算人家肯記住這一個,你後臺可有幾百個服務的名稱和地址呢?難不成人家請求一個,就得記住一個?所以一般微服務架構中都必然會設計一個網關在裏面。像 Android、iOS、PC 前端、微信小程序、H5 等等,不用去關心後端有幾百個服務,就知道有一個網關,所有請求都往網關走,網關會根據請求中的一些特徵,將請求轉發給後端的各個服務。而且有一個網關之後,還有很多好處,比如可以做統一的降級、限流、認證授權、安全,等等。

 

6、Spring Cloud Config:分佈式配置中心

Spring Cloud Config 爲分佈式系統外部化配置提供了服務器端和客戶端的支持,它包 括 Config Server 和 Config Client 兩部分。由於 Config Server 和 Config Client 都實現了對 Spring Environment 和 Propertysource 抽象的映射,因此,Spring Cloud Config 非常適合 Spring 應用程序,當然也可與任何其他語言編寫的應用程序配合使用。

Config Server 是一個可橫向擴展、集中式的配置服務器,它用於集中管理應用程序各個環境下的配置,默認使用 Git 存儲配置文件內容,也可以使用 SVN 存儲,或者是本地文件存儲。

Config Client 是 Config Server 的客戶端,用於操作存儲在 Config Server 中的配置內容。微服務在啓動時會請求 Config Server 獲取配置文件的內容,請求到後再啓動容器。
 

總結

  • Eureka:各個服務啓動時,Eureka Client 都會將服務註冊到 Eureka Server,並且 Eureka Client 還可以反過來從 Eureka Server 拉取註冊表,從而知道其他服務在哪裏。
  • Ribbon:服務間發起請求的時候,基於 Ribbon 做負載均衡,從一個服務的多臺機器中選擇一臺。
  • Feign:基於 Feign 的動態代理機制,根據註解和選擇的機器,拼接請求 URL 地址,發起請求。
  • Hystrix:發起請求是通過 Hystrix 的線程池來走的,不同的服務走不同的線程池,實現了不同服務調用的隔離,避免了服務雪崩的問題。
  • Zuul:如果前端、移動端要調用後端系統,統一從 Zuul 網關進入,由 Zuul 網關轉發請求給對應的服務。

以上就是我們通過一個電商業務場景,闡述了 Spring Cloud 微服務架構幾個核心組件的底層原理。

                                     

 

常見面試題總結

1、Spring Cloud 和 Dubbo有哪些區別?

Dubbo 由於是二進制的傳輸,佔用帶寬會更少。但是開發難度較大,原因是dubbo的jar包依賴問題很多大型工程無法解決。

Spring Cloud 是http協議傳輸,帶寬會比較多,同時使用http協議一般會使用JSON報文,消耗會更大。但是接口協議約定比較自由且鬆散,需要有強有力的行政措施來限制接口無序升級

本質區別: Dubbo 是基於 RPC 遠程過程調用,Spring Cloud 是基於 http rest api 調用。

從系統結構簡易程序:Spring Cloud 的系統結構更簡單、“註冊 + SpringMVC = Spring Cloud”,而 Dubbo 各種複雜的 Url,protocol,register,invocation,dubbofilter,dubboSPI,dubbo序列化..........炫技的成分更多一些。

從性能:Dubbo 的網絡消耗小於 Spring Cloud,但是在國內95%的公司內,網絡消耗不是什麼太大問題,如果真的成了問題,通過壓縮、二進制、高速緩存、分段降級等方法,很容易解。

從開發難易度:Dubbo 的神坑是jar包依賴,開發階段難度極大,Spring Cloud 比較自由。

從後續改進:Dubbo 的改進是通過 dubbofilter,很多東西沒有,需要自己繼承,如監控,如日誌,如限流,如追蹤。Spring Cloud 自己帶了很多監控、限流措施,但是功能可能和歐美習慣相同,國內需要進行適當改造,但更簡單,就是 ServletFilter 而已,但是總歸比 Dubbo 多一些東西是好的。

Dubbo 實踐通常以 ZooKeeper 爲註冊中心(Dubbo 原生支持的Redis 方案需要服務器時間同步,且性能消耗過大)。針對分佈式領域著名的CAP理論(C——數據一致性,A——服務可用性,P——服務對網絡分區故障的容錯性),Zookeeper 保證的是CP ,但對於服務發現而言,可用性比數據一致性更加重要 ,而 Eureka 設計則遵循AP原則 。

嚴格來說,這兩種方式各有優劣。雖然從一定程度上來說,後者犧牲了服務調用的性能,但也避兔了上面提到的原生 RPC 帶來的問題。而且 REST 相比 RPC 更爲靈活,服務提供方和調用方的依賴只依靠一紙契約,不存在代碼級別的強依賴,這在強調快速演化的微服務環境下,顯得更加合適。

 

2、SpringBoot 和 Spring Cloud,請你談談對他們的理解?

 SpringBoot 是一個快速整合第三方框架,關注的是微觀具體關注快速方便的開發單個個體的服務 

 Spring Cloud 關注的是宏觀具體關注全局的微服務協調整理治理框架將 SpringBoot 開發的一個個單體服務整合並管理起來

它爲各個微服務之間提供 配置管理 服務發現 斷路器路由 微代理 全局鎖 分佈式會話 等集成服務

舉個例子:一所醫院 SpringBoot 是一個一個科室 Spring Cloud 是把一個一個科室組合起來對外稱之爲醫院

存在依賴關係  Spring Cloud 離不開 SpringBoot。

 

3、什麼是服務熔斷?

服務熔斷 是指由於某些原因使得服務出現了過載現象,爲防止造成整個系統故障,從而採用的一種保護措施,所以很多地方把熔斷亦稱爲過載保護。 

 

4、什麼是服務降級 微服務的優缺點分別是什麼?

整體資源快不夠了,忍痛將某些服務先關掉,待渡過難關,再開啓回來。

 

5、說下你在項目開發中碰到的坑你所知道的微服務技術棧有哪些?

微服務技術棧:多種技術的結合體 

我們在討論分佈式的微服務架構的時候它需要有哪些維度?服務治理、服務註冊、服務調用、負載均衡、服務監控  

這五點稱爲落地維度,爲什麼叫落地呢 ?天上飛的理念肯定要有落地的實現,也就是說分佈式微服務架構當作天上飛的理念 

落地的實現可以總結爲:

  • 服務開發 :SpringBoot、SpringMVC、Spring 
  • 服務的配置與管理 : Netfix 公司 archaius 阿里的 diamond 等
  • 服務的註冊於發現 :Spriing Cloud 所採用的 Eureka、Consul、Zookeeper 等
  • 服務的調用:REST、GRPC、RPC 
  • 服務的熔斷器 :Hystrix、envoy 等
  • 負載均衡 :Ribbon、Nginx
  • 服務接口調用(客戶端調用服務的簡化工具) Feign 等消息隊列 Kafka、RabbitMQ、ActiveMQ 等
  • 服務配置中心管理 Spring Cloud Config、Chef 等
  • 服務路由(API網關)Zuul 等
  • 服務監控 Zabbix、Nagios、Metrics、Spectator等
  • 全鏈路追蹤 Zipkin、Brave、Dapper等
  • 服務部罟 Docker、Open Stack、Kubernetes等
  • 數據流操作開發包 Spring Cloud Stream(封裝與 Redis、Rabbit、Kafka 等發送接收消息)
  • 事件消息總線 Spring Cloud Bus

 

6、請說說Eureka和 Zookeeper,兩個的區別?

1)、Zookeeper 遵守 CP 

當向註冊中心查詢服務列表時,我們可以容忍註冊中心返回的是幾分鐘以前的註冊信息,但不能接受服務直接down掉不可用。

也就是說,服務註冊功能對一致性的要求要高於可用性。但是 Zookeeper 會出現這樣一種情況,當 master節點因爲網絡故障與其他節點失去聯繫時,剩餘節點會重新進行 leader 選舉。問題在於,選舉 leader的時間太長(30~120s)目選舉期間整個Zookeeper 集羣都是不可用的,這就導致在選舉期間註冊服務癱瘓。在雲部署的環境下,因網絡問題使得 Zookeeper 集羣失去 master節點是較大概率會發生的事,雖然服務能夠最終恢復,但是漫長的選舉時間導致的註冊長期不可用是不能容忍的。 或許這個回答太過於抽象用一種其他說法來說就是:當有一個 Zookeeper 掛了那其他的 Zookeeper 會進行一次選舉(強一致性:我一定要保持數據一致性) 而在此選舉期間 Zookeeper 是不可用的而當前有用戶正在使用用戶就不爽了。

2)、Eureka遵守 AP  

在設計時就優先保證可用性。Eureka各個節點都是平等的,幾個節點掛掉不會影響正常節點的工作,剩餘的節點依然可以提供註冊和查詢服務。而 Eureka的客戶端在向某個 Eureka註冊或時如果發現連接失敗,則會自動切換至其它節點 只要有一臺 Eureka還在,就能保證註冊服務可用(保證可用性),只不過查到的信息可能不是最新的不保證強一致性。

除此之外,Eureka還有一種自我保護機制,如果在15分鐘內超過85%的節點都沒有正常的心跳,那麼 Eureka 就認爲客戶端與註冊中心出現了網絡故障,此時會出現以下幾種情況:

  • Eureka 不再從註冊列表中移除因爲長時間沒收到心跳而應該過期的服務
  • Ureka 仍然能夠接受新服務的註冊和査詢請求,但是不會被同步到其它節點上(即保證當前節點依然可用)
  • 當網絡穩定時,當前實例新的註冊信息會被同步到其它節點中

因此,Eureka 可以很好的應對因網絡故障導致部分節點失去聯繫的情況,而不會像 Zookeeper 那樣使整個註冊服務癱瘓。

 

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