乐趣区

关于java:一文说透Sentinel熔断策略降级规则流量控制

2 Sentinel 限流熔断降级

Sentinel 能够简略的分为 Sentinel 外围库和 Dashboard。外围库不依赖 Dashboard,然而联合 Dashboard 能够获得最好的成果。咱们先来学习 Sentinel 外围库的应用,前面再学习 Dashboard 应用。

在咱们我的项目中,用户申请通过 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… 查问司机信息,如果没有 ID 为 3 的司机信息,会报如下谬误,

这种体验十分差,咱们能够集成 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;
}

留神:

如果 blockHandler 办法和资源办法不在同一个类中,咱们能够在 @SentinelResource 中增加 blockHandlerClass 属性,指定降级解决类的办法所在的类,且要求 blockHandler 办法是动态的,代码如下:

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

2、启动测试,拜访:http://localhost:18081/driver… 测试出错成果如下:

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.Xxx")

2、拜访 http://localhost:18081/driver… 测试出错成果如下:

defaultFallback

下面无论是 blockHandler 还是 fallback,每个办法产生异样,都要为办法独立创立一个解决异样的办法,效率非常低,咱们能够应用@SentinelResource 注解的 defaultFallback 属性,为一个类指定一个全局的处理错误的办法,代码如下:

@RestController
@RequestMapping(value = "/driver")
@Slf4j
@RefreshScope
@SentinelResource(defaultFallback = "defaultExHandler")
public class DriverController {
    @Autowired
    private DriverService driverService;

    public Driver defaultExHandler(Throwable e) {Driver driver = new Driver();
        driver.setName("零碎忙碌, 稍后再试");
        return driver;
    }

    /****
     * 司机信息
     */
    //@SentinelResource(value = "info"/*,blockHandler = "blockExHandler"*/,fallback = "exHandler")
    @SentinelResource("info")
    @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;
    }

拜访 http://localhost:18081/driver… 成果如下:

2.2 Sentinel 的规定

Sentinel 的所有规定都能够在内存态中动静地查问及批改,批改之后立刻失效。同时 Sentinel 也提供相干 API,供您来定制本人的规定策略。

Sentinel 反对以下几种规定:流量管制规定 熔断降级规定 零碎爱护规定 起源访问控制规定 热点参数规定

2.2.1 流量管制规定 (FlowRule)

流量规定的定义,重要属性如下:

Field 阐明 默认值
resource 资源名,资源名是限流规定的作用对象
count 限流阈值
grade 限流阈值类型,QPS 模式(1)或并发线程数模式(0) QPS 模式
limitApp 流控针对的调用起源 default,代表不辨别调用起源
strategy 调用关系限流策略:间接、链路、关联 依据资源自身(间接)
controlBehavior 流控成果(间接回绝 /WarmUp/ 匀速 + 排队期待),不反对按调用关系限流 间接回绝
clusterMode 是否集群限流

同一个资源能够同时有多个限流规定,查看规定时会顺次查看

strategy 限流策略阐明:

间接: 资源达到限流条件时,间接限流。关联:A 资源关联 B 资源,当关联的 B 资源达到阈值限流时,A 资源也会被限流。链路: 对于某资源 C,有两个入口,从资源 A ->C, 从资源 B ->C, 通过指定入口资源能够达到只记录从该入口进来的流量(指定资源从入口资源进来的流量,如果达到阈值,就能够对其限流)。

controlBehavior 流控阐明:

间接回绝: 申请间接失败。WarmUp: 当零碎长期处于低水位的状况下,当流量忽然减少时,间接把零碎拉升到高水位可能霎时把零碎压垮。通过 "冷启动",让通过的流量迟缓减少,在肯定工夫内逐步减少到阈值下限,给冷零碎一个预热的工夫,防止冷零碎被压垮。排队期待: 排队解决申请。

了解下面规定的定义之后,咱们能够通过调用 FlowRuleManager.loadRules() 办法来用硬编码的形式定义流量管制规定。

QPS 流量管制

1、咱们先实现基于 QPS 流量管制,在 hailtaxi-driverDriverApplication启动类上增加如下办法加载限流规定,当 DriverApplication 初始化实现之后加载规定,代码如下:

/***
 * 初始化规定
 */
@PostConstruct
private void initFlowRule() {
    // 规定汇合
    List<FlowRule> rules = new ArrayList<FlowRule>();
    // 定义一个规定
    FlowRule rule = new FlowRule("info");
    // 设置阈值
    rule.setCount(2);
    // 设置限流阈值类型
    rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
    //default,代表不辨别调用起源
    rule.setLimitApp("default");
    // 设置流控成果
    rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT);
    // 将定义的规定增加到汇合中
    rules.add(rule);
    // 加载规定
    FlowRuleManager.loadRules(rules);
}

2、拜访 http://localhost:18081/driver… 此时不会抛出异样,然而频繁刷新,则会调用降级办法,成果如下:

线程数流量管制

1、咱们批改限流阈值类型,代码如下:

@PostConstruct
public void initFlowRule() {
    // 规定汇合
    List<FlowRule> rules = new ArrayList<>();
    // 定义一个规定
    FlowRule rule = new FlowRule("info");
    // 设置基流量管制 的类型
    rule.setGrade(RuleConstant.FLOW_GRADE_THREAD);// 默认是 qps
    // 设置流量阈值
    rule.setCount(2);
    // 将 规定增加到 汇合中
    rules.add(rule);
    // 加载规定
    FlowRuleManager.loadRules(rules);
}

2、此时再来拜访 http://localhost:18081/driver/info/1 咱们发现用浏览器无论怎么拜访都不会呈现降级景象,然而如果用 Jmeter 模仿多个线程,成果就不一样了, 成果如下:

2.2.2 熔断降级规定 (DegradeRule)

熔断降级规定蕴含上面几个重要的属性:

Field 阐明 默认值
resource 资源名,即规定的作用对象
grade 熔断策略,反对慢调用比例 / 异样比例 / 异样数策略 慢调用比例
count 慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用);异样比例 / 异样数模式下为对应的阈值
timeWindow 熔断时长,单位为 s
minRequestAmount 熔断触发的最小申请数,申请数小于该值时即便异样比率超出阈值也不会熔断(1.7.0 引入) 5
statIntervalMs 统计时长(单位为 ms),如 60*1000 代表分钟级(1.8.0 引入) 1000 ms
slowRatioThreshold 慢调用比例阈值,仅慢调用比例模式无效(1.8.0 引入)

同一个资源能够同时有多个降级规定。

了解下面规定的定义之后,咱们能够通过调用 DegradeRuleManager.loadRules() 办法来用硬编码的形式定义熔断规定,

1、在 DriverApplication 规定定义如下:

@PostConstruct
public void initDegradeRule() {List<DegradeRule> rules = new ArrayList<>();
    DegradeRule rule = new DegradeRule();
    // 设置资源名称
    rule.setResource("info");
    /**
         * 设置熔断策略
         * DEGRADE_GRADE_RT: 均匀响应工夫
         * DEGRADE_GRADE_EXCEPTION_RATIO: 异样比例数量
         * DEGRADE_GRADE_EXCEPTION_COUNT: 异样数
         */
    rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
    // 设置阈值
    rule.setCount(2);
    // 设置 熔断时长
    rule.setTimeWindow(30);
    // 统计时长(单位为 ms)默认 1000
    rule.setStatIntervalMs(60*1000);
    // 将规定增加到汇合中
    rules.add(rule);
    DegradeRuleManager.loadRules(rules);
}

2、首先拜访:http://localhost:18081/driver…,确保没问题,

其次拜访:http://localhost:18081/driver…,多拜访几次,造成熔断(5+2=7)

而后在拜访:http://localhost:18081/driver…,会发现曾经有熔断降级成果了,

且查看服务控制台,发现不会有信息输入,表明曾经熔断了,且从页面展现成果来看走了降级

期待 30s 后,再次拜访:http://localhost:18081/driver…,查看熔断是否完结!

2.2.3 零碎爱护规定 (SystemRule)

Sentinel 零碎自适应限流从整体维度对利用入口流量进行管制,联合利用的 Load、CPU 使用率、总体均匀 RT、入口 QPS 和并发线程数等几个维度的监控指标,通过自适应的流控策略,让零碎的入口流量和零碎的负载达到一个均衡,让零碎尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

零碎规定蕴含上面几个重要的属性:

Field 阐明 默认值
highestSystemLoad load1 触发值,用于触发自适应控制阶段 -1 (不失效)
avgRt 所有入口流量的均匀响应工夫 -1 (不失效)
maxThread 入口流量的最大并发数 -1 (不失效)
qps 所有入口资源的 QPS -1 (不失效)
highestCpuUsage 以后零碎的 CPU 使用率(0.0-1.0) -1 (不失效)

了解下面规定的定义之后,咱们能够通过调用 SystemRuleManager.loadRules() 办法来用硬编码的形式定义流量管制规定。

1、在 hailtaxi-driverDriverApplication中创立如下办法,代码如下:

/***
 * 零碎自我爱护
 */
@PostConstruct
private void initSystemRule() {
    // 零碎自我爱护汇合
    List<SystemRule> rules = new ArrayList<>();
    // 创立零碎自我爱护规定
    SystemRule rule = new SystemRule();
    //CPU 使用率 值为[0,1],-1 (不失效)
    rule.setHighestCpuUsage(0.2);
    // 所有入口资源的 QPS,-1 (不失效)
    rule.setQps(10);
    // 入口流量的最大并发数,-1 (不失效)
    rule.setMaxThread(5);
    // 所有入口流量的均匀响应工夫, 单位:秒,-1 (不失效)
    rule.setAvgRt(5);
    //load1 触发值,用于触发自适应控制阶段, 零碎最高负载,倡议取值 CPU cores * 2.5
    rule.setHighestSystemLoad(20);
    // 将规定退出到汇合
    rules.add(rule);
    SystemRuleManager.loadRules(rules);
}

咱们能够测试 CPU 使用率自我爱护,应用 jmeter 测试如下:

2.2.4 访问控制规定 (AuthorityRule)

很多时候,咱们须要依据调用方来限度资源是否通过,这时候能够应用 Sentinel 的访问控制(黑白名单)的性能。黑白名单依据资源的申请起源(origin)限度资源是否通过,若配置白名单则只有申请起源位于白名单内时才可通过;若配置黑名单则申请起源位于黑名单时不通过,其余的申请通过。

受权规定,即黑白名单规定(AuthorityRule)非常简单,次要有以下配置项:

  • resource:资源名,即规定的作用对象
  • limitApp:对应的黑名单 / 白名单,不同 origin 用 , 分隔,如 appA,appB
  • strategy:限度模式,AUTHORITY_WHITE 为白名单模式,AUTHORITY_BLACK 为黑名单模式,默认为白名单模式

理解了以上规定后,能够通过 AuthorityRuleManager.loadRules 来加载规定

1、在 hailtaxi-driverDriverApplication中创立如下办法,代码如下:

@PostConstruct
    public void initAuthorityRule() {AuthorityRule rule = new AuthorityRule();
        rule.setResource("info");
        rule.setStrategy(RuleConstant.AUTHORITY_WHITE);
        rule.setLimitApp("127.0.0.1,appB");
        AuthorityRuleManager.loadRules(Collections.singletonList(rule));
    }

    /**
     * Sentinel 提供了 RequestOriginParser 接口来解决拜访起源,Sentinel 爱护的资源如果被拜访,* 就会调用 RequestOriginParser 解析拜访起源
     */
    @Component
    public class IpLimiter implements RequestOriginParser{

        @Override
        public String parseOrigin(HttpServletRequest httpServletRequest) {return httpServletRequest.getRemoteAddr();
        }
    }

2、拜访:http://localhost:18081/driver…,不通过,走了降级

​ 拜访:http://127.0.0.1:18081/driver…

2.2.4 热点规定 (ParamFlowRule)

何为热点?热点即常常拜访的数据。

很多时候咱们心愿统计某个热点数据中拜访频次最高的 Top K 数据,并对其拜访进行限度。比方:

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

热点参数限流会统计传入参数中的热点参数,并依据配置的限流阈值与模式,对蕴含热点参数的资源调用进行限流。热点参数限流能够看做是一种非凡的流量管制,仅对蕴含热点参数的资源调用失效。

Sentinel 利用 LRU 策略统计最近最常拜访的热点参数,联合令牌桶算法来进行参数级别的流控。热点参数限流反对集群模式。

要应用热点参数限流性能,须要引入以下依赖,将该依赖退出到 hailtaxi-driver 中:

<!-- 热点参数限流 -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-parameter-flow-control</artifactId>
    <version>1.8.1</version>
</dependency>

而后为对应的资源配置热点参数限流规定,并在 entry 的时候传入相应的参数,即可使热点参数限流失效。

热点参数规定(ParamFlowRule)相似于流量管制规定(FlowRule):

属性 阐明 默认值
resource 资源名,必填
count 限流阈值,必填
grade 限流模式 QPS 模式
durationInSec 统计窗口工夫长度(单位为秒),1.6.0 版本开始反对 1s
controlBehavior 流控成果(反对疾速失败和匀速排队模式),1.6.0 版本开始反对 疾速失败
maxQueueingTimeMs 最大排队期待时长(仅在匀速排队模式失效),1.6.0 版本开始反对 0ms
paramIdx 热点参数的索引,必填,对应 SphU.entry(xxx, args) 中的参数索引地位
paramFlowItemList 参数例外项,能够针对指定的参数值独自设置限流阈值,不受后面 count 阈值的限度。仅反对根本类型和字符串类型
clusterMode 是否是集群参数流控规定 false
clusterConfig 集群流控相干配置

咱们能够通过 ParamFlowRuleManagerloadRules 办法更新热点参数规定

1、在 DriverController 中创立一个司机筛选办法,比方依据城市来筛选,在 DriverController 中创立一个办法:

/***
     * 搜素指定城市的司机
     */
@SentinelResource(value = "search")
@GetMapping(value = "/search/{city}")
public Driver search(@PathVariable(value = "city")String city){System.out.println("查问的司机所在城市:"+city);
    // 假如查问到了一个司机信息
    Driver driver = new Driver();
    driver.setName("唐僧老师");
    driver.setId("No.1");
    return driver;
}

2、对热门参数进行管制,对热点数据执行非凡限流,比方资源参数列表中的第一个参数值为 恩施 的时候执行限流,在 DriverApplication 中创立限流配置,代码如下:

/***
 * 热点参数初始化
 */
@PostConstruct
private static void initParamFlowRules() {ParamFlowRule rule = new ParamFlowRule("search")
            // 参数下标为 0
            .setParamIdx(0)
            // 限流模式为 QPS
            .setGrade(RuleConstant.FLOW_GRADE_QPS)
            // 统计窗口工夫长度(单位为秒).setDurationInSec(10)
            // 流控成果(反对疾速失败和匀速排队模式)//CONTROL_BEHAVIOR_DEFAULT:限风行为,间接回绝
            //CONTROL_BEHAVIOR_WARM_UP: 限风行为,匀速排队
            //CONTROL_BEHAVIOR_RATE_LIMITER:限风行为,匀速排队
            .setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT)
            // 最大排队期待时长(仅在匀速排队模式失效  CONTROL_BEHAVIOR_RATE_LIMITER)//.setMaxQueueingTimeMs(600)
            // 最大阈值为 5
            .setCount(5);

    // 为特定参数独自设置规定
    // 如下配置:当下标为 0 的参数值为恩施的时候,阈值达到 2 的时候则执行限流
    ParamFlowItem item = new ParamFlowItem()
            // 参数类型为 String 类型
            .setClassType(String.class.getName())
            // 设置阈值为 2
            .setCount(2)
            // 须要统计的值
            .setObject(String.valueOf("恩施"));
    rule.setParamFlowItemList(Collections.singletonList(item)); // 返回的是不可变的汇合,然而这个长度的汇合只有 1,能够缩小内存空间
    // 加载热点数据
    ParamFlowRuleManager.loadRules(Collections.singletonList(rule));
}

2、咱们拜访 http://localhost:18081/driver/search/ 天津 / 的时候,间断执行 5 次,才会限流,

咱们拜访 http://localhost:18081/driver/search/ 恩施 / 的时候,间断执行 2 次,就会限流,

2.3 OpenFeign 反对

Sentinel 适配了 Feign 组件。如果想应用,除了外还须要 2 个步骤:

1:引入 `spring-cloud-starter-alibaba-sentinel` 的依赖
2:退出 spring-cloud-starter-openfeign 依赖
3:配置文件关上 Sentinel 对 Feign 的反对:feign.sentinel.enabled=true

在下面案例中,咱们能够实现用户打车胜利调用 hailtaxi-order 执行下单,并且通过 feign 调用 hailtaxi-driver 批改司机状态,此时咱们能够应用 Sentinel 实现 Feign 调用降级、限流。

留神:

在进行操作之前,能够先将 hailtaxi-driver 中的访问控制规定正文掉,正文掉 DriverApplication#initAuthorityRuleDriverApplication#initSystemRule 上的注解即可

1、在 hailtaxi-order 中引入 sentinelOpenFeign依赖,配置如下:

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

<!--Openfeign  api 模块中已存在也可不引入 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2、在 hailtaxi-order 的配置文件中开启 Feign 反对sentinel,配置如下:

feign:
  #开启 Sentinel 对 Feign 的反对
  sentinel:
    enabled: true

留神:当初配置信息都寄存在了 nacos 中,所以找到 hailtaxi-order.yaml 的 Data ID 配置,将以上配置增加进去!

留神批改完后肯定要公布能力失效!!!

3、因为 hailtaxi-order 要通过 openfeign 去调用 hailtaxi-driver 中的 DriverController#status 办法,革新一下该办法

/****
     * 更新司机信息
     */
@PutMapping(value = "/status/{id}/{status}")
public Driver status(@PathVariable(value = "id")String id,@PathVariable(value = "status")Integer status) throws Exception {log.info("以后服务占用的端口为:{}",port);
    // 批改状态
    driverService.update(id,status);
    // 批改状态后的司机信息
    Driver driver = driverService.findById(id);
    if (driver == null) {throw new RuntimeException("学生 id="+id+", 不存在");
    }
    return driver;
}

模仿被调用服务出现异常的状况

3、先验证正确性,启动 hailtaxi-gatewayhailtaxi-orderhailtaxi-driver 服务,应用 postman 拜访:

http://localhost:8001/order

4、为了测试程序异样能实现降级操作,咱们在 hailtaxi-order 中将 OrderInfoController.add() 办法的司机 ID 改成一个不存在的司机 ID,让程序报错,测试降级解决,代码如下:

/***
     * 下单
     */
@PostMapping
public OrderInfo add(){
    // 批改司机信息  司机 ID=1
    Driver driver = driverFeign.status("3",2);// 改成一个不存在的 id
    // 创立订单
    OrderInfo orderInfo = new OrderInfo("No"+((int)(Math.random()*10000)), (int)(Math.random()*100), new Date(), "深圳北站", "罗湖港", driver);
    orderInfoService.add(orderInfo);
    return orderInfo;
}

5、再次启动测试:

留神:服务调用出错要进行降级操作有两个中央都能够进行,一是在被调用方进行降级,一是在调用方进行降级,

在被调用方进行降级后面曾经讲过了,所以接下来解说如何在调用方(openfeign)联合 sentinel 进行降级解决。

2.3.1 fallback

hailtaxi-api 模块中找到 DriverFeign 接口:

1、为 Feign 接口创立一个实现类:com.itheima.driver.feign.fallback.DriverFeignFallback,在实现类中处理程序异样降级解决办法,代码如下:

package com.itheima.driver.feign.fallback;

import com.itheima.driver.feign.DriverFeign;
import com.itheima.driver.model.Driver;
import org.springframework.stereotype.Component;

@Component
public class DriverFeignFallback implements DriverFeign {

    /**
     * status()降级解决办法
     */
    @Override
    public Driver status(String id, Integer status) {Driver driver = new Driver();
        driver.setId(id);
        driver.setStatus(status);
        driver.setName("零碎比拟忙碌,请您稍后再试!");
        return driver;
    }
}

2、在 DriverFeign 接口上增加 fallback 属性指定降级解决的类,代码如下:

@FeignClient(value = "hailtaxi-driver",fallback = DriverFeignFallback.class)

留神:批改了 hailtaxi-api 模块,最好cleanpackage!!

3、启动运行,会产生如下问题:

java.lang.AbstractMethodError: com.alibaba.cloud.sentinel.feign.SentinelContractHolder.parseAndValidatateMetadata(Ljava/lang/Class;)Ljava/util/List;

呈现下面问题的次要起因是以后 SpringCloud 版本存在问题。

Hoxton.SR1 中,fegin.context接口办法的定义为 parseAndValidatateMetadata
Hoxton.SR3 中,fegin.context 接口办法的定义为parseAndValidateMetadata

咱们当初须要把 Hoxton.SR1 换成 Hoxton.SR3,因而须要在hailtaxi-parent 批改 SpringCloud 版本:

SpringCloud 版本升级至 Hoxton.SR3 同时将 SpringBoot 版本升级至2.2.10,如上图:

https://github.com/spring-clo…

此时咱们测试,成果如下:

2.3.2 fallbackFactory

咱们能够为 DriverFeign 接口创立一个降级解决的工厂对象,在工厂对象中处理程序异样降级解决办法,用工厂对象解决能够拿到异样信息,代码如下:

1、创立:com.itheima.driver.feign.fallback.DriverFeignFallbackFactory

package com.itheima.driver.feign.fallback;

import com.itheima.driver.feign.DriverFeign;
import com.itheima.driver.model.Driver;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;

@Component
public class DriverFeignFallbackFactory implements FallbackFactory<DriverFeign> {
    @Override
    public DriverFeign create(Throwable throwable) {return new DriverFeign() {
            /**
             * status()降级解决办法
             */
            @Override
            public Driver status(String id, Integer status) {Driver driver = new Driver();
                driver.setId(id);
                driver.setStatus(status);
                driver.setName("零碎比拟忙碌,请您稍后再试!");
                return driver;
            }
        };
    }
}

2、在 DriverFeign 接口上增加 fallbackFactory 属性指定解说解决的类,代码如下:

@FeignClient(value = "hailtaxi-driver",fallbackFactory = DriverFeignFallbackFactory.class)

3、再次启动测试,成果如下:

好了,接下来,咱么来说一说 Sentinel 控制台

4 Sentinel 控制台

Sentinel 控制台是流量管制、熔断降级规定对立配置和治理的入口,它为用户提供了机器自发现、簇点链路自发现、监控、规定配置等性能。在 Sentinel 管制台上,咱们能够配置规定并实时查看流量管制成果。

4.1 Sentinel 控制台装置

Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及衰弱状况治理、监控(单机和集群),规定治理和推送的性能。

Sentinel 控制台蕴含如下性能:

  • 查看机器列表以及衰弱状况:收集 Sentinel 客户端发送的心跳包,用于判断机器是否在线。
  • 监控 (单机和集群聚合):通过 Sentinel 客户端裸露的监控 API,定期拉取并且聚合利用监控信息,最终能够实现秒级的实时监控。
  • 规定治理和推送:对立治理推送规定。
  • 鉴权:生产环境中鉴权十分重要。这里每个开发者须要依据本人的理论状况进行定制。

Sentinel 控制台装置能够基于 jar 包启动的形式装置,也能够基于 docker 装置,为了不便操作,咱们这里采纳 docker 装置形式:

docker run --name=sentinel-dashboard -d -p 8858:8858 -d --restart=on-failure bladex/sentinel-dashboard:1.8.0

装置好了后,咱们能够间接拜访 http://192.168.200.129:8858/,默认用户名和明码都是 sentinel

登录后,成果如下:

4.2 接入控制台

客户端须要引入 Transport 模块来与 Sentinel 控制台进行通信,能够通过 pom.xml 引入 JAR 包:

<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>x.y.z</version>
</dependency>

如果是 SpringBoot 工程接入 Sentinel,能够间接引入如下依赖包:

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

hailtaxi-gateway 接入控制台:

1、引入依赖包:

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

2、在外围配置文件中配置 Sentinel 控制台服务地址

spring:
  cloud:
    sentinel:
      transport:
        port: 8719
        dashboard: 192.168.200.129:8858

留神:

1、这里的 spring.cloud.sentinel.transport.port 端口配置会在利用对应的机器上启动一个 Http Server,该 Server 会与 Sentinel 控制台做交互,比方限流规定拉取。

2、配置信息当初是存储到 nacos 中,故要在 nacos 中找到hailtaxi-gateway.yaml,进行如下配置

批改之后记得公布!

3、启动各个服务,

此时咱们登程一些申请操作,再看 Sentinel 控制台会多一个服务监控:

4.3 可视化治理

4.3.1 实时监控

同一个服务下的所有机器的簇点信息会被汇总,并且秒级地展现在 ” 实时监控 ” 下。

留神: 实时监控仅存储 5 分钟以内的数据,如果须要长久化,须要通过调用实时监控接口来定制。

如果要获取监控数据,间接调用 http://localhost:8719/cluster… 即可获取,成果如下:

4.3.2 流控规定

咱们能够在【流控规定】页面中新增,点击【流控规定】进入页面新增页面,如下图:

资源名:其实能够和申请门路保持一致,这里的流控模式为 QPS,触发流控执行阈值为 1,流控模式为让以后申请的资源疾速直白。

这里的参数和咱们程序中的参数其实是一样的,如下阐明:

resource:资源名,即限流规定的作用对象
count: 限流阈值
grade: 限流阈值类型(QPS 或并发线程数)limitApp: 流控针对的调用起源,若为 default 则不辨别调用起源
strategy: 调用关系限流策略:间接,关联,链路
controlBehavior: 流量管制成果(间接回绝、Warm Up、匀速排队)

咱们测试成果如下:

4.3.3 降级规定

咱们能够抉择 降级规定 > 新增降级规定,如下图:

降级规定的熔断策略有 3 种,别离是慢调用比例、异样比例、异样数,和程序中是一样的。

4.3.4 热点数据

热点即常常拜访的数据。很多时候咱们心愿统计某个热点数据中拜访频次最高的 Top K 数据,并对其拜访进行限度。

拓展知识点:

留神:如果流控模式是链路模式,须要引入如下依赖:

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-web-servlet</artifactId>
    <version>1.8.0</version>
</dependency>

创立过滤器:

/***
 * CommonFilter 过滤器
 * @return
 */
@Bean
public FilterRegistrationBean sentinelFilterRegistration() {FilterRegistrationBean registration = new FilterRegistrationBean();
    registration.setFilter(new CommonFilter());
    registration.addUrlPatterns("/*");    // 过滤所有申请
    // 入口资源敞开聚合
    registration.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "false");
    registration.setName("sentinelFilter");
    registration.setOrder(1);
    return registration;
}

bootstrap.yml 配置:web-context-unify: false

  cloud:
    sentinel:
      transport:
        port: 8719
        dashboard: localhost:8858
      web-context-unify: false  #可依据不同的 URL 进行链路限流

本文由传智教育博学谷 – 狂野架构师教研团队公布
转载请注明出处!

退出移动版