宣告式服務呼叫 Spring Cloud Feign

dffgfff發表於2021-01-19

Spring Cloud 為了簡化服務間的呼叫,在Ribbon的基礎上進行了進一步的封裝。單獨抽出了一個元件,就是Spring Cloud Feign。在引入Spring Cloud Feign後,我們只需要建立一個介面並用註解的方式來配置它,即可完成對服務提供方的介面繫結。

Spring Cloud Feign具備可插拔的註解支援,並擴充套件了Spring MVC的註解支援。

下面我們來看一個具體的例子:

服務方具體的介面定義與實現程式碼如下:

import org.springframework.cloud.netflix.feign.FeignClient;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RequestParam;/**
 * 介面定義
 */@FeignClient(value="service-hi",fallback = TestFeignServiceImpl.class)public interface TestFeignService {
    @RequestMapping(value="/hi",method = RequestMethod.GET)
    String sayHi(@RequestParam("name") String name);}/**
 * 具體的服務實現
 */@Componentpublic class TestFeignServiceImpl implements TestFeignService {
    @Override
    public String sayHi(String name) {
        return "你好,"+name;
    }}123456789101112131415161718192021222324

呼叫方的使用程式碼如下:

@RestControllerpublic class TestController{
    @Resource
    private TestFeignService testFeignService;
    @RequestMapping(value="/hi",method = RequestMethod.GET)
    public String sayHi(@RequestParam String name)
    {
    	// 呼叫遠端服務
        return testFeignService.sayHi(name);
    }}12345678910111213

通過上面的程式碼,我們可以看到,呼叫方通過feign程式遠端服務呼叫的時候,非常簡單,就向是在呼叫本地服務一樣。

像之前的建立連線,構造請求,發起請求,獲取響應,解析響應等等操作,對使用者來說都是透明化的,使用者不用關心服務是怎麼實現呼叫的,直接使用即可。

那麼feign是如何實現這套封裝邏輯的呢?

其實 feign底層主要是靠動態代理來實現這整個服務的呼叫過程的。
主要邏輯如下:

  • 如果一個介面上定義了@FeignClient註解,Feign就會根據這個介面生成一個動態代理類。
  • 如果呼叫方,在呼叫這個定義了@FeignClient註解的介面時,本質上是會呼叫Feign生成的代理類。
  • Feign生成的動態代理類,會根據具體介面方法中的@RequestMapping等註解,來動態構造出需要請求的服務地址。
  • 最後針對這個地址,再通過Ribbon發起服務呼叫,解析響應等操作。

在這裡插入圖片描述
因為Spring Cloud Feign的使用方式比Spring Cloud Ribbon更方便,所以一般專案中都是使用Feign,而且Feign還有繼承特性,可以將遠端服務介面繼承過來然後再進行自己的個性化擴充套件。因此Feign的使用範圍以及普及率更高一些。

服務容錯保護 Spring Cloud Hystrix

在微服務架構中,我們將系統拆分成多個服務單元,各個服務之間通過服務註冊與訂閱的方式互相依賴。

我們以一個電商網站下單的過程來舉例,在下單的業務操作過程中需要呼叫庫存服務,支付服務,積分、物流等服務。 假設訂單服務最多同一時間只能處理50個請求,這個時候如果積分服務掛了,那麼每次訂單服務去呼叫積分服務的時候,都會卡這麼一段時間,然後才返回超時異常

在這種場景下會有什麼問題呢?

如果目前電商網站正在搞活動,進行搶購活動,下單的人非常多,這種高併發的場景下,訂單服務的已經同時在處理50個下單請求了,並且都卡在了請求積分服務的過程中。訂單服務已經沒有能力去處理其他請求了。

那麼其他服務再來呼叫訂單服務時,發訂單服務無響應,這樣就導致訂單服務也不可用了。然後其他依賴訂單服務的服務,也最終會導致不可用。 這就是微服務架構中的服務雪崩。

在這裡插入圖片描述

就上圖所示,如果多個服務之間相互呼叫,而不做任何保護措施的話,那麼一個服務掛了,就會產生連鎖反應,導致其他服務也掛了。

其實就算是積分服務掛了,也並不應該導致訂單服務也掛了,積分服務掛了,我們可以跳過積分服務,或者是放一個預設值,然後繼續往下走,等著積分服務恢復了,可以手動恢復一下資料。

那麼Spring Cloud Hystrix就是解決這個問題的元件,他主要是起到熔斷,隔離,降級的作用。

Spring Cloud Hystrix其實是會為每一個服務開闢一個執行緒池,然後每個執行緒池中的執行緒用於對服務的呼叫請求。這樣就算是積分服務掛了,那也只是呼叫積分服務的執行緒池出現問題了,而其他服務的執行緒池還正常工作。 這就是服務的隔離。

這樣訂單服務在的呼叫積分服務的時候,如果發現有問題了,積分服務可以通過 Hystrix返回一個預設值(預設是5秒內20次呼叫失敗就熔斷)。這樣訂單服務就不用在這裡卡住了,可以繼續往下呼叫其他服務進行業務操作了。 這就是服務的熔斷。

雖然說是積分服務掛了,並且也返回了預設值了,但是後續如果積分服務恢復了,想恢復資料怎麼辦呢?這個時候積分服務可以將姐收到的請求記錄下來,或者是打到日誌中,能為後面恢復資料提供依據就行。 這就是服務的降級

整個過程大致如下圖所示:
在這裡插入圖片描述

API閘道器服務Spring Cloud Zuul

通過上面幾個元件的結合使用,已經能夠完成一個基本的微服務架構了。但是當一個系統中微服務的數量逐漸增多時,一些通用的邏輯,例如:許可權校驗機制,請求過濾,請求路由,限流等等,這些每個服務對外提供能力的時候都要考慮到的邏輯,就會變得冗餘。

這個時候API閘道器的概念應運而生,它類似於物件導向設計模式中的Facade模式(門面模式/外觀模式),所有的外部客戶端訪問都需要經過它來進行排程和過濾。主要實現請求路由、負載均衡、校驗過濾、服務限流等功能。

Spring Cloud Zuul就是Spring Cloud提供的API閘道器元件,它 通過與Eureka進行整合,將自身註冊為Eureka下的應用,從Eureka下獲取所有服務的例項,來進行服務的路由。

Zuul還提供了一套過濾器機制,開發者可以自己指定哪些規則的請求需要執行校驗邏輯,只有通過校驗邏輯的請求才會被路由到具體服務例項上,否則返回錯誤提示。
在這裡插入圖片描述

Spring Cloud Zuul的依賴包 spring-cloud-starter-zuul本身就包含了對s pring-cloud-starter-hystrixspring-cloud-starter-ribbon模組的依賴,所以Zuul天生就擁有執行緒隔離和斷路器的自我保護功能,以及對服務呼叫的客戶端負載功能。

Zuul的路由實現是通過Path和serviceId還實現的,path是一個http請求去除ip和埠號後的方法路徑,例如: http://192.168.20.12:9001/api-zuul/123,那麼path就是 /api-zuul/123,Zuul在配置時支援模糊匹配,若123是動態引數,可以將path配置成 /pai-zuul/**,serviceId就是服務在Eureka中註冊的服務名稱。

zuul.routes.api-zuul.path= /api-zuul/**
zuul.routes.api-zuul.serviceId= service-jimoer12

有了統一的閘道器後,再做統一的鑑權、限流、認證授權、安全等方面的工作就會變的更加方便了。

總結

上面總結了Spring Cloud的幾個核心元件,其實Spring Cloud 除了這幾個元件還有一些其他的元件,例如:

  • 分散式配置中心Spring Cloud Config
  • 訊息匯流排Spring Cloud Bus
  • 訊息驅動Spring Cloud Stream
  • 分散式服務跟蹤Spring Cloud Sleuth

主要是後面這些元件我們平時用的不多,而且對於微服務來說有些是有替代品的,所以我暫時就沒有總結。還有一點畢竟我這次總結是為了解決面試的問題,所以後面如果在實際的工作中用到了剩下的這些元件,我會繼續總結的。

好了,總結一下這次的幾個元件的內容吧。

  • Spring Cloud Eureka 各個微服務在啟動時將自己註冊到Eureka Server中,並且各個服務中的Eureka Client又能從註冊中心獲取各個服務的例項地址清單。
  • Spring Cloud Ribbon 各個服務相互呼叫的時候,通過Ribbon來進行客戶端的負載均衡,從多個例項中根據一定的策略選擇一臺進行請求。
  • Spring Cloud Feign 基於動態代理機制,根據註解和引數拼接URL,選擇具體的服務例項發起請求,簡化了服務間相互呼叫的開發工作。
  • Spring Cloud Hystrix 呼叫每個服務的時候都是通過執行緒池中的執行緒來發起的,不同的服務走不同的執行緒池,實現了服務的隔離,而且服務不可用時還提供了熔斷機制以及支援降低措施。
  • Spring Cloud Zuul 外部請求統一通過Zuul閘道器來進入,支援自定義路由規則,自定義過濾規則,可以實現同一的鑑權、限流、認證等功能。

最後來一個整體的架構圖,將各個元件串起來。

在這裡插入圖片描述


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69993516/viewspace-2751007/,如需轉載,請註明出處,否則將追究法律責任。

相關文章