Version: Next
Sentinel 服务熔断
Sentinel 整合
Ribbon
、OpenFeign
环境准备
准备——新建一些模块
- 两个服务提供者
provider-payment9003
、9004
- 一个服务消费者
consumer-order84
84
通过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
两个节点在轮询负载均衡
- 再看
order84
Controller 中的业务代码- 当
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"}}