Sentinel流量防控卫兵
也可以直接按照官方的操作https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D
启动控制台
到官网下载jar包。
并在控制台启动,这里说明最好我们的控制台和客户端都在一个IP底下,不然会有很多其他繁杂的操作,而且我们的jdk需要时1.8的,不然控制台启动会报错。
下载好后利用控制台启动jar包,用我们的官方提供的命令java -jar sentinel-dashboard-1.6.3.jar。
启动成功
我们接入客户端
pom文件
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>1.6.3</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.6.3</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
<version>1.6.3</version>
</dependency>
</dependencies>
启动类
package com.bfxy.test;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.util.ArrayList;
import java.util.List;
@SpringBootApplication
public class Application {
public static void intDegradeRules() {
List<DegradeRule> rules = new ArrayList<DegradeRule>();
DegradeRule rule = new DegradeRule();
// 注意: 我们的规则一定要绑定到对应的资源上,通过资源名称进行绑定
rule.setResource("com.bfxy.test.web.IndexController:degrade");
rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
rule.setCount(2);
rules.add(rule);
// 规则管理器
DegradeRuleManager.loadRules(rules);
}
public static void intFlowRules() {
List<FlowRule> rules = new ArrayList<FlowRule>();
FlowRule rule = new FlowRule();
// 注意: 我们的规则一定要绑定到对应的资源上,通过资源名称进行绑定
rule.setResource("helloworld");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setCount(20);
rules.add(rule);
// 规则管理器
FlowRuleManager.loadRules(rules);
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
intFlowRules();
intDegradeRules();
System.err.println("规则加载完毕!");
}
}
Controller
package com.bfxy.test.web;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class IndexController {
@RequestMapping("/flow")
public String flow() throws InterruptedException {
Entry entry = null;
try {
// 2.1 定义资源名称
entry = SphU.entry("helloworld");
// 2.2 执行资源逻辑代码
System.err.println("helloworld: 访问数据库");
System.err.println("helloworld: 访问远程redis");
System.err.println("helloworld: 数据库持久化操作");
Thread.sleep(20);
} catch (BlockException e) {
System.err.println("要访问的资源被流控了, 执行流控逻辑!");
} finally {
if(entry != null) {
entry.exit();
}
}
return "flow";
}
private int count = 0;
@RequestMapping("/degrade")
public String degrade() throws Exception {
Entry entry = null;
try {
// resouceName:
String resouceName = "com.bfxy.test.web.IndexController:degrade";
// 2.1 定义资源名称
entry = SphU.entry(resouceName);
// 2.2 执行资源逻辑代码
count ++;
if(count % 2 == 0) {
Thread.sleep(100);
System.err.println("degrade--> 执行正常 100 ms ");
//throw new Exception("degrade--> 抛出异常");
} else {
Thread.sleep(20);
System.err.println("degrade--> 执行正常 20 ms ");
}
} catch (BlockException e) {
System.err.println("要访问的资源被降级了, 执行降级逻辑!");
} finally {
if(entry != null) {
entry.exit();
}
}
return "degrade";
}
}
启动时记得带上jvm参数
在我们的控制台可以添加各种各样的规则,helloworld为我们的代码中定义的资源名
利用@SentinelResource的低侵入方式
flow-service
package com.bfxy.test.service;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.stereotype.Service;
@Service
public class FlowService {
/**
* blockHandler: 流控降级的时候进入的兜底函数
* fallback: 抛出异常的时候进入的兜底函数
* (1.6.0 之前的版本 fallback 函数只针对降级异常(DegradeException)进行处理,不能针对业务异常进行处理)
* @return
*/
@SentinelResource(
value = "com.bfxy.test.service.FlowService:flow",
entryType = EntryType.OUT,
blockHandler = "flowBlockHandler",
fallback = "")
public String flow() {
System.err.println("----> 正常执行flow方法");
return "flow";
}
public String flowBlockHandler(BlockException ex) {
System.err.println("----> 触发 流控策略:" + ex);
return "执行 流控方法";
}
}
Controller
package com.bfxy.test.web;
import com.bfxy.test.service.DegradeService;
import com.bfxy.test.service.FlowService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SentinelAnnotationController {
@Autowired
private FlowService flowService;
@RequestMapping("/flow-test")
public String flowTest() {
return flowService.flow();
}
}
SentinelResourceAspect
package com.bfxy.test;
import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SentinelAspectConfiguration {
@Bean
public SentinelResourceAspect sentinelResourceAspect() {
return new SentinelResourceAspect();
}
}
启动类不需要加载任何规则。
利用postman发送一个请求,记得如果不先发送一个请求,控制台是无法获取信息的。
探讨blockHandler和fallback的区别
DegradeService
package com.bfxy.test.service;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.stereotype.Service;
import java.util.concurrent.atomic.AtomicInteger;
@Service
public class DegradeService {
private AtomicInteger count = new AtomicInteger(0);
/**
* blockHandler: 流控降级的时候进入的兜底函数
* fallback: 抛出异常的时候进入的兜底函数
* (1.6.0 之前的版本 fallback 函数只针对降级异常(DegradeException)进行处理,不能针对业务异常进行处理)
* @return
*/
@SentinelResource(
value = "com.bfxy.test.service.DegradeService:degrade",
entryType = EntryType.OUT,
blockHandler = "degradeBlockHandler",
fallback = "degradeFallback")
public String degrade() {
System.err.println("----> 正常执行degrade方法");
if(count.incrementAndGet() % 3 == 0) {
throw new RuntimeException("抛出业务异常");
}
return "degrade";
}
public String degradeBlockHandler(BlockException ex) {
System.err.println("----> 触发 降级流控策略:" + ex);
return "执行 降级流控方法";
}
public String degradeFallback(Throwable t) {
System.err.println("----> 触发 异常时的降级策略:" + t);
return "执行 异常降级方法";
}
}
Controller
package com.bfxy.test.web;
import com.bfxy.test.service.DegradeService;
import com.bfxy.test.service.FlowService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SentinelAnnotationController {
@Autowired
private DegradeService degradeService;
@RequestMapping("/degrade-test")
public String degradeTest() {
return degradeService.degrade();
}
}
这里利用控制台给这个资源添加一个流控规则:一秒以内不能超过一个请求。
开启postman测试,测试结果当我们的执行方法中手动抛出的异常他会降级到fallback指定的方法,当触发我们的流控规则时会降级到我们的blockHandler指定的方法。