Spring Cloud Alibaba Sentinel
Sentinel 介紹
隨着微服務的流行,服務和服務之間的穩定性變得越來越重要。 Sentinel 以流量爲切入點,從流量控制、熔斷降級、系統負載保護等多個維度保護服務的穩定性。
Sentinel 具有以下特徵:
- 豐富的應用場景: Sentinel 承接了阿里巴巴近 10 年的雙十一大促流量的核心場景,例如秒殺(即突發流量控制在系統容量可以承受的範圍)、消息削峯填谷、實時熔斷下游不可用應用等。
- 完備的實時監控: Sentinel 同時提供實時的監控功能。您可以在控制檯中看到接入應用的單臺機器秒級數據,甚至 500 臺以下規模的集羣的彙總運行情況。
- 廣泛的開源生態: Sentinel 提供開箱即用的與其它開源框架/庫的整合模塊,例如與 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相應的依賴並進行簡單的配置即可快速地接入 Sentinel。
- 完善的 SPI 擴展點: Sentinel 提供簡單易用、完善的 SPI 擴展點。您可以通過實現擴展點,快速的定製邏輯。例如定製規則管理、適配數據源等。
如何使用 Sentinel
如果要在您的項目中引入 Sentinel,使用 group ID 爲 com.alibaba.cloud 和 artifact ID 爲 spring-cloud-starter-alibaba-sentinel 的 starter。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
下面這個例子就是一個最簡單的使用 Sentinel 的例子:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(ServiceApplication.class, args);
}
}
@Service
public class TestService {
@SentinelResource(value = "sayHello")
public String sayHello(String name) {
return "Hello, " + name;
}
}
@RestController
public class TestController {
@Autowired
private TestService service;
@GetMapping(value = "/hello/{name}")
public String apiHello(@PathVariable String name) {
return service.sayHello(name);
}
}
@SentinelResource 註解用來標識資源是否被限流、降級。上述例子上該註解的屬性 sayHello 表示資源名。
@SentinelResource 還提供了其它額外的屬性如 blockHandler,blockHandlerClass,fallback 用於表示限流或降級的操作(注意有方法簽名要求),更多內容可以參考 Sentinel 註解支持文檔。若不配置 blockHandler、fallback 等函數,則被流控降級時方法會直接拋出對應的 BlockException;若方法未定義 throws BlockException 則會被 JVM 包裝一層 UndeclaredThrowableException。
注:一般推薦將 @SentinelResource 註解加到服務實現上,而在 Web 層直接使用 Spring Cloud Alibaba 自帶的 Web 埋點適配。Sentinel Web 適配同樣支持配置自定義流控處理邏輯,參考 相關文檔。
以上例子都是在 Web Servlet 環境下使用的。Sentinel 目前已經支持 Spring WebFlux,需要配合 spring-boot-starter-webflux 依賴觸發 sentinel-starter 中 WebFlux 相關的自動化配置。
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(ServiceApplication.class, args);
}
}
@RestController
public class TestController {
@GetMapping("/mono")
public Mono<String> mono() {
return Mono.just("simple string");
}
}
當 Spring WebFlux 應用接入 Sentinel starter 後,所有的 URL 就自動成爲 Sentinel 中的埋點資源,可以針對某個 URL 進行流控。
Sentinel 控制檯
Sentinel 控制檯提供一個輕量級的控制檯,它提供機器發現、單機資源實時監控、集羣資源彙總,以及規則管理的功能。您只需要對應用進行簡單的配置,就可以使用這些功能。
注意: 集羣資源彙總僅支持 500 臺以下的應用集羣,有大概 1 - 2 秒的延時。
Figure 1. Sentinel Dashboard
開啓該功能需要3個步驟:
獲取控制檯
您可以從 release 頁面 下載最新版本的控制檯 jar 包。
您也可以從最新版本的源碼自行構建 Sentinel 控制檯:
- 下載 控制檯 工程
- 使用以下命令將代碼打包成一個 fat jar: mvn clean package
啓動控制檯
Sentinel 控制檯是一個標準的 Spring Boot 應用,以 Spring Boot 的方式運行 jar 包即可。
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar
如若8080端口衝突,可使用 -Dserver.port=新端口 進行設置。
配置控制檯信息
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 FAQ
Feign 支持
Sentinel 適配了 Feign 組件。如果想使用,除了引入 spring-cloud-starter-alibaba-sentinel 的依賴外還需要 2 個步驟:
- 配置文件打開 Sentinel 對 Feign 的支持:feign.sentinel.enabled=true
- 加入 spring-cloud-starter-openfeign 依賴使 Sentinel starter 中的自動化配置類生效:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
這是一個 FeignClient 的簡單使用示例:
@FeignClient(name = "service-provider", fallback = EchoServiceFallback.class, configuration = FeignConfiguration.class)
public interface EchoService {
@RequestMapping(value = "/echo/{str}", method = RequestMethod.GET)
String echo(@PathVariable("str") String str);
}
class FeignConfiguration {
@Bean
public EchoServiceFallback echoServiceFallback() {
return new EchoServiceFallback();
}
}
class EchoServiceFallback implements EchoService {
@Override
public String echo(@PathVariable("str") String str) {
return "echo fallback";
}
}
Note |
Feign 對應的接口中的資源名策略定義:httpmethod:protocol://requesturl。@FeignClient註解中的所有屬性,Sentinel 都做了兼容。 |
EchoService 接口中方法 echo 對應的資源名爲 GET:http://service-provider/echo/{str}。
RestTemplate 支持
Spring Cloud Alibaba Sentinel 支持對 RestTemplate 的服務調用使用 Sentinel 進行保護,在構造 RestTemplate bean的時候需要加上 @SentinelRestTemplate 註解。
@Bean
@SentinelRestTemplate(blockHandler = "handleException", blockHandlerClass = ExceptionUtil.class)
public RestTemplate restTemplate() {
return new RestTemplate();
}
@SentinelRestTemplate 註解的屬性支持限流(blockHandler, blockHandlerClass)和降級(fallback, fallbackClass)的處理。
其中 blockHandler 或 fallback 屬性對應的方法必須是對應 blockHandlerClass 或 fallbackClass 屬性中的靜態方法。
該方法的參數跟返回值跟 org.springframework.http.client.ClientHttpRequestInterceptor#interceptor 方法一致,其中參數多出了一個 BlockException 參數用於獲取 Sentinel 捕獲的異常。
比如上述 @SentinelRestTemplate 註解中 ExceptionUtil 的 handleException 屬性對應的方法聲明如下:
public class ExceptionUtil {
public static ClientHttpResponse handleException(HttpRequest request, byte[] body, ClientHttpRequestExecution execution, BlockException exception) {
...
}
}
Note |
應用啓動的時候會檢查 @SentinelRestTemplate 註解對應的限流或降級方法是否存在,如不存在會拋出異常 |
@SentinelRestTemplate 註解的限流(blockHandler, blockHandlerClass)和降級(fallback, fallbackClass)屬性不強制填寫。
當使用 RestTemplate 調用被 Sentinel 熔斷後,會返回 RestTemplate request block by sentinel 信息,或者也可以編寫對應的方法自行處理返回信息。這裏提供了 SentinelClientHttpResponse 用於構造返回信息。
Sentinel RestTemplate 限流的資源規則提供兩種粒度:
- httpmethod:schema://host:port/path:協議、主機、端口和路徑
- httpmethod:schema://host:port:協議、主機和端口
Note |
以 https://www.taobao.com/test 這個 url 並使用 GET 方法爲例。對應的資源名有兩種粒度,分別是 GET:https://www.taobao.com 以及 GET:https://www.taobao.com/test |
動態數據源支持
SentinelProperties 內部提供了 TreeMap 類型的 datasource 屬性用於配置數據源信息。
比如配置 4 個數據源:
spring.cloud.sentinel.datasource.ds1.file.file=classpath: degraderule.json
spring.cloud.sentinel.datasource.ds1.file.rule-type=flow
#spring.cloud.sentinel.datasource.ds1.file.file=classpath: flowrule.json
#spring.cloud.sentinel.datasource.ds1.file.data-type=custom
#spring.cloud.sentinel.datasource.ds1.file.converter-class=com.alibaba.cloud.examples.JsonFlowRuleListConverter
#spring.cloud.sentinel.datasource.ds1.file.rule-type=flow
spring.cloud.sentinel.datasource.ds2.nacos.server-addr=localhost:8848
spring.cloud.sentinel.datasource.ds2.nacos.data-id=sentinel
spring.cloud.sentinel.datasource.ds2.nacos.group-id=DEFAULT_GROUP
spring.cloud.sentinel.datasource.ds2.nacos.data-type=json
spring.cloud.sentinel.datasource.ds2.nacos.rule-type=degrade
spring.cloud.sentinel.datasource.ds3.zk.path = /Sentinel-Demo/SYSTEM-CODE-DEMO-FLOW
spring.cloud.sentinel.datasource.ds3.zk.server-addr = localhost:2181
spring.cloud.sentinel.datasource.ds3.zk.rule-type=authority
spring.cloud.sentinel.datasource.ds4.apollo.namespace-name = application
spring.cloud.sentinel.datasource.ds4.apollo.flow-rules-key = sentinel
spring.cloud.sentinel.datasource.ds4.apollo.default-flow-rule-value = test
spring.cloud.sentinel.datasource.ds4.apollo.rule-type=param-flow
這種配置方式參考了 Spring Cloud Stream Binder 的配置,內部使用了 TreeMap 進行存儲,comparator 爲 String.CASE_INSENSITIVE_ORDER 。
Note |
d1, ds2, ds3, ds4 是 ReadableDataSource 的名字,可隨意編寫。後面的 file ,zk ,nacos , apollo 就是對應具體的數據源,它們後面的配置就是這些具體數據源各自的配置。注意數據源的依賴要單獨引入(比如 sentinel-datasource-nacos)。 |
每種數據源都有兩個共同的配置項: data-type、 converter-class 以及 rule-type。
data-type 配置項表示 Converter 類型,Spring Cloud Alibaba Sentinel 默認提供兩種內置的值,分別是 json 和 xml (不填默認是json)。 如果不想使用內置的 json 或 xml 這兩種 Converter,可以填寫 custom 表示自定義 Converter,然後再配置 converter-class 配置項,該配置項需要寫類的全路徑名(比如 spring.cloud.sentinel.datasource.ds1.file.converter-class=com.alibaba.cloud.examples.JsonFlowRuleListConverter)。
rule-type 配置表示該數據源中的規則屬於哪種類型的規則(flow,degrade,authority,system, param-flow, gw-flow, gw-api-group)。
Note |
當某個數據源規則信息加載失敗的情況下,不會影響應用的啓動,會在日誌中打印出錯誤信息。 |
Note |
默認情況下,xml 格式是不支持的。需要添加 jackson-dataformat-xml 依賴後纔會自動生效。 |
Note |
如果規則加載沒有生效,有可能是 jdk 版本導致的,請關注 759 issue 的處理。 |
關於 Sentinel 動態數據源的實現原理,參考: 動態規則擴展
Zuul 支持
若想跟 Sentinel Starter 配合使用,需要加上 spring-cloud-alibaba-sentinel-gateway 依賴,同時需要添加 spring-cloud-starter-netflix-zuul 依賴來讓 spring-cloud-alibaba-sentinel-gateway 模塊裏的 Zuul 自動化配置類生效:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
同時請將 spring.cloud.sentinel.filter.enabled 配置項置爲 false(若在網關流控控制檯上看到了 URL 資源,就是此配置項沒有置爲 false)。
Spring Cloud Gateway 支持
若想跟 Sentinel Starter 配合使用,需要加上 spring-cloud-alibaba-sentinel-gateway 依賴,同時需要添加 spring-cloud-starter-gateway 依賴來讓 spring-cloud-alibaba-sentinel-gateway 模塊裏的 Spring Cloud Gateway 自動化配置類生效:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
同時請將 spring.cloud.sentinel.filter.enabled 配置項置爲 false(若在網關流控控制檯上看到了 URL 資源,就是此配置項沒有置爲 false)。
Endpoint 支持
在使用 Endpoint 特性之前需要在 Maven 中添加 spring-boot-starter-actuator 依賴,並在配置中允許 Endpoints 的訪問。
- Spring Boot 1.x 中添加配置 management.security.enabled=false。暴露的 endpoint 路徑爲 /sentinel
- Spring Boot 2.x 中添加配置 management.endpoints.web.exposure.include=*。暴露的 endpoint 路徑爲 /actuator/sentinel
Sentinel Endpoint 裏暴露的信息非常有用。包括當前應用的所有規則信息、日誌目錄、當前實例的 IP,Sentinel Dashboard 地址,Block Page,應用與 Sentinel Dashboard 的心跳頻率等等信息。
配置
下表顯示當應用的 ApplicationContext 中存在對應的Bean的類型時,會進行自動化設置:
存在Bean的類型 |
操作 |
作用 |
UrlCleaner |
WebCallbackManager.setUrlCleaner(urlCleaner) |
資源清理(資源(比如將滿足 /foo/:id 的 URL 都歸到 /foo/* 資源下)) |
UrlBlockHandler |
WebCallbackManager.setUrlBlockHandler(urlBlockHandler) |
自定義限流處理邏輯 |
RequestOriginParser |
WebCallbackManager.setRequestOriginParser(requestOriginParser) |
設置來源信息 |
Spring Cloud Alibaba Sentinel 提供了這些配置選項:
配置項 |
含義 |
默認值 |
spring.application.name or project.name |
Sentinel項目名 |
|
spring.cloud.sentinel.enabled |
Sentinel自動化配置是否生效 |
true |
spring.cloud.sentinel.eager |
是否提前觸發 Sentinel 初始化 |
false |
spring.cloud.sentinel.transport.port |
應用與Sentinel控制檯交互的端口,應用本地會起一個該端口占用的HttpServer |
8719 |
spring.cloud.sentinel.transport.dashboard |
Sentinel 控制檯地址 |
|
spring.cloud.sentinel.transport.heartbeat-interval-ms |
應用與Sentinel控制檯的心跳間隔時間 |
|
spring.cloud.sentinel.transport.client-ip |
此配置的客戶端IP將被註冊到 Sentinel Server 端 |
|
spring.cloud.sentinel.filter.order |
Servlet Filter的加載順序。Starter內部會構造這個filter |
Integer.MIN_VALUE |
spring.cloud.sentinel.filter.url-patterns |
數據類型是數組。表示Servlet Filter的url pattern集合 |
/* |
spring.cloud.sentinel.filter.enabled |
Enable to instance CommonFilter |
true |
spring.cloud.sentinel.metric.charset |
metric文件字符集 |
UTF-8 |
spring.cloud.sentinel.metric.file-single-size |
Sentinel metric 單個文件的大小 |
|
spring.cloud.sentinel.metric.file-total-count |
Sentinel metric 總文件數量 |
|
spring.cloud.sentinel.log.dir |
Sentinel 日誌文件所在的目錄 |
|
spring.cloud.sentinel.log.switch-pid |
Sentinel 日誌文件名是否需要帶上 pid |
false |
spring.cloud.sentinel.servlet.block-page |
自定義的跳轉 URL,當請求被限流時會自動跳轉至設定好的 URL |
|
spring.cloud.sentinel.flow.cold-factor |
WarmUp 模式中的 冷啓動因子 |
3 |
spring.cloud.sentinel.zuul.order.pre |
SentinelZuulPreFilter 的 order |
10000 |
spring.cloud.sentinel.zuul.order.post |
SentinelZuulPostFilter 的 order |
1000 |
spring.cloud.sentinel.zuul.order.error |
SentinelZuulErrorFilter 的 order |
-1 |
spring.cloud.sentinel.scg.fallback.mode |
Spring Cloud Gateway 流控處理邏輯 (選擇 redirect or response) |
|
spring.cloud.sentinel.scg.fallback.redirect |
Spring Cloud Gateway 響應模式爲 'redirect' 模式對應的重定向 URL |
|
spring.cloud.sentinel.scg.fallback.response-body |
Spring Cloud Gateway 響應模式爲 'response' 模式對應的響應內容 |
|
spring.cloud.sentinel.scg.fallback.response-status |
Spring Cloud Gateway 響應模式爲 'response' 模式對應的響應碼 |
429 |
spring.cloud.sentinel.scg.fallback.content-type |
Spring Cloud Gateway 響應模式爲 'response' 模式對應的 content-type |
application/json |
Note |
請注意。這些配置只有在 Servlet 環境下才會生效,RestTemplate 和 Feign 針對這些配置都無法生效 |