SpringCloudAlibaba系列(二)Sentinel-下

141 阅读4分钟

这是我参与更文挑战的第 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

配置

image-20201223114514842

如果超出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 处理逻辑。若未配置 blockHandlerfallbackdefaultFallback,则被限流降级时会将 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

sentinel 控制台设置

image-20201228003340304