6.6 Sentinel规则降级

降级规则就是设置当满足什么条件的时候,对服务进行降级。 Sentinel提供了三个衡量条件:

慢调用比例: 选择以慢调用比例作为阈值,需要设置允许的慢调用 RT (即最大的响应时间),请求 的响应时间大于该值则统计为慢调用。当单位统计时长内请求数目大于设置的最小请求数目,并且 慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入 探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔 断,若大于设置的慢调用 RT 则会再次被熔断。

异常比例: 当单位统计时长内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接 下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的 阈值范围是 [0.0, 1.0] ,代表 0% - 100%。

异常数:当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进 入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

6.6.1 慢调用比例案例

  1. 在shop-order-server项目中新增FallBackController.java类,代码如下:
@RestController
@Slf4j
public class FallBackController {
    @RequestMapping("/fallBack1")
    public String fallBack1() {
        try {
            log.info("fallBack1执⾏业务逻辑");
            //模拟业务耗时
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "fallBack1";
    }
}
  1. 新增降级规则:

ios15 降级14_spring cloud

上面配置表示,如果在1S之内,有【超过1个的请求】且这些请求中【响应时间>最大RT】的【请求 数量比例>50%】,就会触发熔断,在接下来的10s之内都不会调用真实方法,直接走降级方法。

比如 : 最大RT=900,比例阈值=0.1,熔断时长=10,最小请求数=10

○ 情况1: 1秒内的有20个请求,只有10个请求响应时间>900ms, 那慢调用比例=0.5,这种情况 就会触发熔断

○ 情况2: 1秒内的有20个请求,只有1个请求响应时间>900ms, 那慢调用比例=0.05,这种情况 不会触发熔断

○ 情况3: 1秒内的有8个请求,只有6个请求响应时间>900ms, 那慢调用比例=0.75,这种情况不 会触发熔断,因为最小请求数这个条件没有满足 .

注意: 我们做实验的时候把最小请求数设置为1,因为在1秒内,手动操作很难在1s内发两个请求过 去,所以要做出效果,最好把最小请求数设置为1。

6.6.2 异常比例案例

  1. 在shop-order-server项目的FallBackController.java类新增fallBack2方法:
int i = 0;

    @RequestMapping("/fallBack2")
    public String fallBack2() {
        log.info("fallBack2执⾏业务逻辑");
        //模拟出现异常,异常⽐例为33%
        if (++i % 3 == 0) {
            throw new RuntimeException();
        }
        return "fallBack2";
    }
  1. 新增降级规则:

ios15 降级14_spring cloud_02

上面配置表示,在1s之内, ,有【超过2个的请求】,异常比例30%的情况下,触发熔断,熔断时长5s.

6.3.3 异常数案例

  1. 在shop-order-server项目的FallBackController.java类新增fallBack3方法:
@RequestMapping("/fallBack3")
    public String fallBack3(String name) {
        log.info("fallBack3执⾏业务逻辑");
        //模拟出现异常,异常⽐例为33%
        if (++i % 3 == 0) {
            throw new RuntimeException();
        }
        return "fallBack3";
    }
  1. 新增降级规则

ios15 降级14_spring boot_03

上面配置表示,在1s之内, ,有【超过3个的请求】,请求中超过2个请求出现异常就会触发熔断, 熔断时长为10s

6.7 Sentinel规则热点

何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数 据,并对其访问进行限制。比如:

  1. 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
  2. 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制

热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调 用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。

  1. 在shop-order-server项目中新增HotSpotController.java,代码如下:
@RestController
@Slf4j
public class HotSpotController {
 @RequestMapping("/hotSpot1")
 @SentinelResource(value = "hotSpot1")
 public String hotSpot1(Long productId){
 log.info("访问编号为:{}的商品",productId);
 return "hotSpot1";
 }
}

注意:一定需要在请求方法上贴@SentinelResource直接,否则热点规则无效.

  1. 新增热点规则:

ios15 降级14_spring cloud_04

  1. 在热点规则中编辑规则,在编辑之前一定要先访问一下/hotSpot1,不然参数规则无法新增.

ios15 降级14_spring cloud_05

  1. 新增参数规则:

ios15 降级14_java_06

  1. 点击保存,可以看到已经新增了参数规则.

ios15 降级14_spring cloud_07

  1. 访问http://localhost:8091/hotSpot?productId=1 访问降级;访问http://localhost:8091/hotSpot?productId=2 访问不会降级

ios15 降级14_ios15 降级14_08

6.8 Sentinel规则授权

很多时候,我们需要根据调用来源来判断该次请求是否允许放行,这时候可以使用 Sentinel 的来源访问 控制(黑白名单控制)的功能。来源访问控制根据资源的请求来源( origin )限制资源是否通过,若 配置白名单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。

  1. 在shop-order-server中新建RequestOriginParserDefinition.java,定义请求来源如何获取
@Component
public class RequestOriginParserDefinition implements RequestOriginParser {
    @Override
    public String parseOrigin(HttpServletRequest request) {
        /**
         * 定义从请求的什么地⽅获取来源信息
         * ⽐如我们可以要求所有的客户端需要在请求头中携带来源信息
         */
        String type = request.getParameter("type");
        return type;
    }
}
  1. 在shop-order-server中新建AuthController.java,代码如下:
@RestController
@Slf4j
public class AuthController {
    @RequestMapping("/auth1")
    public String auth1(String type) {
        log.info("应⽤:{},访问接⼝", type);
        return "auth1";
    }
}
  1. 新增授权规则

ios15 降级14_sentinel_09

  1. 访问测试

访问http://localhost:8091/auth1?serviceName=pc 不能访问

访问http://localhost:8091/auth1?serviceName=ios 可以访问

ios15 降级14_spring cloud_10

6.9 Sentinel规则系统规则

系统保护规则是从应用级别的入口流量进行控制,从单台机器的 load 、CPU 使用率、平均 RT、入口QPS 和并发线程数等几个维度监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定 性。

系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应 用的流量( EntryType.IN ),比如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。

系统规则支持以下的模式:

  1. Load⾃适应(仅对 Linux/Unix-like 机器⽣效):系统的 load1 作为启发指标,进⾏⾃适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的 maxQps * minRt 估算得出。设定参考值⼀般是 CPUcores * 2.5 。
  2. CPU usage(1.5.0+ 版本):当系统 CPU 使⽤率超过阈值即触发系统保护(取值范围 0.0-1.0),⽐较灵敏。
  3. 平均 RT:当单台机器上所有⼊⼝流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
  4. 并发线程数:当单台机器上所有⼊⼝流量的并发线程数达到阈值即触发系统保护。
  5. ⼊⼝QPS:当单台机器上所有⼊⼝流量的 QPS 达到阈值即触发系统保护。

ios15 降级14_sentinel_11

6.10 Sentinel 自定义异常返回

当前面设定的规则没有满足是,我们可以自定义异常返回.

  1. FlowException 限流异常
  2. DegradeException 降级异常
  3. ParamFlowException 参数限流异常
  4. AuthorityException 授权异常
  5. SystemBlockException 系统负载异常

在shop-order-server项目中定义异常返回处理类

@Component
public class ExceptionHandlerPage implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse
            response, BlockException e) throws Exception {
        response.setContentType("application/json;charset=utf-8");
        ResultData data = null;
        if (e instanceof FlowException) {
            data = new ResultData(-1, "接⼝被限流了");
        } else if (e instanceof DegradeException) {
            data = new ResultData(-2, "接⼝被降级了");
        } else if (e instanceof ParamFlowException) {
            data = new ResultData(-3, "参数限流异常");
        } else if (e instanceof AuthorityException) {
            data = new ResultData(-4, "授权异常");
        } else if (e instanceof SystemBlockException) {
            data = new ResultData(-5, "接⼝被降级了...");
        }
        response.getWriter().write(JSON.toJSONString(data));
    }
}

@Data
@AllArgsConstructor//全参构造
@NoArgsConstructor//⽆参构造
class ResultData {
    private int code;
    private String message;
}

6.11 @SentinelResource的使用

在定义了资源点之后,我们可以通过Dashboard来设置限流和降级策略来对资源点进行保护。同时还能通过@SentinelResource来指定出现异常时的处理策略。

@SentinelResource 用于定义资源,并提供可选的异常处理和 fallback 配置项。

其主要参数如下:

属性

作用

value

资源名称,必需项(不能为空)

entryType

entry 类型,可选项(默认为 EntryType.OUT )

blockHandler / blockHandlerClass

blockHandler 对应处理 BlockException 的函数名称,可选项。 blockHandler 函数访问范围需要是public ,返回类型需要与原方法相匹配,参数类型需要 和原方法相匹配并且最后加一个额外的参数,类型为BlockException 。blockHandler 函数默认需要和原方 法在同一个类中。若希望使用其他类的函数,则可以指定 blockHandlerClass 为对应的类的 Class 对象,注意 对应的函数必需为 static 函数,否则无法解析。

fallback / fallbackClass

进行处理。fallback 函数签名和位置要求:1. 返回值类型必须与原函数返回值类型一致;2.方法参数列表需要和原函数一致,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常。3.fallback 函数默认需要和原方法在同一个类中。若希望 使用其他类的函数,则可以指定 fallbackClass 为对应 的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。

defaultFallback

默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑(即可以用于很多服务或方法)。默认 fallback 函数可以针对所有类型的异常(除了exceptionsToIgnore 里面排除掉的异常类型)进行处 理。若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。defaultFallback 函数签名要求:1. 返回值类型必须与原函数返回值类型一致;2. 方法参数列表需要为空,或者可以额外多一个Throwable 类型的参数用于接收对应的异常。3. defaultFallback 函数默认需要和原方法在同一个类中。 若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。

exceptionsToIgnore

用于指定哪些异常被排除掉,不会计入异常统计中,也不 会进入 fallback 逻辑中,而是会原样抛出。

定义限流和降级后的处理方法

直接将限流和降级方法定义在方法中

@RestController
@Slf4j
public class AnnoController {
    @RequestMapping("/anno1")
    @SentinelResource(value = "anno1",
            blockHandler = "anno1BlockHandler",//当前方法如果要被限流或被降级就会调用这个字符串对应的方法
            fallback = "anno1Fallback"//当前方法出现异常会执行fallback
    )
    public String anno1(String name) {
        if ("zgh".equals(name)) {
            throw new RuntimeException();
        }
        return "anno1";
    }

    public String anno1BlockHandler(String name, BlockException ex) {
        log.error("{}", ex);
        return "接⼝被限流或者降级了";
    }

    //Throwable时进⼊的⽅法
    public String anno1Fallback(String name, Throwable throwable) {
        log.error("{}", throwable);
        return "接⼝发⽣异常了";
    }
}

6.12 Feign整合Sentinel

  1. 在shop-order-server项目的配置文件中开启feign对Sentinel的支持
feign:
    sentinel:
        enabled: true
  1. 创建容错类
@Component
public class ProductFeignFallBack implements ProductFeignApi {
    @Override
    public Product findByPid(Long pid) {
        Product product = new Product();
        product.setPid(-1L);
        product.setPname("兜底数据");
        product.setPprice(0.0);
        return product;
    }
}
  1. 在feign接口中定义容错类
//name的名称⼀定要和订单服务的服务名保持⼀致
@FeignClient(name = "product-service", fallback =
        ProductFeignFallBack.class)
public interface ProductFeignApi {
    @RequestMapping("/product/{pid}")
    public Product findByPid(@PathVariable("pid") Long pid);
  1. 停止所有 商品服务,重启 shop-order 服务,访问请求,观察容错效果

ios15 降级14_java_12

可能上面的案例并不是特别恰当,我们只是通过案例来演示Feign集成Sentinel实现降级的效果. 接下来 我们具体更贴切的案例来讲解Feign降级的作用 .

比如我们在购物的时候,查看商品详情页面的时候,里面包含库存信息,商品详情信息,评论信息,这个需 求包含的微服务如下:

ios15 降级14_java_13

假设现在评论服务宕机了,那是不是意味用户发出查看商品请求也无法正常显示了,商品都看不到了,那 用户也无法进行下单的操作了 . 但是对于用户来说,评论看不到并不影响他购物,所以这时候我们应该对 评论服务进行降级处理,返回一个兜底数据(空数据),这样用户的查看商品请求能正常显示,只是评 论数据看不到而已,这样的话,用户的下单请求也不会受到影响.