Spring Cloud 系列之 Alibaba Sentinel 服務哨兵

前文中我們提到 Netflix 中多項開源產品已進入維護階段,不再開發新的版本,就目前來看是沒有什麼問題的。但是從長遠角度出發,我們還是需要考慮是否有可替代產品使用。比如本文中要介紹的 Alibaba Sentinel 就是一款高性能且輕量級的流量控制、熔斷降級可替換方案。

Sentinel 官網:https://github.com/alibaba/Sentinel

Hystrix 目前狀態

官網提示:https://github.com/Netflix/Hystrix

Hystrix is no longer in active development, and is currently in maintenance mode.

Hystrix 不再主動開發,當前處於維護模式。

Sentinel 是什麼

隨着微服務的流行,服務和服務之間的穩定性變得越來越重要。Sentinel 以流量爲切入點,從流量控制、熔斷降級、系統負載保護等多個維度保護服務的穩定性。

Sentinel 具有以下特徵:

  • 豐富的應用場景:Sentinel 承接了阿里巴巴近 10 年的雙十一大促流量的核心場景,例如秒殺(即突發流量控制在系統容量可以承受的範圍)、消息削峯填谷、集羣流量控制、實時熔斷下游不可用應用等。
  • 完備的實時監控:Sentinel 同時提供實時的監控功能。您可以在控制檯中看到接入應用的單臺機器秒級數據,甚至 500 臺以下規模的集羣的彙總運行情況。
  • 廣泛的開源生態:Sentinel 提供開箱即用的與其它開源框架/庫的整合模塊,例如與 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相應的依賴並進行簡單的配置即可快速地接入 Sentinel。
  • 完善的 SPI 擴展點:Sentinel 提供簡單易用、完善的 SPI 擴展接口。您可以通過實現擴展接口來快速地定製邏輯。例如定製規則管理、適配動態數據源等。

Sentinel 主要特徵

Sentinel 開源生態

Sentinel 目前已經針對 Servlet、Dubbo、Spring Boot/Spring Cloud、gRPC 等進行了適配,用戶只需引入相應依賴並進行簡單配置即可非常方便地享受 Sentinel 的高可用流量防護能力。Sentinel 還爲 Service Mesh 提供了集羣流量防護的能力。未來 Sentinel 還會對更多常用框架進行適配。

Sentinel 分爲兩個部分:

  • 核心庫(Java 客戶端)不依賴任何框架/庫,能夠運行於所有 Java 運行時環境,同時對 Dubbo / Spring Cloud 等框架也有較好的支持。
  • 控制檯(Dashboard)基於 Spring Boot 開發,打包後可以直接運行,不需要額外的 Tomcat 等應用容器。

Sentinel 的歷史

  • 2012 年,Sentinel 誕生,主要功能爲入口流量控制。
  • 2013-2017 年,Sentinel 在阿里巴巴集團內部迅速發展,成爲基礎技術模塊,覆蓋了所有的核心場景。Sentinel 也因此積累了大量的流量歸整場景以及生產實踐。
  • 2018 年,Sentinel 開源,並持續演進。

Sentinel vs Hystrix

Hystrix

官網:https://github.com/Netflix/Hystrix

Hystrix is a latency and fault tolerance library designed to isolate points of access to remote systems, services and 3rd party libraries, stop cascading failure and enable resilience in complex distributed systems where failure is inevitable.

Hystrix 的關注點在於隔離和熔斷爲主的容錯機制,超時或被熔斷的調用將會快速失敗,並可以提供 fallback 機制。

Sentinel

官網:https://github.com/alibaba/Sentinel

Sentinel 的關注點在於:

  • 多樣化的流量控制
  • 熔斷降級
  • 系統負載保護
  • 實時監控和控制檯

Hystrix 遷移 Sentinel 方案

Sentinel 提供了從 Hystrix 遷移到 Sentinel 的方案,官網:https://github.com/alibaba/Sentinel/wiki/Guideline:-從-Hystrix-遷移到-Sentinel

總結

Sentinel Hystrix
隔離策略 信號量隔離(併發線程數限流) 線程池隔離/信號量隔離
熔斷降級策略 基於響應時間、異常比率、異常數 基於異常比率
實時指標實現 滑動窗口(LeapArray) 滑動窗口(基於 RxJava)
規則配置 支持多種數據源 支持多種數據源
擴展性 多個擴展點 插件的形式
基於註解的支持 支持 支持
調用鏈路信息 支持同步調用 不支持
限流 基於 QPS / 併發數,支持基於調用關係的限流 有限支持
流量整形 支持慢啓動、勻速器模式 不支持
系統負載保護 支持 不支持
控制檯 開箱即用,可配置規則、查看秒級監控、機器發現等 較爲簡單
常見框架的適配 Servlet、Spring Cloud、Dubbo、gRPC 等 Servlet、Spring Cloud Netflix

Sentinel 核心

Sentinel 的使用可以分爲兩個部分:

  • 核心庫(Java 客戶端):不依賴任何框架/庫,能夠運行於 Java 7 及以上的版本的運行時環境,同時對 Dubbo / Spring Cloud 等框架也有較好的支持(見 主流框架適配)。
  • 控制檯(Dashboard):控制檯主要負責管理推送規則、監控、集羣限流分配管理、機器發現等。

Sentinel 控制檯

Sentinel 提供一個輕量級的開源控制檯,它提供機器發現以及健康情況管理、監控(單機和集羣),規則管理和推送的功能。

官網文檔:https://github.com/alibaba/Sentinel/wiki/控制檯

獲取控制檯

您可以從 release 頁面 下載最新版本的控制檯 jar 包。

您也可以從最新版本的源碼自行構建 Sentinel 控制檯:

  • 下載 控制檯 工程
  • 使用以下命令將代碼打包成一個 fat jar: mvn clean package

啓動控制檯

啓動命令如下,本文使用的是目前最新 1.7.1 版本:

java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.7.1.jar

注意:啓動 Sentinel 控制檯需要 JDK 版本爲 1.8 及以上版本。

其中 -Dserver.port=8080 用於指定 Sentinel 控制檯端口爲 8080

從 Sentinel 1.6.0 起,Sentinel 控制檯引入基本的登錄功能,默認用戶名和密碼都是 sentinel。可以參考 鑑權模塊文檔 配置用戶名和密碼。

注:若您的應用爲 Spring Boot 或 Spring Cloud 應用,您可以通過 Spring 配置文件來指定配置,詳情請參考 Spring Cloud Alibaba Sentinel 文檔

爲了方便啓動,可以編寫一個啓動腳本 run.bat

java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.7.1.jar
pause

訪問

訪問:http://localhost:8080/

輸入默認用戶名和密碼 sentinel 點擊登錄。至此控制檯就安裝完成了。

環境準備

sentinel-demo 聚合工程。SpringBoot 2.2.4.RELEASESpring Cloud Hoxton.SR1

  • eureka-server:註冊中心
  • eureka-server02:註冊中心
  • product-service:商品服務,提供了 /product/{id} 接口
  • order-service-rest:訂單服務,基於 Ribbon 通過 RestTemplate 調用商品服務
  • order-server-feign:訂單服務,基於 Feign 通過聲明式服務調用商品服務

客戶端接入控制檯

點擊鏈接觀看:客戶端接入控制檯視頻(獲取更多請關注公衆號「哈嘍沃德先生」)

控制檯啓動後,客戶端需要按照以下步驟接入到控制檯:

  • 添加依賴
  • 定義資源
  • 定義規則

先把可能需要保護的資源定義好,之後再配置規則。也可以理解爲,只要有了資源,我們就可以在任何時候靈活地定義各種流量控制規則。在編碼的時候,只需要考慮這個代碼是否需要保護,如果需要保護,就將之定義爲一個資源。

由於我們的項目是 Spring Cloud 項目所以藉助官方文檔來進行學習。

Spring 官網文檔:https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html

Github 文檔:https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel

添加依賴

父工程需要添加如下依賴:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>2.1.0.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

子工程需要添加如下依賴:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

配置文件

客戶端需要啓動 Transport 模塊來與 Sentinel 控制檯進行通信。

order-service-rest 的 application.yml

spring:
  cloud:
    sentinel:
      transport:
        port: 8719
        dashboard: localhost:8080

這裏的 spring.cloud.sentinel.transport.port 端口配置會在應用對應的機器上啓動一個 Http Server,該 Server 會與 Sentinel 控制檯做交互。比如 Sentinel 控制檯添加了一個限流規則,會把規則數據 push 給這個 Http Server 接收,Http Server 再將規則註冊到 Sentinel 中。

初始化客戶端

確保客戶端有訪問量,Sentinel 會在客戶端首次調用的時候進行初始化,開始向控制檯發送心跳包。

簡單的理解就是:訪問一次客戶端,Sentinel 即可完成客戶端初始化操作,並持續向控制檯發送心跳包。

訪問

首先確保 Sentinel 是啓動狀態,然後依次啓動 eureka-server,eureka-server02,product-service,order-service-rest。

多次訪問:http://localhost:9090/order/1 然後查看控制檯實時監控結果如下:

定義資源

點擊鏈接觀看:定義資源視頻(獲取更多請關注公衆號「哈嘍沃德先生」)

資源 是 Sentinel 中的核心概念之一。我們說的資源,可以是任何東西,服務,服務裏的方法,甚至是一段代碼。最常用的資源是我們代碼中的 Java 方法。Sentinel 提供了 @SentinelResource 註解用於定義資源,並提供了 AspectJ 的擴展用於自動定義資源、處理 BlockException 等。

官網文檔:https://github.com/alibaba/Sentinel/wiki/如何使用#定義資源

註解支持

官網文檔:https://github.com/alibaba/Sentinel/wiki/註解支持

package com.example.service.impl;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.example.pojo.Product;
import com.example.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

/**
 * 商品管理
 */
@Service
public class ProductServiceImpl implements ProductService {

    @Autowired
    private RestTemplate restTemplate;

    /**
     * 根據主鍵查詢商品
     *
     * @param id
     * @return
     */
    @SentinelResource(value = "selectProductById",
            blockHandler = "selectProductByIdBlockHandler", fallback = "selectProductByIdFallback")
    @Override
    public Product selectProductById(Integer id) {
        return restTemplate.getForObject("http://product-service/product/" + id, Product.class);
    }

    // 服務流量控制處理,參數最後多一個 BlockException,其餘與原函數一致。
    public Product selectProductByIdBlockHandler(Integer id, BlockException ex) {
        // Do some log here.
        ex.printStackTrace();
        return new Product(id, "服務流量控制處理-託底數據", 1, 2666D);
    }

    // 服務熔斷降級處理,函數簽名與原函數一致或加一個 Throwable 類型的參數
    public Product selectProductByIdFallback(Integer id, Throwable throwable) {
        System.out.println("product-service 服務的 selectProductById 方法出現異常,異常信息如下:"
                + throwable);
        return new Product(id, "服務熔斷降級處理-託底數據", 1, 2666D);
    }

}

注意:註解方式埋點不支持 private 方法。

@SentinelResource 用於定義資源,並提供可選的異常處理和 fallback 配置項。 @SentinelResource 註解包含以下屬性:

  • value:資源名稱,必需項(不能爲空)
  • entryType:entry 類型,可選項(默認爲 EntryType.OUT
  • blockHandler / blockHandlerClass: blockHandler對應處理 BlockException 的函數名稱,可選項。blockHandler 函數訪問範圍需要是 public,返回類型需要與原方法相匹配,參數類型需要和原方法相匹配並且最後加一個額外的參數,類型爲 BlockException。blockHandler 函數默認需要和原方法在同一個類中。若希望使用其他類的函數,則可以指定 blockHandlerClass 爲對應的類的 Class 對象,注意對應的函數必需爲 static 函數,否則無法解析。
  • fallback:fallback 函數名稱,可選項,用於在拋出異常的時候提供 fallback 處理邏輯。fallback 函數可以針對所有類型的異常(除了 exceptionsToIgnore 裏面排除掉的異常類型)進行處理。fallback 函數簽名和位置要求:
    • 返回值類型必須與原函數返回值類型一致;
    • 方法參數列表需要和原函數一致,或者可以額外多一個 Throwable 類型的參數用於接收對應的異常。
    • fallback 函數默認需要和原方法在同一個類中。若希望使用其他類的函數,則可以指定 fallbackClass 爲對應的類的 Class 對象,注意對應的函數必需爲 static 函數,否則無法解析。
  • defaultFallback(since 1.6.0):默認的 fallback 函數名稱,可選項,通常用於通用的 fallback 邏輯(即可以用於很多服務或方法)。默認 fallback 函數可以針對所有類型的異常(除了 exceptionsToIgnore 裏面排除掉的異常類型)進行處理。若同時配置了 fallback 和 defaultFallback,則只有 fallback 會生效。defaultFallback 函數簽名要求:
    • 返回值類型必須與原函數返回值類型一致;
    • 方法參數列表需要爲空,或者可以額外多一個 Throwable 類型的參數用於接收對應的異常。
    • defaultFallback 函數默認需要和原方法在同一個類中。若希望使用其他類的函數,則可以指定 fallbackClass 爲對應的類的 Class 對象,注意對應的函數必需爲 static 函數,否則無法解析。
  • exceptionsToIgnore(since 1.6.0):用於指定哪些異常被排除掉,不會計入異常統計中,也不會進入 fallback 邏輯中,而是會原樣拋出。

注:1.6.0 之前的版本 fallback 函數只針對降級異常(DegradeException)進行處理,不能針對業務異常進行處理

特別地,若 blockHandler 和 fallback 都進行了配置,則被限流降級而拋出 BlockException 時只會進入 blockHandler 處理邏輯。若未配置 blockHandlerfallbackdefaultFallback,則被限流降級時會將 BlockException 直接拋出(若方法本身未定義 throws BlockException 則會被 JVM 包裝一層 UndeclaredThrowableException)。

從 1.4.0 版本開始,註解方式定義資源支持自動統計業務異常,無需手動調用 Tracer.trace(ex) 來記錄業務異常。Sentinel 1.4.0 以前的版本需要自行調用 Tracer.trace(ex) 來記錄業務異常。

定義規則

Sentinel 的所有規則都可以在內存態中動態地查詢及修改,修改之後立即生效。同時 Sentinel 也提供相關 API,供您來定製自己的規則策略。

Sentinel 支持以下幾種規則:流量控制規則熔斷降級規則系統保護規則來源訪問控制規則熱點參數規則

官網文檔:https://github.com/alibaba/Sentinel/wiki/如何使用#規則的種類

流量控制規則

點擊鏈接觀看:流量控制規則視頻(獲取更多請關注公衆號「哈嘍沃德先生」)

選擇 簇點鏈路 找到定義好的資源 selectProductById 並點擊對應的規則按鈕進行設置。

比如我們設置一個流量控制規則,定義資源訪問的 QPS 爲 1(每秒能處理查詢數目)。

測試

快速刷新頁面多次訪問:http://localhost:9090/order/1 結果如下:

熔斷降級規則

模擬服務出錯

修改 order-service-rest 項目中的核心代碼,模擬服務出錯。

package com.example.service.impl;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.example.pojo.Product;
import com.example.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

/**
 * 商品管理
 */
@Service
public class ProductServiceImpl implements ProductService {

    @Autowired
    private RestTemplate restTemplate;

    /**
     * 根據主鍵查詢商品
     *
     * @param id
     * @return
     */
    @SentinelResource(value = "selectProductById",
            blockHandler = "selectProductByIdBlockHandler", fallback = "selectProductByIdFallback")
    @Override
    public Product selectProductById(Integer id) {
        // 模擬查詢主鍵爲 1 的商品信息會導致異常
        if (1 == id)
            throw new RuntimeException("查詢主鍵爲 1 的商品信息導致異常");
        return restTemplate.getForObject("http://product-service/product/" + id, Product.class);
    }

    // 服務流量控制處理,參數最後多一個 BlockException,其餘與原函數一致。
    public Product selectProductByIdBlockHandler(Integer id, BlockException ex) {
        // Do some log here.
        ex.printStackTrace();
        return new Product(id, "服務流量控制處理-託底數據", 1, 2666D);
    }

    // 服務熔斷降級處理,函數簽名與原函數一致或加一個 Throwable 類型的參數
    public Product selectProductByIdFallback(Integer id, Throwable throwable) {
        System.out.println("product-service 服務的 selectProductById 方法出現異常,異常信息如下:"
                + throwable);
        return new Product(id, "服務熔斷降級處理-託底數據", 1, 2666D);
    }

}

熔斷降級規則支持相應時間、異常比例、異常數三種方式。

測試

訪問:http://localhost:9090/order/1 結果如下:

動態規則擴展

官網文檔:

SentinelProperties 內部提供了 TreeMap 類型的 datasource 屬性用於配置數據源信息。支持:

  • 文件配置規則
  • Nacos 配置規則
  • ZooKeeper 配置規則
  • Apollo 配置規則
  • Redis 配置規則

文件配置規則

Sentinel 支持通過本地文件加載規則配置,使用方式如下(限流規則作爲演示):

spring:
  cloud:
    sentinel:
      datasource:
        ds1:
          file:
            file: classpath:flowRule.json
            data-type: json
            rule-type: flow

flowRule.json 對應 com.alibaba.csp.sentinel.slots.block.RuleConstant 各屬性。

[
  {
    "resource": "selectProductList",
    "count": 1,
    "grade": 1,
    "limitApp": "default",
    "strategy": 0,
    "controlBehavior": 0
  }
]

重要屬性:

Field 說明 默認值
resource 資源名,資源名是限流規則的作用對象
count 限流閾值
grade 限流閾值類型,QPS 模式(1)或併發線程數模式(0) QPS 模式
limitApp 流控針對的調用來源 default,代表不區分調用來源
strategy 調用關係限流策略:直接、鏈路、關聯 根據資源本身(直接)
controlBehavior 流控效果(直接拒絕 / 排隊等待 / 慢啓動模式),不支持按調用關係限流 直接拒絕
clusterMode 是否集羣限流

訪問客戶端以後,刷新控制檯,查看流控規則如下:

RestTemplate 支持

Spring Cloud Alibaba Sentinel 支持對 RestTemplate 調用的服務進行服務保護。需要在構造 RestTemplate Bean 時添加 @SentinelRestTemplate 註解。

啓動類

OrderServiceRestApplication.java

package com.example;

import com.alibaba.cloud.sentinel.annotation.SentinelRestTemplate;
import com.example.exception.ExceptionUtil;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
public class OrderServiceRestApplication {

    @Bean
    @LoadBalanced
    @SentinelRestTemplate(blockHandler = "handleException", blockHandlerClass = ExceptionUtil.class,
            fallback = "fallback", fallbackClass = ExceptionUtil.class)
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

    public static void main(String[] args) {
        SpringApplication.run(OrderServiceRestApplication.class, args);
    }

}

服務熔斷處理類

ExceptionUtil.java 必須使用靜態方法。

package com.example.exception;

import com.alibaba.cloud.sentinel.rest.SentinelClientHttpResponse;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.fastjson.JSON;
import com.example.pojo.Product;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpResponse;

public class ExceptionUtil {

    // 服務流量控制處理
    public static ClientHttpResponse handleException(HttpRequest request,
                                                     byte[] body,
                                                     ClientHttpRequestExecution execution,
                                                     BlockException exception) {
        exception.printStackTrace();
        return new SentinelClientHttpResponse(
                JSON.toJSONString(new Product(1, "服務流量控制處理-託底數據", 1, 2666D)));
    }

    // 服務熔斷降級處理
    public static ClientHttpResponse fallback(HttpRequest request,
                                                    byte[] body,
                                                    ClientHttpRequestExecution execution,
                                                    BlockException exception) {
        exception.printStackTrace();
        return new SentinelClientHttpResponse(
                JSON.toJSONString(new Product(1, "服務熔斷降級處理-託底數據", 1, 2666D)));
    }

}

訪問

控制檯設置流量控制規則,定義資源訪問的 QPS 爲 1(每秒能處理查詢數目)。

快速刷新頁面多次訪問:http://localhost:9090/order/1 結果如下:

OpenFeign 支持

其實不管是 Hystrix 還是 Sentinel 對於 Feign 的支持,核心代碼基本上是一致的,只需要修改依賴和配置文件即可。

添加依賴

<!-- spring cloud openfeign 依賴 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- spring cloud alibaba sentinel 依賴 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

開啓 Sentinel

server:
  port: 9091 # 端口

spring:
  application:
    name: order-service-feign # 應用名稱
  cloud:
    sentinel:
      transport:
        port: 8719
        dashboard: localhost:8080

# 配置 Eureka Server 註冊中心
eureka:
  instance:
    prefer-ip-address: true       # 是否使用 ip 地址註冊
    instance-id: ${spring.cloud.client.ip-address}:${server.port} # ip:port
  client:
    service-url:                  # 設置服務註冊中心地址
      defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/

# feign 開啓 sentinel 支持
feign:
  sentinel:
    enabled: true

熔斷降級

ProductServiceFallback.java

package com.example.fallback;

import com.example.pojo.Product;
import com.example.service.ProductService;
import feign.hystrix.FallbackFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * 服務熔斷降級處理可以捕獲異常
 */
@Component
public class ProductServiceFallbackFactory implements FallbackFactory<ProductService> {

    // 獲取日誌,在需要捕獲異常的方法中進行處理
    Logger logger = LoggerFactory.getLogger(ProductServiceFallbackFactory.class);

    @Override
    public ProductService create(Throwable throwable) {
        return new ProductService() {
            @Override
            public Product selectProductById(Integer id) {
                logger.error("product-service 服務的 selectProductById 方法出現異常,異常信息如下:"
                        + throwable);
                return new Product(id, "託底數據", 1, 2666D);
            }
        };
    }

}

消費服務

ProductService.java

package com.example.service;

import com.example.fallback.ProductServiceFallbackFactory;
import com.example.pojo.Product;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

// 聲明需要調用的服務
@FeignClient(value = "product-service", fallbackFactory = ProductServiceFallbackFactory.class)
public interface ProductService {

    /**
     * 根據主鍵查詢商品
     *
     * @param id
     * @return
     */
    @GetMapping("/product/{id}")
    Product selectProductById(@PathVariable("id") Integer id);

}

OrderServiceImpl.java

package com.example.service.impl;

import com.example.pojo.Order;
import com.example.service.OrderService;
import com.example.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;

@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    private ProductService productService;

    /**
     * 根據主鍵查詢訂單
     *
     * @param id
     * @return
     */
    @Override
    public Order selectOrderById(Integer id) {
        return new Order(id, "order-001", "中國", 2666D,
                Arrays.asList(productService.selectProductById(1)));
    }

}

控制層

package com.example.controller;

import com.example.pojo.Order;
import com.example.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private OrderService orderService;

    /**
     * 根據主鍵查詢訂單
     *
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    public Order selectOrderById(@PathVariable("id") Integer id) {
        return orderService.selectOrderById(id);
    }

}

啓動類

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

// 開啓 FeignClients 註解
@EnableFeignClients
@SpringBootApplication
public class OrderServiceFeignApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderServiceFeignApplication.class, args);
    }

}

測試

控制檯信息如下:

添加流量控制規則,定義資源訪問的 QPS 爲 1(每秒能處理查詢數目)。

快速刷新頁面多次訪問:http://localhost:9091/order/1 結果如下:

或者關閉服務提供者,訪問:http://localhost:9091/order/1 結果如下:

至此 Sentinel 服務哨兵知識點就講解結束了。

本文采用 知識共享「署名-非商業性使用-禁止演繹 4.0 國際」許可協議

大家可以通過 分類 查看更多關於 Spring Cloud 的文章。


🤗 您的點贊轉發是對我最大的支持。

📢 掃碼關注 哈嘍沃德先生「文檔 + 視頻」每篇文章都配有專門視頻講解,學習更輕鬆噢 ~

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