Version: Next
Sentinel 服务熔断
Sentinel 整合
Ribbon、OpenFeign
环境准备
准备——新建一些模块
- 两个服务提供者
provider-payment9003、9004- 一个服务消费者
consumer-order8484通过Nacos找到9003、9004的真实地址,通过Ribbon负载均衡的进行访问
Cloudalibaba-provider-payment9003
- POM
- YAML
- 主启动
- 业务类
<dependencies>
<!-- SpringCloud ailibaba nacos-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- SpringCloud ailibaba sentinel-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency><!-- 引用自己定义的api通用包,可以使用Payment支付Entity -->
<groupId>org.example</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--监控-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Cloudalibaba-provider-payment9004
- 照着 9003 弄一个,改一下端口号
Cloudalibaba-consumer-nacos-order84
- POM
- YAML
- 主启动
- 业务类
<dependencies>
<!-- SpringCloud ailibaba nacos-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- SpringCloud ailibaba sentinel-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency><!-- 引用自己定义的api通用包,可以使用Payment支付Entity -->
<groupId>org.example</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--监控-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
服务熔断无配置
- 重启
9003、9004- 启动
84- 访问
http://localhost:84/consumer/fallback/1,得到正常响应,且可以看到9003、9004两个节点在轮询负载均衡
- 再看
order84Controller 中的业务代码- 当
id为1、2、3时,能到9003、9004查到数据正常返回 - 当为
4抛出一个非法参数异常 - 如果是
1、2、3、4以外的数字,会跑去9003、9004查,然后啥也查不到,得到的响应中data为空,于是84自己抛出一个空指针异常 - 上述两个异常都是 Java 层面的,后续就是演示用
fallback属性来处理它们
- 当
@RequestMapping("/consumer/fallback/{id}")
@SentinelResource(value = "fallback")
// @SentinelResource(value = "fallback",fallback ="handlerFallback")
// 异常忽略 exceptionsToTrace = IllegalArgumentException.class 忽略指定的异常
// @SentinelResource(value = "fallback", fallback = "handlerFallback", blockHandler = "blockHandler")
public CommonResult<Payment> fallback(@PathVariable Long id) {
CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/" + id, CommonResult.class, id);
if (id == 4) {
throw new IllegalArgumentException("IllegalArgument ,非法参数异常...");
} else if (result.getData() == null) {
throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常");
}
return result;
}
服务熔断只配置 fallback
@SentinelResource加上fallback属性
fallback属性指定一个兜底方法@RequestMapping("/consumer/fallback/{id}")// @SentinelResource(value = "fallback")@SentinelResource(value = "fallback", fallback = "handlerFallback")// 异常忽略 exceptionsToTrace = IllegalArgumentException.class 忽略指定的异常// @SentinelResource(value = "fallback", fallback = "handlerFallback", blockHandler = "blockHandler")public CommonResult<Payment> fallback(@PathVariable Long id) {CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/" + id, CommonResult.class, id);if (id == 4) {throw new IllegalArgumentException("IllegalArgument ,非法参数异常...");} else if (result.getData() == null) {throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常");}return result;}// 兜底方法public CommonResult handlerFallback(@PathVariable Long id, Throwable e) {Payment payment = new Payment(id, "null");return new CommonResult(444, "异常handlerFallback,exception内容: " + e.getMessage(), payment);}
- 访问
http://localhost:84/consumer/fallback/4,触发了兜底方法,打印了自定义异常信息,屏蔽了 500 错误及异常信息栈- 访问
http://localhost:84/consumer/fallback/5,触发了兜底方法,打印了自定义异常信息,屏蔽了 500 错误及异常信息栈
- id 4 兜底响应
- id 5 兜底响应
{"code": 444,"message": "异常handlerFallback,exception内容: IllegalArgument ,非法参数异常...","data": {"id": 4,"serial": "null"}}
服务熔断只配置 blockHandler
@RequestMapping("/consumer/fallback/{id}")
// @SentinelResource(value = "fallback")
// @SentinelResource(value = "fallback", fallback = "handlerFallback")
// 异常忽略 exceptionsToTrace = IllegalArgumentException.class 忽略指定的异常
@SentinelResource(value = "fallback", blockHandler = "blockHandler")
// @SentinelResource(value = "fallback", fallback = "handlerFallback", blockHandler = "blockHandler")
public CommonResult<Payment> fallback(@PathVariable Long id) {
CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/" + id, CommonResult.class, id);
if (id == 4) {
throw new IllegalArgumentException("IllegalArgument ,非法参数异常...");
} else if (result.getData() == null) {
throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常");
}
return result;
}
public CommonResult blockHandler(@PathVariable Long id, BlockException e) {
Payment payment = new Payment(id, "null");
return new CommonResult(444, "blockHandler-sentinel 限流,BlockException: " + e.getMessage(), payment);
}
添加 Sentinel 配置
- 给资源名
fallback添加降级规则测试
- 访问
http://localhost:84/consumer/fallback/4- Java 异常会直接以 500 报文响应
- 疯狂访问,触发降级,得到
blockHandler方法执行后的响应结果
服务熔断两个都配
@RequestMapping("/consumer/fallback/{id}")
// @SentinelResource(value = "fallback")
// @SentinelResource(value = "fallback", fallback = "handlerFallback")
// 异常忽略 exceptionsToTrace = IllegalArgumentException.class 忽略指定的异常
// @SentinelResource(value = "fallback", blockHandler = "blockHandler")
@SentinelResource(value = "fallback", fallback = "handlerFallback", blockHandler = "blockHandler")
public CommonResult<Payment> fallback(@PathVariable Long id) {
CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/" + id, CommonResult.class, id);
if (id == 4) {
throw new IllegalArgumentException("IllegalArgument ,非法参数异常...");
} else if (result.getData() == null) {
throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常");
}
return result;
}
public CommonResult handlerFallback(@PathVariable Long id, Throwable e) {
Payment payment = new Payment(id, "null");
return new CommonResult(444, "异常handlerFallback,exception内容: " + e.getMessage(), payment);
}
public CommonResult blockHandler(@PathVariable Long id, BlockException e) {
Payment payment = new Payment(id, "null");
return new CommonResult(444, "blockHandler-sentinel 限流,BlockException: " + e.getMessage(), payment);
}
Java的错误会触发fallback- 违反 Sentinel 设置会触发
blockHandler如果一个请求把两个都触发了会发生什么?
- 执行的是
blockHandler,因为 Sentinel 的限流直接阻止了方法的执行,根本执行不到fallback
异常忽略
使用:exceptionsToTrace 属性指定要忽略的异常类型
exceptionsToTrace = IllegalArgumentException.class 忽略指定的异常
@RequestMapping("/consumer/fallback/{id}")
// @SentinelResource(value = "fallback")
// @SentinelResource(value = "fallback", fallback = "handlerFallback")
// 异常忽略 exceptionsToTrace = IllegalArgumentException.class 忽略指定的异常
// @SentinelResource(value = "fallback", blockHandler = "blockHandler")
// @SentinelResource(value = "fallback", fallback = "handlerFallback", blockHandler = "blockHandler")
@SentinelResource(value = "fallback", fallback = "handlerFallback", blockHandler = "blockHandler",exceptionsToIgnore = IllegalArgumentException.class)
public CommonResult<Payment> fallback(@PathVariable Long id) {
CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/" + id, CommonResult.class, id);
if (id == 4) {
throw new IllegalArgumentException("IllegalArgument ,非法参数异常...");
} else if (result.getData() == null) {
throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常");
}
return result;
}
public CommonResult handlerFallback(@PathVariable Long id, Throwable e) {
Payment payment = new Payment(id, "null");
return new CommonResult(444, "异常handlerFallback,exception内容: " + e.getMessage(), payment);
}
public CommonResult blockHandler(@PathVariable Long id, BlockException e) {
Payment payment = new Payment(id, "null");
return new CommonResult(444, "blockHandler-sentinel 限流,BlockException: " + e.getMessage(), payment);
}
整合 OpenFeign
- 修改
order84
- POM
- YAML
- 主启动
- 业务类
- 引入 OpenFeign ,之前引入过了
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
测试
- 只启动
9003- 重启
84- 访问
http://localhost:84/consumer/paymentSQL/1,可以得到正常响应,来自9003测试服务降级
- 把
9003关了,继续访问,当调用到9003时,因为9003挂了,OpenFeign 的调用就会出问题- 应当触发定义的自定义兜底类
{"code": 444,"message": "服务降级返回,---PaymentFallbackService","data": {"id": 1,"serial": "ErrorSerial"}}
