sentinel dashboard
下载地址
https://github.com/alibaba/Sentinel/releases
启动dashboard
java -jar sentinel-dashboard-1.8.2.jar
登录dashboard
http://localhost:8080/
规则的种类
官网描述的非常详细。
https://sentinelguard.io/zh-cn/docs/basic-api-resource-rule.html
Sentinel 的所有规则都可以在内存态中动态地查询及修改,修改之后立即生效。同时 Sentinel 也提供相关 API,供您来定制自己的规则策略。
Sentinel 支持以下几种规则:流量控制规则、熔断降级规则、系统保护规则、来源访问控制规则 和 热点参数规则。
流量控制规则 (FlowRule)
流量规则的定义
重要属性:
Field | 说明 | 默认值 |
---|
resource | 资源名,资源名是限流规则的作用对象 | | count | 限流阈值 | | grade | 限流阈值类型,QPS 或线程数模式 | QPS 模式 | limitApp | 流控针对的调用来源 | default ,代表不区分调用来源 | strategy | 调用关系限流策略:直接、链路、关联 | 根据资源本身(直接) | controlBehavior | 流控效果(直接拒绝 / 排队等待 / 慢启动模式),不支持按调用关系限流 | 直接拒绝 |
同一个资源可以同时有多个限流规则。
流控模式(直接)
单机阈值比较好理解,就是对QPS/线程数的控制。 QPS与线程数的区别在于:
- QPS(每秒的访问次数),到达一定的阈值,就进行限流
- 线程数,调用该api的线程数达到阈值的时候,进行限流
流控模式(关联)
定义:当关联的资源达到阈值时,限流自己。 如当testB的QPS的阈值到达1的时候,testA就会被限流。
Warm Up
它的实现是在 Guava 的算法的基础上实现的。然而,和 Guava 的场景不同,Guava 的场景主要用于调节请求的间隔,即 Leaky Bucket,而 Sentinel 则主要用于控制每秒的 QPS,即我们满足每秒通过的 QPS 即可,我们不需要关注每个请求的间隔,换言之,我们更像一个 Token Bucket。
我们用桶里剩余的令牌来量化系统的使用率。假设系统每秒的处理能力为 b,系统每处理一个请求,就从桶中取走一个令牌;每秒这个令牌桶会自动掉落b个令牌。令牌桶越满,则说明系统的利用率越低;当令牌桶里的令牌高于某个阈值之后,我们称之为令牌桶"饱和"。
默认 coldFactor 为 3,即请求 QPS 从 threshold / 3 开始,经预热时长逐渐升至设定的 QPS 阈值。
例如如下配置流控规则是QPS从3开始,经过10s预热逐渐升至单机阈值10。
排队等待
Leaky Bucket 对应 流量整形 中的匀速器。它的中心思想是,以固定的间隔时间让请求通过。当请求到来的时候,如果当前请求距离上个通过的请求通过的时间间隔不小于预设值,则让当前请求通过;否则,计算当前请求的预期通过时间,如果该请求的预期通过时间小于规则预设的 timeout 时间,则该请求会等待直到预设时间到来通过(排队等待处理);若预期的通过时间超出最大排队时长,则直接拒接这个请求。
这种方式适合用于请求以突刺状来到,这个时候我们不希望一下子把所有的请求都通过,这样可能会把系统压垮;同时我们也期待系统以稳定的速度,逐步处理这些请求,以起到“削峰填谷”的效果,而不是拒绝所有请求。
例如,如果系统使用 Apache RocketMQ 来收发消息,系统在某个时间突然收到大量消息。我们希望以固定的速率来处理消息,而不是一下子拒绝这些消息。这个时候可以使用匀速器,也就是给消息排队。
熔断策略
- 慢调用比例 (
SLOW_REQUEST_RATIO ):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs )内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。 - 异常比例 (
ERROR_RATIO ):当单位统计时长(statIntervalMs )内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0] ,代表 0% - 100%。 - 异常数 (
ERROR_COUNT ):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。
热点参数限流
热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
以下热点参数限流配置即意味着调用sentinel资源aa接口的时候,如果传了该方法第0个参数则进行热点参数限流计数,满足规则触发限流。
可以通过@SentinelResource设置资源点和兜底异常处理方法(仅热点规则兜底),注意,定义兜底异常处理方法时,兜底方法参数列表和资源点参数列表一致,并在参数列表中添加BlockException。
@GetMapping("/testParamKey")
@SentinelResource(value = "aa", blockHandler = "deal_testParamKey")
public String testParamKey(@RequestParam(value = "name", required = false) String name,
@RequestParam(value = "age", required = false) String age){
System.out.println("name:" + name + ",age:" + age);
return "---------------testParamKey";
}
public String deal_testParamKey(String name, String age, BlockException blockException){
return "---------------deal_testParamKey";
}
系统限流
Sentinel 系统自适应限流从整体维度对应用入口流量进行控制,结合应用的 Load、CPU 使用率、总体平均 RT、入口 QPS 和并发线程数等几个维度的监控指标,通过自适应的流控策略,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
全局兜底处理
自定义全局兜底方法
package com.fox.springcloud.handler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.fox.springcloud.entity.CommonResult;
public class GlobalBlockExceptionHandler {
public static CommonResult testA_handler(BlockException exception){
return new CommonResult(500, exception.getLocalizedMessage() + "==testA服务不可用");
}
public static CommonResult testC_handler(BlockException exception){
return new CommonResult(500, exception.getLocalizedMessage() + "==testC服务不可用");
}
}
controller
@GetMapping("/testA")
@SentinelResource(value = "testA", blockHandlerClass = GlobalBlockExceptionHandler.class, blockHandler = "testA_handler")
public CommonResult testA(){
log.info(Thread.currentThread().getName());
return new CommonResult(200, Thread.currentThread().getName());
}
@GetMapping("/testC")
@SentinelResource(value = "testC", blockHandlerClass = GlobalBlockExceptionHandler.class, blockHandler = "testC_handler")
public CommonResult testC(){
return new CommonResult(200, "testC");
}
本人自测全局兜底处理配置流控规则时只能用资源名,用url配置的流控规则促发限流时自定义兜底不生效。
sentinel熔断
nacos使用ribbon负载均衡
nacos使用ribbon做负载均衡,服务提供者不用改,使用nacos做服务注册即可。
服务消费者添加负载均衡配置类
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
controller层注入restTemplate使用服务名调用
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.fox.springcloud.entity.CommonResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
@RestController
@Slf4j
public class CircleBreakerController {
private static final String service_url = "http://nacos-ribbon-provider";
@Resource
private RestTemplate restTemplate;
@GetMapping("/consume/echo/{id}")
public CommonResult<String> callback(@PathVariable Long id){
if (id == 4){
throw new IllegalArgumentException("IllegalArgumentException 非法参数异常。。。");
}
return new CommonResult<>(200, restTemplate.getForObject(service_url + "/echo/" + id, String.class));
}
}
添加sentinel熔断配置
创建兜底方法添加到要兜底的方法fallback配置属性上
@GetMapping("/consume/echo/{id}")
@SentinelResource(value = "fallback", fallback = "handler_fallback")
public CommonResult<String> callback(@PathVariable Long id){
if (id == 4){
throw new IllegalArgumentException("IllegalArgumentException 非法参数异常。。。");
}
return new CommonResult<>(200, restTemplate.getForObject(service_url + "/echo/" + id, String.class));
}
public CommonResult<String> handler_fallback(@PathVariable Long id, Throwable e){
return new CommonResult<>(500, "全局兜底异常处理:" + e.getMessage());
}
配置fallback和blockhandler
@GetMapping("/consume/echo/{id}")
@SentinelResource(value = "fallback", fallback = "handler_fallback", blockHandler = "handler_block")
public CommonResult<String> callback(@PathVariable Long id){
if (id == 4){
throw new IllegalArgumentException("IllegalArgumentException 非法参数异常。。。");
}
return new CommonResult<>(200, restTemplate.getForObject(service_url + "/echo/" + id, String.class));
}
public CommonResult<String> handler_fallback(@PathVariable Long id, Throwable e){
return new CommonResult<>(500, "全局兜底业务异常处理:" + e.getMessage());
}
public CommonResult<String> handler_block(@PathVariable Long id, BlockException e){
return new CommonResult<>(543, "全局兜底流控规则异常处理:" + e.getClass().getName());
}
当@SentinelResource同时配置fallback熔断配置和blockhandler流控规则,流控规则优先。
exceptionsToIgnore
配置某些异常不走熔断兜底处理,支持配置多个
@SentinelResource(value = "fallback", fallback = "handler_fallback", blockHandler = "handler_block", exceptionsToIgnore = {IllegalArgumentException.class})
熔断openfeign
pom.xml添加openfeign maven坐标
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
yaml配置文件开启Feign对sentinel的支持
feign:
sentinel:
enabled: true
启动类添加@EnableFeignClients
创建带@FeignClient的接口
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(value = "nacos-ribbon-provider", fallback = EchoFallbackService.class)
public interface EchoService {
@GetMapping(value = "/echo/{id}")
public String echo(@PathVariable("id") Long id);
}
创建fallback兜底处理
import org.springframework.stereotype.Component;
@Component
public class EchoFallbackService implements EchoService {
@Override
public String echo(Long id) {
return "全局兜底业务异常处理";
}
}
public String echo(@PathVariable("id") Long id);
}
创建fallback兜底处理
import org.springframework.stereotype.Component;
@Component
public class EchoFallbackService implements EchoService {
@Override
public String echo(Long id) {
return "全局兜底业务异常处理";
}
}
|