流量控制服務降級神器之Sentinel
說到流量服務控制,那么肯定有很多人都不太了解這個內容,因為如果對服務要求不是那么嚴格的情況下,基本是不會使用到這個東西的,但是,如果想要通過多個維度來保護服務和維持系統穩定性的話,那么就一定離不開Sentinel。
什么是 Sentinel
Sentinel是阿里巴巴公司開源的面向分布式環境的輕量級流量控制框架。
Sentinel 主要是用來做什么的
Sentinel是以流量為切入點,通過多個維度來保護服務和維持系統穩定性的工具。
主要功能:
- 流量控制
- 熔斷降級
- 系統負載保護
我們來分別的看一下都是什么意思,首先這個流量控制,
什么是流量控制呢?
就比如說,我們的請求,堆積起來成批次的時候,就相當于是流量,當有大批的請求流量過來的時候,Sentinel就得起到一些作用了,它就相當于是一個調配器,將隨機的請求變成順序的請求,將不同格式的請求格式化為統一的格式的請求。
那么什么是熔斷降級呢?
實際上熔斷降級就是在調用鏈路中的某個資源出現了不穩定,最終會導致請求發生堆積,然后為了避免這種情況,就有了熔斷降級。
發生熔斷降級時,系統這時候所處的狀態可能為:
- 調用(響應)超時
- 異常比例升高
所以熔斷降級會進行處理,通過并發線程數進行限制,還有就是通過響應時間對資源進行降級。
那么過載保護又體現在哪些方面呢?
其實主要就是體現在系統資源占用比例過高,讓系統的入口流量和系統的負載達到一個平衡,保證系統在能力范圍之內處理最多的請求。
為什么使用 Sentinel
我們來看看這個 Sentinel 都有哪些優點,為什么這么人都使用呢?
我們都知道這個 Sentinel 是阿里開源的,甚至在雙十一大促的時候,也起到了關鍵性的作用。
比如其中的秒殺,集群流量控制,消息削峰填谷,所以第一個優點就出來了,
1.應用場景豐富。
如果你使用過 Sentinel ,那么一定登陸過 Sentinel 的后臺,它的后臺十分完善,服務流量的實時顯示,集群匯總的運行情況,都是非常完美的,所以第二個優點也有了。
2.完善的實時監控
第三個優點,其實其他很多的工具都是有的,那就開源,那么我們就來看看這個 Sentinel 在 Windows 下是如何使用的。
Sentinel 控制臺
畢竟我們剛才已經說了他有完善的實時監控了,而這個實時監控也能體現在我們的頁面上,那么他就是控制臺程序,我們直接來整一下。
1.下載 Windows 的安裝包
Windows下的jar
了不起已經把jar包已經下載下來了,接下來我們看看如何啟動,其實啟動jar包的方式那我都不需要說,肯定都知道,但是啟動 Sentinel 的 Jar 包也是需要有些參數的,比如如下需要你了解的參數。
- -Dserver.port:指定啟動的端口,默認8080
- -Dproject.name:指定本服務的名稱
- -Dcsp.sentinel.dashboard.server:指定sentinel控制臺的地址,用于將自己注冊進入實現監控自己
- -Dsentinel.dashboard.auth.username=sentinel 用于指定控制臺的登錄用戶名為 "sentinel",默認值為 “sentinel”
- -Dsentinel.dashboard.auth.password=123456 用于指定控制臺的登錄密碼為 "123456",默認值為 "sentinel"
- -Dserver.servlet.session.timeout=7200 用于指定 Spring Boot 服務端 session 的過期時間,如 7200 表示 7200 秒;60m 表示 60 分鐘,默認為 30 分鐘,需要注意的是,部署多臺控制臺時,session 默認不會在各實例之間共享,這一塊需要自行改造。
了解這么多也不錯了,然后我們來弄個比較簡單的啟動
我們直接用比較簡單的命令來啟動。
java -Dserver.port=9999 -Dcsp.sentinel.dashboard.server=localhost:9999 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.6.jar
默認賬號和密碼都是 sentinel
我們直接登陸,然后看到的就是他的控制面板了。
我們看到了控制臺,接下來我們就得去看看整合到項目中,是如何實現限流的。
Sentinel 整合入SpringBoot中
創建 SpringCloud的項目,了不起就不再說了,直接說怎么引入這個 Sentinel 吧。
依賴引入:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
其實往上還有很多博主說需要引入一些不如 actuator 的依賴,其實不需要,原因顯而易見,這和個包肯定是包含這些依賴的,比如::
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
<version>2.4.2</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator-autoconfigure</artifactId>
<version>2.4.2</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>2.4.2</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
在 spring-cloud-starter-alibaba-sentinel中實際上已經都引入過了,所以不需要再單獨的去引入依賴。
依賴引入了,接下來就得看看怎么配置這個配置文件
spring:
application:
name: xxxxx
cloud:
nacos:
config:
username: nacos
password: nacos
context-path: /nacos
server-addr: 127.0.0.1:8848
file-extension: yml
group: DEFAULT_GROUP
discovery:
username: nacos
password: nacos
server-addr: 127.0.0.1:8848
sentinel:
# sentinel看板的地址
transport:
dashboard: localhost:9999
# 開啟對sentinel看板的饑餓式加載。sentinel默認是懶加載機制,只有訪問過一次的資源才會被監控,通過關閉懶加載,在項目啟動時就連接sentinel控制臺
eager: true
了不起就截圖了一些內容,主要看sentinel 的配置就可以,
當我們啟動的時候,然后訪問一下swagger的文檔,
此時查看sentinel控制臺,將會看見這個服務已經被監控了。
Sentinel 限流使用方法
Sentinel 可以簡單分為 Sentinel 核心庫和 Dashboard,核心庫不依賴 Dashboard,但是結合 Dashboard 可以獲得更好的效果。使用 Sentinel 來進行資源保護,主要分為幾個步驟:
(1)定義資源:資源可以是程序中的任何內容,例如一個服務,服務里的方法,甚至是一段代碼。
(2)定義規則:Sentinel 支持以下幾種規則:流量控制規則、熔斷降級規則、系統保護規則、來源訪問控制規則 和 熱點參數規則。
(3)檢驗規則是否生效
由于 Sentinel 中所有的規則都可以在動態地查詢和修改,并且修改后立即生效,并且 Sentinel 中資源定義和規則的配置是分離的。因此在編碼時,我們先把需要保護的資源定義好(埋點),之后便可以在需要的時候動態配置規則了。也可以理解為,只要有了資源,我們就能在任何時候靈活地定義各種規則。
實現方式有兩種,第一種是通過硬編碼的方式,但是這種方式很少有人使用,侵入性太高了呀,改代碼還得改一堆東西,了不起就不說了,我們主要來說說這個使用注解的方式,這種方式方便而且還簡單。
@SentinelResource注解方式(推薦)
我們先看看注解源碼都寫了啥?
package com.alibaba.csp.sentinel.annotation;
import com.alibaba.csp.sentinel.EntryType;
import java.lang.annotation.*;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface SentinelResource {
/**
* @return name of the Sentinel resource
*/
String value() default "";
/**
* @return the entry type (inbound or outbound), outbound by default
*/
EntryType entryType() default EntryType.OUT;
/**
* @return the classification (type) of the resource
* @since 1.7.0
*/
int resourceType() default 0;
/**
* @return name of the block exception function, empty by default
*/
String blockHandler() default "";
/**
* The {@code blockHandler} is located in the same class with the original method by default.
* However, if some methods share the same signature and intend to set the same block handler,
* then users can set the class where the block handler exists. Note that the block handler method
* must be static.
*
* @return the class where the block handler exists, should not provide more than one classes
*/
Class<?>[] blockHandlerClass() default {};
/**
* @return name of the fallback function, empty by default
*/
String fallback() default "";
/**
* The {@code defaultFallback} is used as the default universal fallback method.
* It should not accept any parameters, and the return type should be compatible
* with the original method.
*
* @return name of the default fallback method, empty by default
* @since 1.6.0
*/
String defaultFallback() default "";
/**
* The {@code fallback} is located in the same class with the original method by default.
* However, if some methods share the same signature and intend to set the same fallback,
* then users can set the class where the fallback function exists. Note that the shared fallback method
* must be static.
*
* @return the class where the fallback method is located (only single class)
* @since 1.6.0
*/
Class<?>[] fallbackClass() default {};
/**
* @return the list of exception classes to trace, {@link Throwable} by default
* @since 1.5.1
*/
Class<? extends Throwable>[] exceptionsToTrace() default {Throwable.class};
/**
* Indicates the exceptions to be ignored. Note that {@code exceptionsToTrace} should
* not appear with {@code exceptionsToIgnore} at the same time, or {@code exceptionsToIgnore}
* will be of higher precedence.
*
* @return the list of exception classes to ignore, empty by default
* @since 1.6.0
*/
Class<? extends Throwable>[] exceptionsToIgnore() default {};
}
- value:資源名稱,必需項
- entryType:entry 類型,可選項(默認為 EntryType.OUT)
- blockHandler / blockHandlerClass:blockHandler 指定函數負責處理 BlockException 異常,可選項。blockHandler 函數默認需要和原方法在同一個類中,通過指定 blockHandlerClass 為對應類的 Class 對象,則可以指定其他類中的函數,但注意對應的函數必需為 static 函數,否則無法解析
- fallback /fallbackClass:fallback 指定的函數負責處理業務運行的異常,可選項,fallback 函數可以針對所有類型的異常(除了exceptionsToIgnore里面排除掉的異常類型)進行處理。
- defaultFallback(since 1.6.0):默認的 fallback 函數名稱,可選項,通常用于通用的 fallback 邏輯。defaultFallback 函數默認需要和原方法在同一個類中,通過指定 fallbackClass 為對應類的 Class 對象,則可以指定指定為其他類的函數,但注意對應的函數必需為 static 函數,否則無法解析。defaultFallback 函數可以針對所有類型的異常(除了 exceptionsToIgnore 里面排除掉的異常類型)進行處理。若同時配置了 fallback和 defaultFallback,則只有 fallback會生效。
- exceptionsToIgnore(since 1.6.0):用于指定哪些異常被排除掉,不會計入異常統計中,也不會進入 fallback 邏輯中,而是會原樣拋出。
其中不常用的可以了解就可以了,你說呢?