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 应用 @SentinelResource
的blockHandler
返回默认错误信息,造成 降级!!!
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
异样才调用,此时能够应用 @SentinelResource
的fallback
属性,代码如下:
/****
* 司机信息
*/
@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-driver
的DriverApplication
启动类上增加如下办法加载限流规定,当 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-driver
的DriverApplication
中创立如下办法,代码如下:
/***
* 零碎自我爱护
*/
@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-driver
的DriverApplication
中创立如下办法,代码如下:
@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 | 集群流控相干配置 |
咱们能够通过 ParamFlowRuleManager
的 loadRules
办法更新热点参数规定
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#initAuthorityRule
,DriverApplication#initSystemRule
上的注解即可
1、在 hailtaxi-order
中引入 sentinel
和OpenFeign
依赖,配置如下:
<!--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-gateway
,hailtaxi-order
,hailtaxi-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
模块,最好clean
,package
!!
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 进行链路限流
本文由传智教育博学谷 – 狂野架构师教研团队公布
转载请注明出处!