Sentinel 入門學習記錄

1.Sentinel是什麼?

隨着分佈式系統變得越來越流行,服務之間的可靠性變得比以往任何時候都更加重要。Sentinel是強大的流控制組件,以“流”爲切入點,涵蓋多個領域,包括流控制,併發限制,電路中斷和自適應系統保護,以確保微服務的可靠性。
一句話講就是Spring Cloud Alibaba用來替換之前的Hystrix的技術。

2.有什麼用?

用來做系統流量控制、熔斷降級、系統的負載保護等。
在這裏插入圖片描述

3.下載並啓動Sentinel

1.下載地址
2.啓動

java -jar sentinel-dashboard-1.7.2.jar

3.訪問Dashboard,用戶名密碼都是sentinel
在這裏插入圖片描述

4.測試準備

1.新建一個springboot項目
2.引入依賴

<dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--     sentinel-datasource-nacos 後續持久化用   -->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

3.啓動類添加註解@EnableDiscoveryClient

@SpringBootApplication
@EnableDiscoveryClient
public class AlibabaSentinelServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(AlibabaSentinelServiceApplication.class, args);
    }
}

4.application.properties配置

server.port=8401

spring.application.name=cloudalibaba-sentinel-service
spring.cloud.nacos.discovery.server-addr=localhost:8848
spring.cloud.sentinel.transport.dashboard=localhost:8080
spring.cloud.sentinel.transport.port=8719
spring.cloud.sentinel.datasource.dsl.nacos.server-addr=localhost:8848
spring.cloud.sentinel.datasource.dsl.nacos.data-id=${spring.application.name}
spring.cloud.sentinel.datasource.dsl.nacos.group-id=DEFAULT_GROUP
spring.cloud.sentinel.datasource.dsl.nacos.data-type=json
spring.cloud.sentinel.datasource.dsl.nacos.rule-type.=flow

management.endpoints.web.exposure.include=*

5.提供測試接口

@RestController
public class FlowLimitController {

    private static Logger log = LoggerFactory.getLogger(FlowLimitController.class);

    @GetMapping("/testA")
    public String testA(){
//        try {
//            TimeUnit.MILLISECONDS.sleep(800);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
        return "testA-----";
    }

    @GetMapping("/testB")
    public String testB(){
        log.info(Thread.currentThread().getName() + "...testB ");
        return "testB   -----";
    }
    }

6.啓動sentinelnacos
不懂nacos可以參考

5.測試流控規則

在這裏插入圖片描述

  • 資源名:唯一名稱,默認請求路徑
  • 針對來源:Sentinel可以針對調用者進行限流,填寫微服務名,默認default(不區分來源)
  • 閾值類型/單機閾值
    • QPS(每秒鐘的請求數量):當調用該api的QPS達到閾值的時候,進行限流
    • 線程數:當調用該api的線程數達到閾值的時候,進行限流
  • 流控模式
    • 直接:api達到限流條件時,直接限流
    • 關聯:當關聯的資源達到閾值時就限流自己。
      A接口與B接口關聯,當B接口到達閾值,讓A接口限流起到保護B接口的作用。 例如支付接口與下單接口,當支付接口到達閾值,讓下單接口限流,起到保護支付接口的作用。
    • 鏈路:只記錄指定鏈路上的流量(指定資源入口資源進來的流量,如果達到閾值,就進行限流)
  • 流控效果
    • 快速失敗:直接失敗拋異常
    • Warm up:根據codeFactor(冷加載因子,默認3)的值,從閾值/codeFactor,經過預熱時長,才達到設置的QPS閾值。
      一般用於類似秒殺的功能。
    • 排隊等候:勻速排隊,讓請求以勻速的速度通過,閾值類型必須設置爲QPS,否則無效。

5.1測試QPS到達閾值

配置如下:
在這裏插入圖片描述
當你連續點擊看到如下限流提示(1s請求數量超過配置閾值)
在這裏插入圖片描述

5.2測試線程數到達閾值

配置如下:
在這裏插入圖片描述
爲了方便測試讓每個被調用的方法睡眠一會

@GetMapping("/testA")
    public String testA(){
        //測試線程閾值
        try {
            TimeUnit.MILLISECONDS.sleep(800);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "testA-----";
    }

當你連續點擊看到如下限流提示(1s請求數量超過配置閾值)
在這裏插入圖片描述

5.3測試關聯限流

配置如下
在這裏插入圖片描述
用postman模擬與/testA關聯的/testB到達閾值
在這裏插入圖片描述
postman啓動之後調用/testA可以看到該接口被限流。

5.4測試Warm up(限流冷啓動)

配置如下(訪問流量忽然增大時,從閾值/冷加載因子 開始經過預熱時長達到每秒可訪問閾值,即從流量增大時剛開始可以支持每秒2次訪問,經過3s可以支持每秒6次訪問接口),默認冷加載因子(coldFactor)爲3
在這裏插入圖片描述
可以點擊訪問/testA接口測試,開始慢慢慢點擊沒問題,然後加快速度會出現限流,過一會之後,限流就沒有了。

5.5.排隊等候

配置如下
在這裏插入圖片描述
爲了方便查看調用,接口中打印線程名稱

@GetMapping("/testB")
    public String testB(){
        log.info(Thread.currentThread().getName() + "...testB ");
        return "testB   -----";
    }

重啓項目調用,可以在控制檯中看到調用記錄
在這裏插入圖片描述

6.測試降級規則

官方文檔

  • RT:
    • 當資源的平均響應時間超過閾值(這裏閾值即自己配置的毫秒值)且在時間窗口內通過的請求>= 5,兩個條件同時滿足觸發熔斷降級
    • 窗口期後關閉斷路器。
    • RT最大4900(更大通過 -Dcsp.sentinel.statistic.max.rt=xxx 來配置)
  • 異常比例:
    QPS>=5且異常比例(秒級統計)超過閾值時,觸發降級;時間窗口結束後,關閉降級。
  • 異常數:
    異常數(分鐘統計)超過閾值,觸發降級;時間窗口結束後,關閉降級

Sentienl熔斷降級會在調用調用鏈路中某個資源出現不穩定時(例如調用超時或異常比例升高),對這個資源的調用進行限制,讓請求快速失敗,避免影響到其他的資源而導致級聯錯誤。
當資源降級後,在接下來的降級時間窗口之內,對該資源的調用自動熔斷(默認行爲是拋出DegradeException)


6.1測試RT

1.添加測試接口

@GetMapping("/testD")
    public String testD(){
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("testD 測試RT");
        return "testD -----";
    }

爲了讓平均響應時間增大,在代碼中加入sleep休眠。
2.利用JMater進行壓力測試
1s 10個線程訪問/testD接口
在這裏插入圖片描述
在這裏插入圖片描述
3.配置如下
在這裏插入圖片描述
4.啓動JMeter,自己調用/testD,可以看到該接口已被熔斷降級。
在這裏插入圖片描述
熔斷分析:1.平均響應時間(1000ms)超出閾值(200ms) 2.在時間窗口內通過請求10*5=50>=5。滿足兩個條件,所以發生熔斷降級

6.2測試異常比例

資源每秒請求量>=5&&每秒異常總數佔通過量的比值超過閾值之後,資源進入降級狀態,即在接下的時間窗口之內,對這個方法的調用都會自動的返回(服務熔斷)。異常比率閾值範圍[0.0,1.0],代表0%-100%。

1.提供測試異常比例接口

@GetMapping("/testException")
    public String testException(){
        log.info("testException 異常比例");
        int age = 10 /0 ;
        return "testException -----";
    }

2.利用JMater進行壓力測試,除接口外其他配置同上面測試RT
在這裏插入圖片描述
3.sentinel配置
在這裏插入圖片描述
4.重啓項目並啓動JMeter進行測試,調用/testException可以服務熔斷提示信息
在這裏插入圖片描述
在這裏插入圖片描述

6.3測試異常數

當資源近 1 分鐘的異常數目超過閾值之後會進行熔斷。注意由於統計時間窗口是分鐘級別的,若時間窗口小於60s,則結束熔斷狀態後可能再進入熔斷狀態。

1.提供測試接口

 @GetMapping("/testExceptionCount")
    public String testExceptionCount(){
        log.info("testExceptionCount 異常數");
        int age = 10 /0 ;
        return "testExceptionCount -----";
    }

2.sentinel配置
在這裏插入圖片描述
3.重啓項目進行測試
前面5次訪問都報錯,後面訪問進入熔斷後降級。
在這裏插入圖片描述
熔斷後降級如下圖
在這裏插入圖片描述

7.熱點參數限流

在這裏插入圖片描述

7.1普通熱點參數限流

1.提供接口進行測試

	@GetMapping("/testHotKey")
    @SentinelResource(value = "testHotKey", blockHandler = "dealTestHotKey")
    public String testHotKey(@RequestParam(value = "p1", required = false) String p1,
                             @RequestParam(value = "p2", required = false) String p2){
        return "testHotKey -----";
    }

    public String dealTestHotKey(String p1, String p2, BlockException blockException){
        return "dealTestHotKey---------";
    }

2.sentinel配置
在這裏插入圖片描述
上面的配置第一個參數p1,當QPS超過1秒1次點擊後馬上被限流。
3.重啓項目測試
在這裏插入圖片描述

7.2參數例外項熱點限流

1.sentinel配置如下
在這裏插入圖片描述
以上配置含義,當第一個參數p1的值爲5時接口/testHotKey的流量閾值爲200

注意:

@SentinelResource處理的是控制檯配置的違規情況,有blockHandler方法配置的兜底處理。
但是@SentinelResource不管代碼中出現的運行時期異常(RuntimeException)

在這裏插入圖片描述

8.@SentinelResource配置

8.1按資源名稱或URL地址限流加後續處理

1.提供接口

    /**
     * (違反sentinel配置)手動配置兜底處理blockHandler
     * @return
     */
    @GetMapping(value = "/byResource")
    @SentinelResource(value = "byResource", blockHandler = "handleException")
    public CommonResult byResource(){
        return new CommonResult(200, "按資源名稱限流測試OK");
    }

    public CommonResult handleException(BlockException blockException){
        return new CommonResult<>(444, blockException.getClass().getCanonicalName()+"\t服務不可用" );
    }


    /**
     * 默認處理
     * @return
     */
    @GetMapping("/rateLimit/byUrl")
    @SentinelResource(value = "byUrl")
    public CommonResult byUrl(){
        return new CommonResult(200, "by url限流測試OK");
    }
 

2.sentinel配置
資源名稱:
在這裏插入圖片描述
url:
在這裏插入圖片描述

3.重新啓動測試
訪問byResource當每秒訪問超過1次時,使用自定義的兜底處理。
在這裏插入圖片描述
訪問/rateLimit/byUrl當每秒訪問超過1次時,使用默認處理。
在這裏插入圖片描述


以上配置存在問題:

  • 1.系統默認的,沒有體現我們自己的業務需求
  • 2.依照現有條件,我們自定義的處理方法和業務代碼耦合在一塊,不直觀
  • 3.每個業務方法都有一個兜底的,代碼膨脹加劇
  • 4.全局同一處理方法沒有體現

8.1解決存在的問題

1.提供接口

public class CustomerBlockHandler {

    public static CommonResult handlerException(BlockException exception) {
        return new CommonResult(444, "客戶自定義,global handlerException---1");
    }

    public static CommonResult handlerException2(BlockException exception) {
        return new CommonResult(444, "客戶自定義,global handlerException---2");
    }
}

 @GetMapping("/rateLimit/customerBlockHandler")
    @SentinelResource(value = "customerBlockHandler",
                    blockHandlerClass = CustomerBlockHandler.class, blockHandler = "handlerException2")
    public CommonResult customerBlockHandler(){
        return new CommonResult(200, "客戶自定義 限流測試OK");
    }

2.sentinel中配置
在這裏插入圖片描述
3.重啓測試

9.整合Ribbon和OpenFeign

9.1準備

1.創建三個springboot項目,分別爲alibaba-consumer2、alibaba-provider3、alibaba-provider4(alibaba-provider3/alibaba-provider4一樣)
由於東西過多這裏不羅列,詳細參考https://github.com/xiaoxiaoshou/springclouddemo

9.2Ribbon系列

主要示例代碼:

@RestController
@Slf4j
@RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public class CircleBreakerController {
    private static final String SERVICE_URL = "http://nacos-payment-provider";

    @Resource
    private RestTemplate restTemplate;

    @RequestMapping("/consumer/fallback/{id}")
 //    @SentinelResource(value = "fallback") //沒有配置
//    @SentinelResource(value = "fallback",fallback = "handlerFallback") //配置了fallback的,fallback只負責業務異常
//    @SentinelResource(value = "fallback",blockHandler = "blockHandler") // 配置了blockHandler,只負責sentinel控制檯配置違規
   @SentinelResource(value = "fallback",fallback = "handlerFallback", blockHandler = "blockHandler") // 配置了blockHandler和fallback
 //   @SentinelResource(value = "fallback",fallback = "handlerFallback", blockHandler = "blockHandler", exceptionsToIgnore = {IllegalArgumentException.class}) // 忽略運行時IllegalArgumentException異常不進行自定義處理
    public CommonResult<Payment> fallback(@PathVariable("id") Long id){
        CommonResult<Payment> commonResult = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/" + id, CommonResult.class);
        if(id == 4){
            throw new IllegalArgumentException("IllegalArgumentException,非法參數異常");
        }else if(commonResult.getData() == null){
            throw new NullPointerException("NullPointerException,該ID沒有記錄,空指針異常");
        }
        return commonResult;
    }
    // 本例是fallback
    public CommonResult handlerFallback(Long id, Throwable e){
        Payment payment = new Payment(id, null);
        return new CommonResult(444, "兜底異常handler,exception內容"+e.getMessage(), payment);
    }

    public CommonResult blockHandler(Long id, BlockException exception){
        Payment payment = new Payment(id, null);
        return new CommonResult<>(445, "blockHandler-sentinel 限流,無此流水號:blockException" + exception.getMessage(), payment);
    }
}
  • fallback對應方法(handlerFallback方法)處理代碼運行時期異常
  • blockHandler對應方法(blockHandler)處理Sentinel中違規
  • exceptionsToIgnore忽略運行時期某個異常不進行自定義處理

配置Sentinel(對資源fallback閾值爲1)並啓動項目測試,可以看到既可以處理調用過程中對應Sentinel違規也可以處理運行時期異常。

9.3 OpenFeign系列

1.主要配置

#激活sentinel對feign的支持
feign:
  sentinel:
    enabled: true

2.綁定對應服務

@FeignClient(value = "nacos-payment-provider", fallback = PaymentFallbackService.class)
public interface PaymentService {

    @GetMapping("/paymentSQL/{id}")
    CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
}

@Component
public class PaymentFallbackService implements PaymentService {
    @Override
    public CommonResult<Payment> paymentSQL(Long id) {
        return new CommonResult<>(444, "fallback");
    }
}

3.提供訪問接口

    @Resource
    private PaymentService paymentService;

    @GetMapping("/consumer/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id){
        return paymentService.paymentSQL(id);
    }

4.重啓項目即可衝過consumer接口調用第三方接口


各熔斷器的比較:
在這裏插入圖片描述

10.規則持久化

當你每次重啓對應服務,你會發現在Sentinel中配置對應的規則就沒有了,在生產環境中我們需要配置規則的持久化(持久化工具都可以,官方推薦Nacos)。

1.引入依賴

  <!--     sentinel-datasource-nacos 後續持久化用   -->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>

2.配置文件配置

spring.cloud.sentinel.datasource.dsl.nacos.server-addr=localhost:8848
spring.cloud.sentinel.datasource.dsl.nacos.data-id=${spring.application.name}
spring.cloud.sentinel.datasource.dsl.nacos.group-id=DEFAULT_GROUP
spring.cloud.sentinel.datasource.dsl.nacos.data-type=json
spring.cloud.sentinel.datasource.dsl.nacos.rule-type=flow

3.在nacos中配置

[
	{
	"resource":"/rateLimit/byUrl",
	"limitApp":"default",
	"grade":1,
	"count":1,
	"strategy":0,
	"controlBehavior":0,
	"clusterMode":false
	}
]

在這裏插入圖片描述
配置項含義:

  • resource:資源名稱
  • limitApp:來源應用
  • grade:閾值類型,0表示線程數,1表示QPS
  • count:單機閾值
  • strategy:流控模式,0表示直接,1表示級聯,2表示鏈路
  • controlBehavior:流控效果,0表示快速失敗,1表示Warm Up,2表示排隊等候
  • clusterMode:是否集羣
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章