微服务与Nacos概述-4

限流规则配置

每次服务重启后 之前配置的限流规则就会被清空因为是内存态的规则对象,所以就要用到Sentinel一个特性ReadableDataSource 获取文件、数据库或者配置中心是限流规则

依赖:spring-cloud-alibaba-sentinel-datasource

通过文件读取限流规则

properties 复制代码
spring.cloud.sentinel.datasource.ds1.file.file=classpath:flowrule.json
spring.cloud.sentinel.datasource.ds1.file.data-type=json
spring.cloud.sentinel.datasource.ds1.file.rule-type=flow

在resources新建一个文件 比如flowrule.json 添加限流规则

json 复制代码
[
    {
        "resource": "resource",
        "controlBehavior": 0,
        "count": 1,
        "grade": 1,
        "limitApp": "default",
        "strategy": 0
    }
]
java 复制代码
@RestController
public class TestController {
    @GetMapping("/test1")
    @SentinelResource(value = "resource")
    public String sayHello(String name){
        if(name==null || name.trim().length()<1)
        throw new IllegalArgumentException("参数为空!");
        return "Hello "+name+"!";
    }
}

一条限流规则主要有:

  • resource资源名,即限流规则的作用对象

  • count限流阈值

  • grade限流阈值类型,0表示线程,1表示QPS

  • limitApp流控针对的调用来源,若为 default 则不区分调用来源

  • strategy调用关系限流策略,0表示直接,1表示关联,2表示链路

  • controlBehavior流量控制效果,0表示快速失败,1表示Warm Up,2表示排队等待

隔离降级

限流是一种预防措施,虽然限流可以尽量避免因高并发而引起的服务故障,但服务还会因为其它原因而故障。而要将这些故障控制在一定范围,避免雪崩,就要靠线程隔离(舱壁模式)和熔断降级手段了。

  • 线程隔离就是调用者在调用服务提供者时,给每个调用的请求分配独立线程池,出现故障时,最多消耗这个线程池内资源,避免把调用者的所有资源耗尽

  • 熔断降级是在调用方这边加入断路器,统计对服务提供者的调用,如果调用的失败比例过高,则熔断该业务,不允许访问该服务的提供者了。

不管是线程隔离还是熔断降级,都是对客户端调用方的保护。需要在调用方发起远程调用时做线程隔离、或者服务熔断。

RestTemplate整合Sentinel

Spring Cloud Alibaba Sentinel 支持对 RestTemplate 的服务调用使用 Sentinel 进行保护,在构造RestTemplate bean的时候需要加上 @SentinelRestTemplate 注解。

  • @SentinelRestTemplate 注解的属性支持限流(blockHandler, blockHandlerClass)和降级(fallback, fallbackClass)的处理。

SentinelRestTemplate用于sentinel 集成 RestTemplate。可以添加在 RestTemplate上,全局的限流容错处理,优先级低于局部限流容错注解。例如 @SentinelRestTemplate(blockHandler ="handleException", blockHandlerClass = ExceptionUtil.class, fallback = "fallback",fallbackClass = ExceptionUtil.class)

  • blockHandler限流策略 (方法名,方法必须是静态的)

  • blockHandlerClass 限流方法类

  • fallback 熔断降级策略(方法名,方法必须是静态的)

  • fallbackClass 熔断降级类

java 复制代码
@Bean
@LoadBalance
@SentinelRestTemplate
public RestTemplate restTemplate(){
    return new RestTemplate();
}

对应实现,static修饰参数类型不能出错

java 复制代码
public class ExceptionUtil {
    // 服务流量控制处理
    public static ClientHttpResponse handleException(HttpRequest request,
byte[] body, ClientHttpRequestExecution execution, BlockException exception)
    {
        exception.printStackTrace();
        return new SentinelClientHttpResponse( JSON.toJSONString(new
Product(1, "服务流量控制处理-托底数据")));
    }
    // 服务熔断降级处理
    public static ClientHttpResponse fallback(HttpRequest request,byte[]
body, ClientHttpRequestExecution execution, BlockException exception) {
        exception.printStackTrace();
        return new SentinelClientHttpResponse( JSON.toJSONString(new
Product(1, "服务熔断降级处理-托底数据")));
    }
}

FeignClient整合Sentinel

SpringCloud中微服务调用都是通过Feign来实现的,因此做客户端保护必须整合Feign和Sentinel。

在启动类上面加个注解 @EnableFeignClients

修改OrderService的application.yml文件,开启Feign的Sentinel功能 feign.sentinel.enabled=true开启feign对sentinel的支持

方法1:定义对应FeignClient接口的实现类,提供对应的处理

java 复制代码
@Component
public class UserClientImpl implements UserClient {
    @Override
    public JsonResult getAllUsers() {
        return JsonResult.failure(103,"加载失败...");
    }
}

然后在FeignClient上添加注解说明

java 复制代码
@FeignClient(value="user-provider",fallback = UserClientImpl.class)
public interface UserClient {
    @GetMapping("/users")
    public JsonResult getAllUsers();
}

方法2:自定义工厂 [推荐使用]

java 复制代码
@Component
public class MyFeignFactory implements FallbackFactory<UserClient> {
    @Override
    public UserClient create(Throwable cause) {
        return new UserClient() {
            @Override
            public JsonResult getAllUsers() {
                return JsonResult.failure(1031,"加载失败...");
            }
        };
    }
}

在配置类中添加配置

java 复制代码
@Bean
public MyFeignFactory myClientFallbackFactory(){
    return new MyFeignFactory();
}

在FeignClient接口上添加配置使用MyFeignFactory

java 复制代码
@FeignClient(value="user-provider",fallbackFactory = MyFeignFactory.class)
public interface UserClient {
    @GetMapping("/users")
    public JsonResult getAllUsers();
}

失败降级逻辑

业务失败后不能直接报错,而应该返回用户一个友好提示或者默认结果,这个就是失败降级逻辑。可以给FeignClient编写失败后的降级逻辑。

  • 方式一FallbackClass无法对远程调用的异常做处理

  • 方式二FallbackFactory可以对远程调用的异常做处理

定义类实现FallbackFactory

java 复制代码
@Slf4j
public class UserClientFallbackFactory implements
FallbackFactory<UserClient> {
    @Override
    public UserClient create(Throwable throwable) {
        return new UserClient() {
            @Override
            public User findById(Long id) {
                log.error("查询用户异常", throwable);
                return new User();
            }
        };
    }
}

项目中的DefaultFeignConfiguration类中将UserClientFallbackFactory注册为一个Bean

java 复制代码
@Bean
public UserClientFallbackFactory userClientFallbackFactory(){
    return new UserClientFallbackFactory();
}

项目中的UserClient接口中使用UserClientFallbackFactory

java 复制代码
@FeignClient(value = "userservice", fallbackFactory =
UserClientFallbackFactory.class) public interface UserClient {
    @GetMapping("/user/{id}")
    User findById(@PathVariable("id") Long id);
}

在需要被保护的方法上使用@SentinelResource注解进行熔断配置。与Hystrix不同的是,Sentinel对抛出异常和熔断降级做了更加细致的区分,通过 blockHandler 指定熔断降级方法,通过 fallback 指定 触发异常执行的降级方法

java 复制代码
@GetMapping("/buy/{id}")
@SentinelResource(value="order",blockHandler = "orderblockHandler",fallback
= "orderfallback")
public Product order(@PathVariable Long id) {
    return restTemplate.getForObject("http://shop-
service/product/product/1", Product.class);
}
//降级方法
public Product orderblockHandler(Long id) {
    Product product = new Product();
    product.setId(-1l);
    product.setProductName("触发熔断降级方法");
    return product;
}
//降级方法
public Product orderfallback(Long id) {
    Product product = new Product();
    product.setId(-1l);
    product.setProductName("触发抛出异常方法");
    return product;
}

隔离降级总结

Sentinel支持的雪崩解决方案:线程隔离的仓壁模式、降级熔断

相关推荐
掘金-我是哪吒6 小时前
微服务mysql,redis,elasticsearch, kibana,cassandra,mongodb, kafka
redis·mysql·mongodb·elasticsearch·微服务
茶馆大橘7 小时前
微服务系列六:分布式事务与seata
分布式·docker·微服务·nacos·seata·springcloud
58沈剑8 小时前
80后聊架构:架构设计中两个重要指标,延时与吞吐量(Latency vs Throughput) | 架构师之路...
架构
想进大厂的小王10 小时前
项目架构介绍以及Spring cloud、redis、mq 等组件的基本认识
redis·分布式·后端·spring cloud·微服务·架构
九卷技术录11 小时前
(微服务)服务治理:几种开源限流算法库/应用软件介绍和使用
微服务·服务治理·限流算法
阿伟*rui11 小时前
认识微服务,微服务的拆分,服务治理(nacos注册中心,远程调用)
微服务·架构·firefox
ZHOU西口12 小时前
微服务实战系列之玩转Docker(十八)
分布式·docker·云原生·架构·数据安全·etcd·rbac
deephub14 小时前
Tokenformer:基于参数标记化的高效可扩展Transformer架构
人工智能·python·深度学习·架构·transformer
想进大厂的小王14 小时前
Spring-cloud 微服务 服务注册_服务发现-Eureka
微服务·eureka·服务发现
架构师那点事儿15 小时前
golang 用unsafe 无所畏惧,但使用不得到会panic
架构·go·掘金技术征文