SpringCloud之服务熔断Hystrix

服务与服务之间通过远程调用的方式进行通信,一旦某个被调用的服务发生了故障,其依赖服务也会发生故障,此时就会发生故障的蔓延,最终导致系统瘫痪
在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,如何能够保证在一个依赖出问题的情况下,不会导致整体服务失败,这个就是Hystrix需要做的事情。Hystrix提供了熔断、隔离、Fallback、cache、监控等功能,能够在一个、或多个依赖同时出现问题时保证系统依然可用。
1.服务雪崩效应
当一个请求依赖多个服务的时候:正常情况
在这里插入图片描述
但是,当请求的服务中出现无法访问、异常、超时等问题时(图中的I),那么用户的请求将会被阻塞。
在这里插入图片描述
如果多个用户的请求中,都存在无法访问的服务,那么他们都将陷入阻塞的状态中。
在这里插入图片描述
通过Hystrix的引入,可以通过服务熔断和服务降级来解决这个问题。
熔断机制是应对雪崩效应的一种微服务链路保护机制。当某个服务不可用或者响应时间超时,会进行服务降级,进而熔断该节点的服务调用,快速返回自定义的错误影响页面信息。
以下模拟熔断:@HystrixCommand****

 /**
 * 获取信息
 * @return
 * @throws InterruptedException 
 */
@ResponseBody
@GetMapping(value="/getInfo")
@HystrixCommand(fallbackMethod="getInfoFallback")
public Map<String,Object> getInfo() throws InterruptedException{
    Thread.sleep(2000);
    Map<String,Object> map=new HashMap<String,Object>();
    map.put("code", 200);
    map.put("info", "业务数据xxxxx");
    return map;
}
public Map<String,Object> getInfoFallback() throws InterruptedException{
    Map<String,Object> map=new HashMap<String,Object>();
    map.put("code", 500);
    map.put("info", "系统出错,稍后重试");
    return map;
}

正常访问返回的是{200 ,业务数据xxxxx} 但是设置了Thread.sleep(2000) 来模拟超时;
@HystrixCommand(fallbackMethod=“getInfoFallback”)表明这个方法我们在没有异常以及没有超时(hystrix默认1秒算超时)的情况,才返回正常的业务数据;否则,进入fallback指定的本地方法,返回{500 ,系统出错稍后重试},模拟解决雪崩效应。
在这里插入图片描述
@HystrixCommand详解
@HystrixCommand中的常用参数

fallbackMethod:指定服务降级处理方法;
ignoreExceptions:忽略某些异常,不发生服务降级;
commandKey:命令名称,用于区分不同的命令;
groupKey:分组名称,Hystrix会根据不同的分组来统计命令的告警及仪表盘信息;
threadPoolKey:线程池名称,用于划分线程池。
2.Hystrix的请求缓存
当系统并发量越来越大时,我们需要使用缓存来优化系统,达到减轻并发请求线程数,提供响应速度的效果。
2.1 相关注解
@CacheResult:开启缓存,默认所有参数作为缓存的key,cacheKeyMethod可以通过返回String类型的方法指定key;
@CacheKey:指定缓存的key,可以指定参数或指定参数中的属性值为缓存key,cacheKeyMethod还可以通过返回String类型的方法指定;
@CacheRemove:移除缓存,需要指定commandKey。
2.2测试使用缓存
在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:8401/user/testCache/1,这个接口中调用了三次getUserCache方法,但是只打印了一次日志,说明有两次走的是缓存
在这里插入图片描述
3 请求合并
微服务系统中的服务间通信,需要通过远程调用来实现,随着调用次数越来越多,占用线程资源也会越来越多。Hystrix中提供了@HystrixCollapser用于合并请求,从而达到减少通信消耗及线程数量的效果。
3.1 @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:8401/user/testCollapser,由于 设置了100毫秒进行一次请求合并,前两次被合并,最后一次自己单独合并了
在这里插入图片描述
4.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不能动态改版大小,使用时需要用该参数来控制线程数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值