九:服务熔断功能(Fallback 和 BlockHandler)
1)Sentinel 整合 Ribbon + OpenFeign + fallback:
2)Ribbon 系列:
a:启动 nacos 和 Sentinel;
b:提供者 9003/9004:
- 新建 Module:cloud-alibaba-provider-payment-9003 / 9004(两个做法一样)
- POM:nacos、common、sentinal
- YML:再加上 Sentinel 的
- 主启动:
- 业务类:
- 测试地址:http://127.0.0.1:9003/getPayment?id=2
c:消费者 84:
- 新建 Module:cloud-alibaba-consumer-nacos-order-84
- POM:
- YML:
- 主启动:
- 业务类:
1.配置 RestTemplate @LoadBalance
2.修改后,重启服务:热部署对 java 代码及时生效,对 @SentinelResource 注解有时效果不好,所以重启;
3.目的:
fallback:管运行异常,java 异常(报错)(RuntimeException)
blockHandler:管配置违规(限流)(必须配置在 资源名称 上 才生效)(配置了熔断,达到熔断条件 会进入 blockHandler)
4.测试地址:(访问:localhost:84/orderController?id=2)达到轮询效果
5.没有任何配置:
6.只配置 fallback:(抛出异常时,走兜底方法)(管java 运行时异常)
@RestController
public class OrderComsumerController {
private static final String str = "http://cloud-alibaba-provider-payment";
@Autowired
private RestTemplate restTemplate;
@GetMapping(value = "/orderController")
@SentinelResource(value = "orderController", fallback = "fallback_orderController")
public CommonResult orderController(@RequestParam(value = "id") Long id) {
CommonResult commonResult = restTemplate.getForObject(str + "/getPayment?id=" + id, CommonResult.class);
if (4 == id) {
throw new IllegalArgumentException("传入参数异常");
} else if (commonResult == null) {
throw new NullPointerException("未查询到 结构");
}
return commonResult;
}
public CommonResult fallback_orderController(@RequestParam(value = "id") Long id,
Throwable throwable) {
return new CommonResult(401, "fallback 兜底方法 : " + throwable);
}
}
7.只配置 blockHandler:若本次访问被限流或服务降级熔断,则调用blockHandler指定的接口;配置了熔断,达到熔断条件 会进入 blockHandler;管 控制台配置违规
@RestController
public class OrderComsumerController {
private static final String str = "http://cloud-alibaba-provider-payment";
@Autowired
private RestTemplate restTemplate;
@GetMapping(value = "/orderController")
@SentinelResource(value = "orderController", blockHandler = "block_orderController")
public CommonResult orderController(@RequestParam(value = "id") Long id) {
CommonResult commonResult = restTemplate.getForObject(str + "/getPayment?id=" + id, CommonResult.class);
if (4 == id) {
throw new IllegalArgumentException("传入参数异常");
} else if (commonResult == null) {
throw new NullPointerException("未查询到 结构");
}
return commonResult;
}
public CommonResult block_orderController(@RequestParam(value = "id") Long id,
BlockException blockException) {
return new CommonResult(402, "blockHandler 限流 降级方法 : " + blockException);
}
}
8.fallback 和 blockHandler 都配置:(也就是 先 限流,后 进入程序;)
一个管java,一个管 控制台配置违规; fallback 达到控制台阈值,会触发 blockHandler 熔断异常
@RestController
public class OrderComsumerController {
private static final String str = "http://cloud-alibaba-provider-payment";
@Autowired
private RestTemplate restTemplate;
@GetMapping(value = "/orderController")
@SentinelResource(value = "orderController",
fallback = "fallback_orderController",
blockHandler = "block_orderController")
public CommonResult orderController(@RequestParam(value = "id") Long id) {
CommonResult commonResult = restTemplate.getForObject(str + "/getPayment?id=" + id, CommonResult.class);
if (4 == id) {
throw new IllegalArgumentException("传入参数异常");
} else if (commonResult == null) {
throw new NullPointerException("未查询到 结构");
}
return commonResult;
}
public CommonResult fallback_orderController(@RequestParam(value = "id") Long id,
Throwable throwable) {
return new CommonResult(401, "fallback 兜底方法 : " + throwable);
}
public CommonResult block_orderController(@RequestParam(value = "id") Long id,
BlockException blockException) {
return new CommonResult(402, "blockHandler 限流 降级方法 : " + blockException);
}
}
9.忽略属性:排除 个别异常,排除的异常,不进入 fallback 方法,直接返回错误页面;
编码:
结果:(携带参数 为 4,直接返回错误页面,不走 fallback 兜底方法;)
@GetMapping(value = "/orderController")
@SentinelResource(value = "orderController",
fallback = "fallback_orderController",
blockHandler = "block_orderController",
exceptionsToIgnore = {IllegalArgumentException.class})
public CommonResult orderController(@RequestParam(value = "id") Long id) {
CommonResult commonResult = restTemplate.getForObject(str + "/getPayment?id=" + id, CommonResult.class);
if (4 == id) {
throw new IllegalArgumentException("传入参数异常");
} else if (commonResult == null) {
throw new NullPointerException("未查询到 结构");
}
return commonResult;
}
3)Feign 系列:
a:修改 84 模块:
- 84 消费者,调用 提供者 9003;
- feign 组件一般是 消费侧;
b:POM:引入 Openfiegn
c:YML:激活 Feign
feign:
sentinel:
enabled: true
d:主启动:@EnableFeignClients
e:业务类:(主要是配置 兜底方法)
@FeignClient(value = "cloud-alibaba-provider-payment",
fallback = PaymentFallbackService.class)
public interface PaymentService {
@GetMapping(value = "/getPayment")
CommonResult getPayment(@RequestParam(value = "id") Long id);
}
@Component
public class PaymentFallbackService implements PaymentService {
@Override
public CommonResult getPayment(Long id) {
return new CommonResult(401, "fallback_serviceOrder() : " + id);
}
}
f:测试:(访问:localhost:84/serviceOrderController?id=2)
84 调用 9003/9004 ;此时 关闭 9003/9004,看 84 反应;(返回 fallback 兜底方法)
这个是 openFeign 指定的 降级方法,和 Sentinel 无关;如果出现异常,不会走 fallback 方法;
g:在 Controller 配置 blockHandler 方法:(流量控制 时,会返回 此方法)
@RestController
public class OrderComsumerController_02 {
@Autowired
private PaymentService paymentService;
@GetMapping(value = "/serviceOrderController")
@SentinelResource(value = "serviceOrderController")
public CommonResult serviceOrderController(@RequestParam("id") Long id) {
CommonResult commonResult = paymentService.getPayment(id);
if (4 == id) {
throw new IllegalArgumentException("传入参数异常");
} else if (commonResult == null) {
throw new NullPointerException("未查询到 结构");
}
return commonResult;
}
}
@Component
public class PaymentBlockHandlerService implements PaymentService {
@Override
public CommonResult getPayment(Long id) {
return new CommonResult(402, "blockHandler_serviceOrder() : " + id);
}
}
4)熔断框架比较:
十:规则持久化
1)是什么:
a:一旦我们 项目重启,sentinel 规则 将消失,生产环节需要将配置规则 进行持久化;
2)怎么玩:
a:将 限流配置规则 持久化 进 Nacos 保存,只要刷新 8401 某个 rest 地址,
b:Sentinel 控制台的流控规则 就能看到,只要 Nacos 里面的配置不删除,
c:针对 8401 上的 Sentinel 的流控规则 就持续有效;
3)步骤:
a:修改 8401:
b:POM:
<!-- 后续 持久化 用到 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
c:YML:
server:
port: 8401
spring:
application:
name: cloud-alibaba-sentinel-service-8401
cloud:
nacos:
discovery:
server-addr: 114.215.173.88:8848
sentinel:
transport:
# 配置 sentinel dashboard 地址
dashboard: 192.168.43.44:8080
# 默认 以 8719 端口,假如被占用,会自动从 8719 开始,
# 依次 +1 扫描,直到找到未被占用的端口
port: 8719
datasource:
ds1:
nacos:
serverAddr: 114.215.173.88:8848
dataId: ${spring.application.name}
groupId: DEFAULT_GROUP
dataType: json
ruleType: flow
management:
endpoints:
web:
exposure:
include: '*'
d:添加 Nacos 业务规则配置:新建配置
e:启动 8401 后,刷新 sentinel ,发现 业务规则有了:
f:快速访问 测试借口:(限流规则,马上生效)
g:停止 8401 ,在看 Sentinel:
h:重新启动 8401 在看 Sentinel 配置规则是否存在:存在