一文说透Sentinel熔断策略、降级规则、流量控制

2 Sentinel 限流熔断降级

Sentinel 可以简单的分为 Sentinel 核心库和 Dashboard。核心库不依赖 Dashboard,但是结合 Dashboard 可以取得最好的效果。我们先来学习Sentinel 核心库的使用,后面再学习Dashboard使用。

file

在我们项目中,用户请求通过hailtaxi-gateway路由到hailtaxi-driver或者hailtaxi-order,还有可能在hailtaxi-order中使用feign调用hailtaxi-driver,所以我们有可能在单个服务中实现熔断限流,也有可能要集成feign调用实现熔断限流,还有可能在微服务网关中实现熔断限流。我们接下来一步一步实现每一种熔断限流操作。

SpringBoot集成:

如果在SpringBoot项目中使用Sentinel,首先需要引入spring-cloud-starter-alibaba-sentinel依赖,并使用@SentinelResource标识资源。

hailtaxi-driver工程中引入spring-cloud-starter-alibaba-sentinel依赖,依赖如下:

<!--sentinel-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>2.2.5.RELEASE</version>
</dependency>

2.1 @SentinelResource定义资源

@SentinelResource 用于定义资源,并提供可选的异常处理和 fallback 配置项。 @SentinelResource 注解包含以下属性:

value 资源名称,必需项(不能为空)
blockHandler / blockHandlerClass blockHandler 对应处理 BlockException 的函数名称,可选项。
♞ blockHandler 函数访问范围需要是 public;
♞ 返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException。
♞ blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
fallback / fallbackClass fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。fallback 函数签名和位置要求:
♞ 返回值类型必须与原函数返回值类型一致;
♞ 方法参数列表需要和原函数一致,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。
♞ fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
defaultFallback(1.6.0 开始) 默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑(即可以用于很多服务或方法)。默认 fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。defaultFallback 函数签名要求:
♞ 返回值类型必须与原函数返回值类型一致;
♞ 方法参数列表需要为空,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。
♞ defaultFallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
exceptionsToIgnore(1.6.0 开始) 用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。
entryType entry 类型,可选项(默认为 EntryType.OUT)
blockHandler/blockHandlerClass

hailtaxi-driver中找到DriverController中的info方法,用户在打车的时候,会查询司机信息,如果司机不存在,此时会报错,代码改造如下:

/****
     * 司机信息
     */
@GetMapping(value = "/info/{id}")
//@RequestMapping(value = "/info/{id}")
public Driver info(@PathVariable(value = "id")String id,HttpServletRequest request){
    log.info("当前服务占用的端口为:{}",port);
    Driver driver = driverService.findById(id);
    if (driver==null) {
        throw new RuntimeException("司机id="+id+"不存在");
    }
    return driver;
}

如果此时访问:http://localhost:18081/driver/info/3 查询司机信息,如果没有ID为3的司机信息,会报如下错误,

file

这种体验非常差,我们可以集成Sentinel使用@SentinelResourceblockHandler返回默认错误信息,形成降级!!!

1、Sentinel 支持在程序中抛出它定义的BlockException异常,该异常会被Sentinel捕获,然后走降级方法,

info()方法添加一个@SentinelResource注解,用来标注资源,表示当前方法需要执行限流、降级,在注解中添加value属性,用来标注资源,说白了就是给当前资源起个名字,blockHandler用来表示当前方法发生BlockException异常的时候,将处理流程交给指定的方法blockExHandler()处理,此时blockExHandler()方法必须和抛出异常的方法在同一个类中,这是一种降级操作,代码如下:

/****
     * 司机信息
     */
@SentinelResource(value = "info",blockHandler = "blockExHandler")
@RequestMapping(value = "/info/{id}")
public Driver info(@PathVariable(value = "id")String id) throws BlockException {
    log.info("当前服务占用的端口为:{}",port);
    Driver driver = driverService.findById(id);
    if (driver==null) {
        //throw new RuntimeException("司机id="+id+"不存在");
        throw new SystemBlockException("info", "司机id="+id+"不存在",null); // 抛出BlockException
    }
    return driver;
}

/**
     * info资源出现BlockException后的降级处理
     */
public Driver blockExHandler(String id,BlockException e) {
    Driver driver = new Driver();
    driver.setId(id);
    driver.setName("系统繁忙,稍后再试");
    return driver;
}

file

注意:

如果blockHandler方法和资源方法不在同一个类中,我们可以在@SentinelResource中添加blockHandlerClass属性,指定降级处理类的方法所在的类,且要求blockHandler方法是静态的,代码如下:

@SentinelResource(value = "info",blockHandler = "blockExHandler",blockHandlerClass = "xxx.xxx.Xxxx")

2、启动测试,访问:http://localhost:18081/driver/info/3 测试出错效果如下:

file

fallback/fallbackClass

1、如果我们希望抛出任何异常都能处理,都能调用默认处理方法,而并非只是BlockException异常才调用,此时可以使用@SentinelResourcefallback属性,代码如下:

/****
     * 司机信息
     */
@SentinelResource(value = "info"/*,blockHandler = "blockExHandler"*/,fallback = "exHandler")
@RequestMapping(value = "/info/{id}")
public Driver info(@PathVariable(value = "id")String id) throws BlockException {
    log.info("当前服务占用的端口为:{}",port);
    Driver driver = driverService.findById(id);
    if (driver==null) {
        throw new RuntimeException("司机id="+id+"不存在");
        // throw new SystemBlockException("info", "司机id="+id+"不存在",null); // 抛出BlockException
    }
    return driver;
}
/**
     * info资源出现任何类型异常后的降级处理
     * 方法参数可以添加一个Throwable 类型的参数,也可不添加
     */
public Driver exHandler(String id,Throwable e) {
    Driver driver = new Driver();
    driver.setId(id);
    driver.setName("系统繁忙,稍后再试");
    return driver;
}

注意:

如果fallback方法和当前的资源方法不在同一个类中,可以使用@SentinelResource注解的fallbackClass实现,也要求fallback方法是静态的,代码如下:

@SentinelResource(value = "info",fallback ="exHandler" ,fallbackClass = "xx.xxx.xxx.xx.X
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值