文章目录
一、服务熔断功能
1. Ribbon系列
参考代码:码云 注意提交记录
1.1 整体流程
1.2 配置
- 启动nacos和sentinel
- 服务提供者cloudalibaba-provider-payment9003/9004 配置和正常的服务提供者一样
- 测试所用的controller
@RestController
public class PaymentController
{
@Value("${server.port}")
private String serverPort;
public static HashMap<Long, Payment> hashMap = new HashMap<>();
static{
hashMap.put(1L,new Payment(1L,"28a8c1e3bc2742d8848569891fb42181"));
hashMap.put(2L,new Payment(2L,"bba8c1e3bc2742d8848569891ac32182"));
hashMap.put(3L,new Payment(3L,"6ua8c1e3bc2742d8848569891xt92183"));
}
@GetMapping(value = "/paymentSQL/{id}")
public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id){
Payment payment = hashMap.get(id);
CommonResult<Payment> result = new CommonResult(200,"from mysql,serverPort: "+serverPort,payment);
return result;
}
}
- 消费端 cloudalibaba-consumer-nacos-order84
主要配置
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</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>
server:
port: 84
spring:
application:
name: nacos-order-consumer
cloud:
nacos:
discovery:
server-addr: localhost:8848
sentinel:
transport:
dashboard: localhost:8080
port: 8719
service-url:
nacos-user-service: http://nacos-payment-provider
- 消费端的controller
@RestController
@Slf4j
public class CircleBreakerController {
public static final String SERVICE_URL = "http://nacos-payment-provider";
@Resource
private RestTemplate restTemplate;
//======= OpenFeign
@Resource
private PaymentServiceFeign paymentServiceFeign;
@RequestMapping("/consumer/fallback/{id}")
// @SentinelResource(value = "fallback") //没有任何配置
// @SentinelResource(value = "fallback",fallback ="handlerFallback") //fallback只负责业务异常
@SentinelResource(value = "fallback", fallback = "handlerFallback", blockHandler = "blockHandler") //blockHandler只负责Sentinel控制台配置违规
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);
}
}
- 消费端的RestTemplate(远程调用)配置负载均衡
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
1.3 测试
1.3.1没有任何配置
http://localhost:84/consumer/fallback/4
前提没有限流和降级处理 出现异常直接返回Errorpage
1.3.2只配置fallback
处理业务中的异常
@RequestMapping("/consumer/fallback/{id}")
@SentinelResource(value = "fallback",fallback ="handlerFallback") //fallback只负责业务异常
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没有对应记录,空指针异常");
}
}
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 一定会出现异常
并没有返回异常页面 而是调用handlerFallback方法
SentinelResource
的·fallback·:针对于方法级别的处理 注意:方法的返回值请求参数对应 并且添加一个异常方法Throwable e
springmvc
:全局异常异常处理:针对于异常类型进行处理
配置fallback出现异常走指定的fallback方法 控制台不会进行打印异常
1.3.3只配置blockHandler
@RequestMapping("/consumer/fallback/{id}")
@SentinelResource(value = "fallback", blockHandler = "blockHandler")//blockHandler只负责Sentinel控制台配置违规
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);
}
访问localhost:84/consumer/fallback/4 一定会抛出异常
第一次访问
第二次 访问 和第一次一样
第三次访问
已经进行熔断了
1.3.4 fallback和blockHandler都配置
前两次使用fallback
两次异常触发了降级 使用blockHandler方法
1.3.5 结论
fallback:只负责业务异常
blockHandle:只负责Sentinel控制台配置违规 使用该属性只是替换默认的违规提示
参考博文:你知道Sentinel限流、降级的统一处理吗?
2. Feign系列
pom
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
yml
#对Feign的支持
feign:
sentinel:
enabled: true
//远程调用service
//fallback 熔断调用的类
@FeignClient(value = "nacos-payment-provider",fallback = PaymentFallbackService.class)
public interface PaymentService
{
@GetMapping(value = "/paymentSQL/{id}")
public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
}
//熔断实现类
@Component
public class PaymentFallbackService implements PaymentService
{
@Override
public CommonResult<Payment> paymentSQL(Long id)
{
return new CommonResult<>(44444,"服务降级返回,---PaymentFallbackService",new Payment(id,"errorSerial"));
}
}
二、熔断框架对比
同类组件功能对比
Sentinel | Hystrix | resilience4j | |
---|---|---|---|
隔离策略 | 信号量隔离(并发控制) | 线程池隔离/信号量隔离 | 信号量隔离 |
熔断降级策略 | 基于慢调用比例、异常比例、异常数 | 基于异常比例 | 基于异常比例、响应时间 |
实时统计实现 | 滑动窗口(LeapArray) | 滑动窗口(基于 RxJava) | Ring Bit Buffer |
动态规则配置 | 支持近十种动态数据源 | 支持多种数据源 | 有限支持 |
扩展性 | 多个扩展点 | 插件的形式 | 接口的形式 |
基于注解的支持 | 支持 | 支持 | 支持 |
单机限流 | 基于 QPS,支持基于调用关系的限流 | 有限的支持 | Rate Limiter |
集群流控 | 支持 | 不支持 | 不支持 |
流量整形 | 支持预热模式与匀速排队控制效果 | 不支持 | 简单的 Rate Limiter 模式 |
系统自适应保护 | 支持 | 不支持 | 不支持 |
热点识别/防护 | 支持 | 不支持 | 不支持 |
多语言支持 | Java/Go/C++ | Java | Java |
Service Mesh 支持 | 支持 Envoy/Istio | 不支持 | 不支持 |
控制台 | 提供开箱即用的控制台,可配置规则、实时监控、机器发现等 | 简单的监控查看 | 不提供控制台,可对接其它监控系统 |
三、持久化
maven配置
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
yml配置
spring:
application:
name: cloudalibaba-sentinal-service
cloud:
nacos:
discovery:
#Nacos服务注册中心地址
server-addr: localhost:8848
sentinel:
transport:
#配置Sentin dashboard地址
dashboard: localhost:8080
port: 8719 # 默认8719端口,假如被占用了会自动从8719端口+1进行扫描,直到找到未被占用的 端口
datasource: #持久化配置
ds1:
nacos:
server-addr: localhost:8848
dataId: cloudalibaba-sentinel-service
groupId: DEFAULT_GROUP
data-type: json
rule-type: flow
nacos中
[
{
"resource": "/retaLimit/byUrl",
"limitApp": "default",
"grade": 1,
"count": 1,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]
启动8401后刷新sentinel发现业务规则有了
结论:
会把nacos中配置的同步到sentinel 注意在sentinel界面中配置的不会添加到nacos中