随着微服务的流行,服务和服务之间的稳定性变得越来越重要。 Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
Sentinel具有如下特性:
Sentinel包括服务端和客户端,服务端有可视化界面,客户端需引入jar后即可和服务端通信并完成限流功能。
下载
从官网下载Sentinel,下载地址:https://github.com/alibaba/Sentinel/releases, 这里下载的是sentinel-dashboard-1.6.3.jar文件
启动
通过命令启动sentinel服务端:java -jar sentinel-dashboard-1.6.3.jar,默认启动8080端口。启动成功之后,通过如下地址可以进行访问:http://localhost:8080,默认登录账号密码均为sentinel。
此时因为我们并没有启动客户端,所以界面是空的。
客户端接入,这里分两种方式,一种是基于Spring Cloud的方式接入,另外一种是基于原生客户端的方式接入。
####Spring Cloud接入
首先,maven中引入:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>0.9.0.RELEASE</version>
</dependency>
然后,在yml配置文件里面,配置服务端地址:
spring:
application:
name: sentinel
cloud:
sentinel:
transport:
dashboard: localhost:8080
heartbeat-interval-ms:500
eager:true
接着,编写测试用例:
@RestController
public class HelloController {
@GetMapping(value = "/hello")
@SentinelResource("hello")
public String hello() {
return "Hello,Sentinel";
}
}
SentinelResource注解里的值是资源标识符,可以为这个资源标识符指定限流,熔断规则等,在浏览器里请求这个地址,然后查看sentinel控制台:
首先,maven中引入:
<properties>
<java.version>1.8</java.version>
<sentinel.version>1.6.3</sentinel.version>
</properties>
<!-- 适配dubbo -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-dubbo-adapter</artifactId>
<version>${sentinel.version}</version>
</dependency>
<!-- 开启注解 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
<version>${sentinel.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-core</artifactId>
<version>${sentinel.version}</version>
</dependency>
<!-- 客户端需要引入 Transport 模块来与 Sentinel 控制台进行通信 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>${sentinel.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-parameter-flow-control</artifactId>
<version>${sentinel.version}</version>
</dependency>
接着就是连接到服务端:
@SpringBootApplication
public class SpringbootSentinelApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringbootSentinelApplication.class, args);
// 连接到控制台,与sentinel控制台通信
System.setProperty("project.name",
context.getEnvironment().getProperty("spring.application.name","sentinel"));
System.setProperty("csp.sentinel.dashboard.server",
context.getEnvironment().getProperty("sentinel.dashboard.server","localhost:8080"));
InitExecutor.doInit();
}
}
或者通过启动命令:-Dcsp.sentinel.dashboard.server=localhost:8080 连接到服务端
要使用SentinelResource注解,需要先初始化:
@Configuration
public class SentinelConfig {
@Bean
public SentinelResourceAspect sentinelResourceAspect() {
return new SentinelResourceAspect();
}
//@PostConstruct
private void initFlowRules() {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setResource("sayHello");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setCount(2);
rules.add(rule);
FlowRuleManager.loadRules(rules);
//降级规则,可以多个degradeRule rule
//DegradeRuleManager.getRules()可以获取到已经设置的降级规则
List<DegradeRule> degradeRules = new ArrayList<>();
DegradeRule degradeRule = new DegradeRule();
//设置资源名称,sentinel降级都是以资源为单位进行
degradeRule.setResource("circuitBreaker");
//使用异常统计降级,分钟统计,滑动时间窗口
degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
//异常数达到的数量阈值
degradeRule.setCount(2);
//秒级时间窗口,该值必须有且必须大于零,否则降级将无法生效
degradeRule.setTimeWindow(1);
degradeRules.add(degradeRule);
//重新加载限流规则,此处将覆盖原有的限流,所以如果想要不覆盖
//请使用DegradeRuleManager.getRules()获取到的加入到rules中
DegradeRuleManager.loadRules(degradeRules);
}
}
接下来就是编写测试用例:
@Service
public class HelloService {
/**
* 限流降级
* @return
*/
@SentinelResource(value = "sayHello", blockHandler = "sayHelloExceptionHandler")
public String sayHello(String name){
return "hello,"+ name;
}
/**
* 熔断降级
* @return
*/
@SentinelResource(value = "circuitBreaker", fallback = "circuitBreakerFallback", blockHandler = "sayHelloExceptionHandler")
public String circuitBreaker(String name){
if ("zhangsan".equals(name)){
return "hello,"+ name;
}
throw new RuntimeException("发生异常");
}
public String circuitBreakerFallback(String name){
return "服务异常,熔断降级, 请稍后重试!";
}
public String sayHelloExceptionHandler(String name, BlockException ex){
return "访问过快,限流降级, 请稍后重试!";
}
}
1.手工使用
先初始化流控规则,或者在sentinel控制台指定限流规则:
@Configuration
public class SentinelConfig {
@PostConstruct
private void initFlowRules() {
List<FlowRule> rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setResource("hello");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setCount(2);
rules.add(rule);
FlowRuleManager.loadRules(rules);
//降级规则,可以多个degradeRule rule
//DegradeRuleManager.getRules()可以获取到已经设置的降级规则
List<DegradeRule> degradeRules = new ArrayList<>();
DegradeRule degradeRule = new DegradeRule();
//设置资源名称,sentinel降级都是以资源为单位进行
degradeRule.setResource("circuitBreaker");
//使用异常统计降级,分钟统计,滑动时间窗口
degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
//异常数达到的数量阈值
degradeRule.setCount(2);
//秒级时间窗口,该值必须有且必须大于零,否则降级将无法生效
degradeRule.setTimeWindow(1);
degradeRules.add(degradeRule);
//重新加载限流规则,此处将覆盖原有的限流,所以如果想要不覆盖
//请使用DegradeRuleManager.getRules()获取到的加入到rules中
DegradeRuleManager.loadRules(degradeRules);
}
}
@RequestMapping(value = "/hello")
public String hello() {
Entry entry = null;
try {
entry = SphU.entry("hello");
return "hello,sentinel!";
} catch (BlockException e) {
return "block...";
} finally {
if(entry!=null){
entry.exit();
}
}
}
使用apache ab工具,ab -c 10 -n 100 http://localhost:8080/hello, 可以看到会出现blocking…, 因为超出阈值的时候,触发流控规则,统一抛出BlockExection
2.注解使用
注解使用的话,必须要先初始化配置:
@Configuration
public class SentinelConfig {
@Bean
public SentinelResourceAspect sentinelResourceAspect() {
return new SentinelResourceAspect();
}
}
然后就是简单的测试用例:
@RestController
public class HelloController {
@Autowired
private HelloService helloService;
@GetMapping("/hello")
public String hello(@RequestParam("name") String name){
return helloService.sayHello(name);
}
@GetMapping("/hello2")
public String circuitBreaker(@RequestParam("name") String name){
return helloService.circuitBreaker(name);
}
}
@Service
public class HelloService {
/**
* 限流降级
* @return
*/
@SentinelResource(value = "sayHello", blockHandler = "sayHelloExceptionHandler")
public String sayHello(String name){
return "hello,"+ name;
}
/**
* 熔断降级
* @return
*/
@SentinelResource(value = "circuitBreaker", fallback = "circuitBreakerFallback", blockHandler = "sayHelloExceptionHandler")
public String circuitBreaker(String name){
if ("zhangsan".equals(name)){
return "hello,"+ name;
}
throw new RuntimeException("发生异常");
}
public String circuitBreakerFallback(String name){
return "服务异常,熔断降级, 请稍后重试!";
}
public String sayHelloExceptionHandler(String name, BlockException ex){
return "访问过快,限流降级, 请稍后重试!";
}
}