Spring Cloud Alibaba 04:Sentinel 服務限流降級
雪崩效應
解決方案
1、設定執行緒超時
2、設定限流
3、熔斷器 Sentinel、Hystrix
1、pom.xml 引入依賴
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
2、application 配置
# actuator暴露所有端點
management:
endpoints:
web:
exposure:
include: '*'
# 與Sentinel DashBoard互動地址
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8080
3、下載 Sentinel 控制檯:https://github.com/alibaba/Sentinel/releases,啟動:java -jar sentinel-dashboard-1.8.0.jar
1、流控規則
直接限流:直接對關聯的url資源限流
開啟sentinel,開啟provider服務
對/index資源做流控,設定QPS為1(表示一秒鐘只允許訪問一次)
當訪問一秒鐘訪問http://localhost:8001/index超過一次時,會限制顯示被流控限制阻塞
關聯限流:當被訪問的url資源超過設定的閾值,限流關聯的資源
controller新增list方法:
@GetMapping("/list") public String list() { return "list"; }
新增測試依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
需要同時範文資源才能看到效果,測試類對http://localhost:8001/index訪問
@Test
@DisplayName("測試關聯流控模式")
void test1() throws InterruptedException {
RestTemplate restTemplate = new RestTemplate();
for (int i = 0; i < 100; ++i) {
restTemplate.getForObject("http://localhost:8081/index", String.class);
System.out.println("provider==>/index=======>" + i);
//休眠200毫秒
TimeUnit.MILLISECONDS.sleep(200);
}
}
啟動provider程式,設定流控規則如下:
設定完流控規則後啟動測試程式,瀏覽器訪問http://localhost:8001/list則出現以下情況,表示對index訪問超過閾值,則關聯資源list限流
鏈路限流:對更深層次資源限流(不僅僅侷限於controller)
1、pom.xml 新增依賴
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-web-servlet</artifactId>
</dependency>
2、application.yml
spring:
cloud:
sentinel:
filter:
enabled: false
3、寫配置類
package com.godfrey.configuration;
import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.servlet.Filter;
/**
* @author godfrey
* @since 2020-12-07
*/
@Configuration
public class FilterConfiguration {
@Bean
public FilterRegistrationBean<Filter> registrationBean() {
FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new CommonFilter());
registrationBean.addUrlPatterns("/*");
registrationBean.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "false");
registrationBean.setName("sentinelFilter");
return registrationBean;
}
}
4、Service
@Service
public class ProviderService {
@SentinelResource("test") //test 保護資源名
public void test() {
System.out.println("test");
}
}
5、Controller
private final ProviderService providerService;
@Autowired
public ProviderController(ProviderService providerService) {
this.providerService = providerService;
}
@GetMapping("/test1")
public String test1() {
this.providerService.test();
return "test1";
}
@GetMapping("/test2")
public String test2() {
this.providerService.test();
return "test2";
}
為了對比,test1做鏈路限流,對test2不做限流,設定如下
一秒鐘訪問http://localhost:8081/test1超過一次時,會對service繫結資源限流
訪問http://localhost:8081/test2則不會
2、流控效果
快速失敗
直接丟擲異常
Warm UP
給系統一個預熱的時間,預熱時間段內單機閾值較低,預熱時間過後單機閾值增加,預熱時間內當前的單機閾值是設定的閾值的三分之一,預熱時間過後單機閾值恢復設定的值。
排隊等待
當請求呼叫失敗之後,不會立即丟擲異常,等待下一次呼叫,時間範圍是超時時間,在時間範圍內如果請求則丟擲異常。閥值型別必須設成QPS,否則無效
3、降級規則
RT
單個請求的響應時間超過閾值,則進入準降級狀態,接下來 1 S 內連續 5 個請求響應時間均超過閾值,就進行降級,持續時間為時間視窗的值。
異常比例
每秒異常數量佔通過量的比例大於閾值,就進行降級處理,持續時間為時間視窗的值。
異常數
1 分鐘內的異常數超過閾值就進行降級處理,時間視窗的值要大於 60S,否則剛結束熔斷又進入下一次熔斷了。
4、熱點規則
熱點規則是流控規則的更細粒度操作,可以具體到對某個熱點引數的限流,設定限流之後,如果帶著限流引數的請求量超過閾值,則進行限流,時間為統計視窗時長。
必須要新增 @SentinelResource,即對資源進行流控。
@GetMapping("/hot")
@SentinelResource("hot")
public String hot(
@RequestParam(value = "num1",required = false) Integer num1,
@RequestParam(value = "num2",required = false) Integer num2){
return num1+"-"+num2;
}
5、授權規則
給指定的資源設定流控應用(追加引數),可以對流控應用進行訪問許可權的設定,具體就是新增白名單和黑名單。
如何給請求指定流控應用,通過實現 RequestOriginParser 介面來完成,程式碼如下所示。
package com.southwind.configuration;
import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
public class RequestOriginParserDefinition implements RequestOriginParser {
@Override
public String parseOrigin(HttpServletRequest httpServletRequest) {
String name = httpServletRequest.getParameter("name");
if(StringUtils.isEmpty(name)){
throw new RuntimeException("name is null");
}
return name;
}
}
要讓 RequestOriginParserDefinition 生效,需要在配置類中進行配置。
package com.southwind.configuration;
import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
@Configuration
public class SentinelConfiguration {
@PostConstruct
public void init(){
WebCallbackManager.setRequestOriginParser(new RequestOriginParserDefinition());
}
}