雪崩效應
解決方案
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
賬号密碼皆為sentinel,啟動nacos,啟動provider子產品和consumer子產品,通路http://localhost:9090/index
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;
}
對參數num1進行限流
效果:
可以添加例外值:當傳的對應參數值等于例外值的時候,讀取的門檻值為例外設定門檻值
5、授權規則
給指定的資源設定流控應用(追加參數),可以對流控應用進行通路權限的設定,具體就是添加白名單和黑名單。
如何給請求指定流控應用,通過實作 RequestOriginParser 接口來完成,代碼如下所示。
package com.godfrey.configuration;
import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
/**
* @author godfrey
* @since 2020-12-26
*/
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.godfrey.configuration;
import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
/**
* @author godfrey
* @since 2020-12-26
*/
@Configuration
public class SentinelConfiguration {
@PostConstruct
public void init() {
WebCallbackManager.setRequestOriginParser(new RequestOriginParserDefinition());
}
}
6 自定義規則異常傳回
建立異常處理類
package com.godfrey.execption;
import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlBlockHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author godfrey
* @since 2020-12-26
*/
public class ExceptionHandler implements UrlBlockHandler {
@Override
public void blocked(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws IOException {
httpServletResponse.setContentType("text/html;charset=utf-8");
String msg = null;
if (e instanceof FlowException) {
msg = "限流";
} else if (e instanceof DegradeException) {
msg = "降級";
}
httpServletResponse.getWriter().write(msg);
}
}
進行配置。
@Configuration
public class SentinelConfiguration {
@PostConstruct
public void init2() {
WebCallbackManager.setUrlBlockHandler(new ExceptionHandler());
}
}