这是我参与更文挑战的第 20 天,活动详情查看: 更文挑战
Sentinel
六、@SentinelResource
根据资源名称做流控
代码
@RestController
public class RateLimitController {
@GetMapping("/byResource")
@SentinelResource(value = "byResource",blockHandler = "handlerException")
public ResultDto byResource() {
System.out.println("byResource");
return new ResultDto(200,"byResource",new Payment(2020L,"PaymentOne"));
}
public ResultDto handlerException(BlockException e) {
System.out.println("deal_byResource");
return new ResultDto(500,e.getClass().getCanonicalName());
}
}
资源名称为byResource
配置
如果超出QPS,就会进入到自定义的handlerException方法。如果是按照URL做流控,那么资源名就应该为/byResource
自定义限流处理
把业务代码和blockHandler代码分开
业务代码
@GetMapping("/customerBlockHandler")
@SentinelResource(value = "customerBlockHandler",
blockHandlerClass = CustomerBlockHandler.class,blockHandler = "customerBlockHandler")
public ResultDto customerBlockHandler() {
System.out.println("customerBlockHandler");
return new ResultDto(200,"自定义customerBlockHandler");
}
CustomerBlockHandler
public class CustomerBlockHandler {
public static ResultDto customerBlockHandler(BlockException e) {
return new ResultDto(500,"自定义CustomerBlockHandler---1");
}
public static ResultDto customerBlockHandler2(BlockException e) {
return new ResultDto(500,"自定义CustomerBlockHandler---2");
}
}
此时触发流控规则,就会调用blockHandlerClass指定的类中的blockHandler指定的方法。
注解属性说明
注意:注解方式埋点不支持 private 方法。
@SentinelResource 用于定义资源,并提供可选的异常处理和 fallback 配置项。 @SentinelResource 注解包含以下属性:
-
value:资源名称,必需项(不能为空) -
entryType:entry 类型,可选项(默认为EntryType.OUT) -
blockHandler/blockHandlerClass:blockHandler对应处理BlockException的函数名称,可选项。blockHandler 函数访问范围需要是public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为BlockException。blockHandler 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定blockHandlerClass为对应的类的Class对象,注意对应的函数必需为 static 函数,否则无法解析。 -
fallback:fallback 函数名称,可选项,用于在抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常(除了
exceptionsToIgnore里面排除掉的异常类型)进行处理。fallback 函数签名和位置要求:
- 返回值类型必须与原函数返回值类型一致;
- 方法参数列表需要和原函数一致,或者可以额外多一个
Throwable类型的参数用于接收对应的异常。 - fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定
fallbackClass为对应的类的Class对象,注意对应的函数必需为 static 函数,否则无法解析。
-
defaultFallback(since 1.6.0):默认的 fallback 函数名称,可选项,通常用于通用的 fallback 逻辑(即可以用于很多服务或方法)。默认 fallback 函数可以针对所以类型的异常(除了
exceptionsToIgnore里面排除掉的异常类型)进行处理。若同时配置了 fallback 和 defaultFallback,则只有 fallback 会生效。defaultFallback 函数签名要求:
- 返回值类型必须与原函数返回值类型一致;
- 方法参数列表需要为空,或者可以额外多一个
Throwable类型的参数用于接收对应的异常。 - defaultFallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定
fallbackClass为对应的类的Class对象,注意对应的函数必需为 static 函数,否则无法解析。
-
exceptionsToIgnore(since 1.6.0):用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。
注:1.6.0 之前的版本 fallback 函数只针对降级异常(
DegradeException)进行处理,不能针对业务异常进行处理。
特别地,若 blockHandler 和 fallback 都进行了配置,则被限流降级而抛出 BlockException 时只会进入 blockHandler 处理逻辑。若未配置 blockHandler、fallback 和 defaultFallback,则被限流降级时会将 BlockException 直接抛出。
七、服务熔断
Sentinel整合Ribbon+openFeign+fallback
环境搭建
服务提供者cloudalibaba-provider-payment9003/9004
依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
配置
server:
port: 9003
spring:
application:
name: nacos-provider-payment
cloud:
nacos:
discovery:
server-addr: localhost:8848 # nacos配置中心地址
management: # 暴露监控地址
endpoints:
web:
exposure:
include: '*'
业务
@RestController
public class PaymentController {
@Value("${server.port}")
private String port;
public static HashMap<Long, Payment> hashMap = new HashMap<>();
static {
hashMap.put(1L,new Payment(1L,"111111111111111"));
hashMap.put(2L,new Payment(2L,"222222222222222"));
hashMap.put(3L,new Payment(3L,"333333333333333"));
}
@GetMapping("/payment/{id}")
public ResultDto<Payment> customerBlockHandler(@PathVariable("id") Long id) {
Payment payment = hashMap.get(id);
return new ResultDto<Payment>(200,"---customerBlockHandler---" + port + "---",payment);
}
}
在9003的基础上copy一个9004
服务消费者cloudalibaba-consumer-nacos-order84
依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
配置
server:
port: 84
spring:
application:
name: nacos-consumer-order
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # nacos配置中心地址
sentinel:
transport:
dashboard: localhost:8080
# 默认8719端口,如果被占用自动从8719开始一次+1扫描,找到未被占用的端口
port: 8719
service-url: #可选,用户访问的微服务名称
nacos-user-service: http://nacos-provider-payment
config
@SpringBootConfiguration
public class ApplicationContextConfig {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
业务
@RestController
public class CircleBreakerController {
public final static String SERVER_URL = "http://nacos-provider-payment";
@Resource
private RestTemplate restTemplate;
@RequestMapping("/consumer/fallback/{id}")
@SentinelResource("fallback") //没有配置
public ResultDto<Payment> fallback(@PathVariable("id") Long id) {
ResultDto<Payment> result = restTemplate.getForObject(SERVER_URL + "/payment/" + id, ResultDto.class, id);
if (result.getData() == null) {
throw new NullPointerException("null");
}
return result;
}
}
服务熔断测试
没有指定任何fallback方法,直接把异常信息返回。
配置fallback方法
@RequestMapping("/consumer/fallback/{id}")
@SentinelResource(value = "fallback",fallback = "fallbackMethod")
public ResultDto<Payment> fallback(@PathVariable("id") Long id) {
...
}
public ResultDto<String> fallbackMethod(@PathVariable("id") Long id,Throwable e) {
return new ResultDto<>(500,"fallbackMethod---" + e + "---" +id);
}
代码中出现异常后调用fallbackMethod兜底方法。
配置blockHandler方法
@RequestMapping("/consumer/fallback/{id}")
@SentinelResource(value = "fallback",blockHandler = "blockHandlerMethod")
public ResultDto<Payment> fallback(@PathVariable("id") Long id) {
...
}
public ResultDto<String> blockHandlerMethod(@PathVariable("id") Long id, BlockException e) {
return new ResultDto<>(500,"blockMethod---" + e + "---" +id);
}
blockHandler只有在Sentinel控制台配置的限制触发后才会调用blockHandler的方法。
配置fallback方法和blockHandler方法
两个可以都生效,如有冲突控制台的控制和blockHandler会优先生效。
配置exceptionsToIgnore(异常忽略)方法
@RequestMapping("/consumer/fallback/{id}")
@SentinelResource(value = "fallback",blockHandler = "blockHandlerMethod",exceptionsToIgnore = {NullPointerException.class})
public ResultDto<Payment> fallback(@PathVariable("id") Long id) {
...
}
public ResultDto<String> blockHandlerMethod(@PathVariable("id") Long id, BlockException e) {
return new ResultDto<>(500,"blockMethod---" + e + "---" +id);
}
此时如果再次出现exceptionsToIgnore异常,就不会走blockHandler方法
服务熔断OpenFeign
依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
配置
# 激活sentinel对feign的支持
feign:
sentinel:
enabled: true
主启动
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OrderMain84 {
public static void main(String[] args) {
SpringApplication.run(OrderMain84.class, args);
}
}
业务
@FeignClient(value = "nacos-provider-payment", fallback = PaymentFallbackService.class)
public interface PaymentService {
@GetMapping("/payment/{id}")
ResultDto<Payment> paymentSQL(@PathVariable("id") Long id);
}
如果出现异常需要降级调用fallback指定的实现类中的具体方法实现
@Service
public class PaymentFallbackService implements PaymentService{
@Override
public ResultDto<Payment> paymentSQL(Long id) {
return new ResultDto<>(444,"PaymentFallbackService-paymentSQL-降级");
}
}
八、sentinel规则持久化
之前的配置中,只要微服务重启,sentinel的配置规则就会失效,使用规则持久化来保存配置的规则。
把规则配置到nacos中保存,只要刷新微服务的某个rest地址,sentinel的配置就会生效。
修改8401微服务
依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
配置
cloud:
sentinel:
# 流控规则持久化到nacos
datasource:
dsl:
nacos:
server-addr: localhost:8848
data-id: ${spring.application.name}
group-id: DEFAULT_GROUP
data-type: json
rule-type: flow