Spring Cloud Hystrix:服务容错保护

Spring Cloud Hystrix:服务容错保护

  • 在启动类上添加@EnableCircuitBreaker来开启Hystrix的断路器功能

1.Hystrix 简介

在微服务架构中,服务与服务之间通过远程调用的方式进行通信,一旦某个被调用的服务发生了故障,其依赖服务也会发生故障,此时就会发生故障的蔓延,最终导致系统瘫痪。Hystrix实现了断路器模式,当某个服务发生故障时,通过断路器的监控,给调用方返回一个错误响应,而不是长时间的等待,这样就不会使得调用方由于长时间得不到响应而占用线程,从而防止故障的蔓延。Hystrix具备服务降级、服务熔断、线程隔离、请求缓存、请求合并及服务监控等强大功能。

@HystrixCommand中的常用参数

  • fallbackMethod:指定服务降级处理方法;
  • ignoreExceptions:忽略某些异常,不发生服务降级;
  • commandKey:命令名称,用于区分不同的命令;
  • groupKey:分组名称,Hystrix会根据不同的分组来统计命令的告警及仪表盘信息;
  • threadPoolKey:线程池名称,用于划分线程池。

2.创建一个hystrix-service模块

这里我们创建一个hystrix-service模块来演示hystrix的常用功能。

在pom-xml中添加相关依赖在pom.xml中添加相关依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

ps:服务注册和服务配置都是用nacos

server:
  port: 6603
spring:
  application:
    name: demo-springCloud-hystrix
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #配置Nacos地址

service-url:
  user-service: http://user-service

在启动类上添加@EnableCircuitBreaker来开启Hystrix的断路器功能

//在启动类上添加@EnableCircuitBreaker来开启Hystrix的断路器功能
@EnableCircuitBreaker
@SpringBootApplication
public class SpringCloudHystrix {
    public static void main(String[] args) {
        SpringApplication.run(SpringCloudHystrix.class, args);
    }
}

3.服务降级演示

1.在UserHystrixController中添加用于测试服务降级的接口:

@GetMapping("/testFallback/{id}")
public CommonResult testFallback(@PathVariable Long id) {
    return userService.getUser(id);
}
  • 在UserService中添加调用方法与服务降级方法,方法上需要添加@HystrixCommand注解:
@HystrixCommand(fallbackMethod = "getDefaultUser")
public CommonResult getUser(Long id) {
    return restTemplate.getForObject(userServiceUrl + "/user/{1}", CommonResult.class, id);
}

public CommonResult getDefaultUser(@PathVariable Long id) {
    User defaultUser = new User(-1L, "defaultUser", "123456");
    return new CommonResult<>(defaultUser);
}

调用该接口:http://localhost:6603/user/testFallback/1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1hwMoiVG-1665373139351)(Spring%20Cloud%20Hystrix%E6%9C%8D%E5%8A%A1%E5%AE%B9%E9%94%99%E4%BF%9D%E6%8A%A4.assets/image-20220726111605611.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zCg2Ucly-1665373139352)(Spring%20Cloud%20Hystrix%E6%9C%8D%E5%8A%A1%E5%AE%B9%E9%94%99%E4%BF%9D%E6%8A%A4.assets/image-20220726114512494.png)]

接下去把 demo-springCloud-client 服务关掉

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eCV0ERv2-1665373139352)(Spring%20Cloud%20Hystrix%E6%9C%8D%E5%8A%A1%E5%AE%B9%E9%94%99%E4%BF%9D%E6%8A%A4.assets/image-20220726111526882.png)]

调用该接口:http://localhost:6603/user/testFallback/1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6zxt9IlJ-1665373139353)(Spring%20Cloud%20Hystrix%E6%9C%8D%E5%8A%A1%E5%AE%B9%E9%94%99%E4%BF%9D%E6%8A%A4.assets/image-20220726111811134.png)]

2.设置命令、分组及线程池名称

  • 在UserHystrixController中添加测试接口:

    @GetMapping("/testCommand/{id}")
    public CommonResult testCommand(@PathVariable Long id) {
        return userService.getUserCommand(id);
    }
    
  • 在UserService中添加方式实现功能:

     @HystrixCommand(fallbackMethod = "getDefaultUser",
        commandKey = "getUserCommand",
        groupKey = "getUserGroup",
        threadPoolKey = "getUserThreadPool")
    public CommonResult getUserCommand(@PathVariable Long id) {
        return restTemplate.getForObject(userServiceUrl + "/user/{1}", CommonResult.class, id);
     }
    
  • 在UserService中添加实现方法,这里忽略了NullPointerException,当id为1时抛出IndexOutOfBoundsException,id为2时抛出NullPointerException:

    调用接口:http://localhost:6603/user/testException/1

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-foWVkV9Z-1665373139353)(Spring%20Cloud%20Hystrix%E6%9C%8D%E5%8A%A1%E5%AE%B9%E9%94%99%E4%BF%9D%E6%8A%A4.assets/image-20220726134548131.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-retz0yir-1665373139353)(Spring%20Cloud%20Hystrix%E6%9C%8D%E5%8A%A1%E5%AE%B9%E9%94%99%E4%BF%9D%E6%8A%A4.assets/image-20220726134600774.png)]

调用接口:http://localhost:6603/user/testException/2

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-03nTK7GW-1665373139354)(Spring%20Cloud%20Hystrix%E6%9C%8D%E5%8A%A1%E5%AE%B9%E9%94%99%E4%BF%9D%E6%8A%A4.assets/image-20220726134620008.png)]

3. Hystrix的请求缓存

当系统并发量越来越大时,我们需要使用缓存来优化系统,达到减轻并发请求线程数,提供响应速度的效果。

相关注解

  • @CacheResult:开启缓存,默认所有参数作为缓存的key,cacheKeyMethod可以通过返回String类型的方法指定key;
  • @CacheKey:指定缓存的key,可以指定参数或指定参数中的属性值为缓存key,cacheKeyMethod还可以通过返回String类型的方法指定;
  • @CacheRemove:移除缓存,需要指定commandKey。
(1)测试使用缓存
  • 在UserHystrixController中添加使用缓存的测试接口,直接调用三次getUserCache方法:

    @GetMapping("/testCache/{id}")
    public CommonResult testCache(@PathVariable Long id) {
        userService.getUserCache(id);
        userService.getUserCache(id);
        userService.getUserCache(id);
        return new CommonResult("操作成功", 200);
    }
    
  • 在UserService中添加具有缓存功能的getUserCache方法:

@CacheResult(cacheKeyMethod = "getCacheKey")
@HystrixCommand(fallbackMethod = "getDefaultUser", commandKey = "getUserCache")
    public CommonResult getUserCache(Long id) {
    LOGGER.info("getUserCache id:{}", id);
    return restTemplate.getForObject(userServiceUrl + "/user/{1}", CommonResult.class, id);
}

/**
 * 为缓存生成key的方法
 */
public String getCacheKey(Long id) {
    return String.valueOf(id);
}
  • 调用接口测试http://localhost:6603/user/testCache/1 这个接口中调用了三次getUserCache方法,但是只打印了一次日志,说明有两次走的是缓存:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2KgihwUL-1665373139354)(Spring%20Cloud%20Hystrix%E6%9C%8D%E5%8A%A1%E5%AE%B9%E9%94%99%E4%BF%9D%E6%8A%A4.assets/image-20220726135152897.png)]

(2)测试移除缓存
  • 在UserHystrixController中添加移除缓存的测试接口,调用一次removeCache方法:
@GetMapping("/testRemoveCache/{id}")
public CommonResult testRemoveCache(@PathVariable Long id) {
    userService.getUserCache(id);
    userService.removeCache(id);
    userService.getUserCache(id);
    return new CommonResult("操作成功", 200);
}
  • 在UserService中添加具有移除缓存功能的removeCache方法:
@CacheRemove(commandKey = "getUserCache", cacheKeyMethod = "getCacheKey")
@HystrixCommand
public CommonResult removeCache(Long id) {
    LOGGER.info("removeCache id:{}", id);
    return restTemplate.postForObject(userServiceUrl + "/user/delete/{1}", null, CommonResult.class, id);
}

调用接口测试http://localhost:6603/user/testRemoveCache/1 ,可以发现有两次查询都走的是接口

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kxd12Qme-1665373139354)(Spring%20Cloud%20Hystrix%E6%9C%8D%E5%8A%A1%E5%AE%B9%E9%94%99%E4%BF%9D%E6%8A%A4.assets/image-20220726140000321.png)]

4. 请求合并

微服务系统中的服务间通信,需要通过远程调用来实现,随着调用次数越来越多,占用线程资源也会越来越多。Hystrix中提供了@HystrixCollapser用于合并请求,从而达到减少通信消耗及线程数量的效果。

@HystrixCollapser的常用属性
  • batchMethod:用于设置请求合并的方法;

  • collapserProperties:请求合并属性,用于控制实例属性,有很多;

  • timerDelayInMilliseconds:collapserProperties中的属性,用于控制每隔多少时间合并一次请求;

    功能演示

    • 在UserHystrixController中添加testCollapser方法,这里我们先进行两次服务调用,再间隔200ms以后进行第三次服务调用:
    @GetMapping("/testCollapser")
    public CommonResult testCollapser() throws ExecutionException, InterruptedException {
        Future<User> future1 = userService.getUserFuture(1L);
        Future<User> future2 = userService.getUserFuture(2L);
        future1.get();
        future2.get();
        ThreadUtil.safeSleep(200);
        Future<User> future3 = userService.getUserFuture(3L);
        future3.get();
        return new CommonResult("操作成功", 200);
    }
    
    • 使用@HystrixCollapser实现请求合并,所有对getUserFuture的的多次调用都会转化为对getUserByIds的单次调用:
    @HystrixCollapser(batchMethod = "getUserByIds",collapserProperties = {
        @HystrixProperty(name = "timerDelayInMilliseconds", value = "100")
    })
    public Future<User> getUserFuture(Long id) {
        return new AsyncResult<User>(){
        @Override
        public User invoke() {
            CommonResult commonResult = restTemplate.getForObject(userServiceUrl + "/user/{1}", CommonResult.class, id);
            Map data = (Map) commonResult.getData();
            User user = BeanUtil.mapToBean(data,User.class,true);
            LOGGER.info("getUserById username:{}", user.getUsername());
            return user;
            }
        };
    }
    
    @HystrixCommand
    public List<User> getUserByIds(List<Long> ids) {
        LOGGER.info("getUserByIds:{}", ids);
        CommonResult commonResult = restTemplate.getForObject(userServiceUrl + "/user/getUserByIds?ids={1}", CommonResult.class, CollUtil.join(ids,","));
        return (List<User>) commonResult.getData();
    }
    
    • 访问接口测试http://localhost:6603/user/testCollapser由于我们设置了100毫秒进行一次请求合并,前两次被合并,最后一次自己单独合并了。

5.Hystrix的常用配置

全局配置

hystrix:
  command: #用于控制HystrixCommand的行为
    default:
      execution:
        isolation:
          strategy: THREAD #控制HystrixCommand的隔离策略,THREAD->线程池隔离策略(默认),SEMAPHORE->信号量隔离策略
          thread:
            timeoutInMilliseconds: 1000 #配置HystrixCommand执行的超时时间,执行超过该时间会进行服务降级处理
            interruptOnTimeout: true #配置HystrixCommand执行超时的时候是否要中断
            interruptOnCancel: true #配置HystrixCommand执行被取消的时候是否要中断
          timeout:
            enabled: true #配置HystrixCommand的执行是否启用超时时间
          semaphore:
            maxConcurrentRequests: 10 #当使用信号量隔离策略时,用来控制并发量的大小,超过该并发量的请求会被拒绝
      fallback:
        enabled: true #用于控制是否启用服务降级
      circuitBreaker: #用于控制HystrixCircuitBreaker的行为
        enabled: true #用于控制断路器是否跟踪健康状况以及熔断请求
        requestVolumeThreshold: 20 #超过该请求数的请求会被拒绝
        forceOpen: false #强制打开断路器,拒绝所有请求
        forceClosed: false #强制关闭断路器,接收所有请求
      requestCache:
        enabled: true #用于控制是否开启请求缓存
  collapser: #用于控制HystrixCollapser的执行行为
    default:
      maxRequestsInBatch: 100 #控制一次合并请求合并的最大请求数
      timerDelayinMilliseconds: 10 #控制多少毫秒内的请求会被合并成一个
      requestCache:
        enabled: true #控制合并请求是否开启缓存
  threadpool: #用于控制HystrixCommand执行所在线程池的行为
    default:
      coreSize: 10 #线程池的核心线程数
      maximumSize: 10 #线程池的最大线程数,超过该线程数的请求会被拒绝
      maxQueueSize: -1 #用于设置线程池的最大队列大小,-1采用SynchronousQueue,其他正数采用LinkedBlockingQueue
      queueSizeRejectionThreshold: 5 #用于设置线程池队列的拒绝阀值,由于LinkedBlockingQueue不能动态改版大小,使用时需要用该参数来控制线程数

实例配置

实例配置只需要将全局配置中的default换成与之对应的key即可。

hystrix:
  command:
    HystrixComandKey: #将default换成HystrixComrnandKey
      execution:
        isolation:
          strategy: THREAD
  collapser:
    HystrixCollapserKey: #将default换成HystrixCollapserKey
      maxRequestsInBatch: 100
  threadpool:
    HystrixThreadPoolKey: #将default换成HystrixThreadPoolKey
      coreSize: 10
配置文件中相关key的说明
  • HystrixComandKey对应@HystrixCommand中的commandKey属性;
  • HystrixCollapserKey对应@HystrixCollapser注解中的collapserKey属性;
  • HystrixThreadPoolKey对应@HystrixCommand中的threadPoolKey属性。# Spring Cloud Hystrix:服务容错保护
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

有点东西且很多

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值