12.hystrix嵌套command实现多级降级


多级降级

先降一级,尝试用一个备用方案去执行,如果备用方案失败了,再用最后下一个备用方案去执行

command嵌套command

尝试从备用服务器接口去拉取结果


给大家科普一下,常见的多级降级的做法,有一个操作,要访问MySQL数据库


mysql数据库访问报错,降级,去redis中获取数据


如果说redis又挂了,然后就去从本地ehcache缓存中获取数据


hystrix command fallback语义,很容易就可以实现多级降级的策略



商品服务接口,多级降级的策略


command,fallback,又套了一个command,第二个command其实是第一级降级策略


第二个command的fallback是第二级降级策略



第一级降级策略,可以是


storm,我们之前做storm这块,第一级降级,一般是搞一个storm的备用机房,部署了一套一模一样的拓扑,如果主机房中的storm拓扑挂掉了,备用机房的storm拓扑定顶上


如果备用机房的storm拓扑也挂了


第二级降级,可能就降级成用mysql/hbase/redis/es,手工封装的一套,按分钟粒度去统计数据的系统


第三季降级,离线批处理去做,hdfs+spark,每个小时执行一次数据统计,去降级


特别复杂,重要的系统,肯定是要搞好几套备用方案的,一个方案死了,立即上第二个方案,而且要尽量做到是自动化的


商品接口拉取


主流程,访问的商品服务,是从主机房去访问的,服务,如果主机房的服务出现了故障,机房断电,机房的网络负载过高,机器硬件出了故障


第一级降级策略,去访问备用机房的服务

第二级降级策略,用stubbed fallback降级策略,比较常用的,返回一些残缺的数据回去



/**
 * 获取商品信息(hystrix线程隔离)
 * HystrixCommand:是用来获取一条数据的
 * @author Administrator
 *
 */
public class GetProductInfoCommand extends HystrixCommand<ProductInfo>{


private Long productId;


public GetProductInfoCommand(Long productId) {
// super(HystrixCommandGroupKey.Factory.asKey("GetProductInfoGroup"));默认1秒,我手设3秒timeout
// super(HystrixCommandGroupKey.Factory.asKey("GetProductInfoGroup"),3000);
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("GetProductInfoGroup"))
//设置当前command的key,默认值为当前类名
.andCommandKey(HystrixCommandKey.Factory.asKey("GetProductInfoCommand"))


.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
//控制是否要打开timeout机制,默认是true
.withExecutionTimeoutEnabled(true)
//手动设置timeout超时时间,一个command运行超出这个时间,就被认为是timeout,然后将hystrix command标识为timeout,同时执行fallback降级逻辑,默认是1000,也就是1000毫秒
.withExecutionTimeoutInMilliseconds(10000)
//设置一个rolling window,滑动窗口中,最少要有多少个请求时,才触发开启短路
.withCircuitBreakerRequestVolumeThreshold(30)
//设置异常请求量的百分比,当异常请求达到这个百分比时,就触发打开短路器,默认是50,也就是50%
.withCircuitBreakerErrorThresholdPercentage(40)
//设置在短路之后,需要在多长时间内直接reject请求,然后在这段时间之后,再重新导holf-open状态,尝试允许请求通过以及自动恢复,默认值是5000毫秒
.withCircuitBreakerSleepWindowInMilliseconds(3000)
//使用信号量隔离时,命令调用最大的并发数,默认:10 
.withExecutionIsolationSemaphoreMaxConcurrentRequests(30))
//如果不想直接用command group,也可以手动设置thread pool name,细分线程池
//一个CommandGroup可以有多个线程池进行内部资源隔离
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("GetProductInfoPool"))
//设置当前command对应的线程池的大小和等待队列的大小,但是在信号量模式不适用!!!!
.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter()
.withCoreSize(12)//设置线程池的大小,默认值是10
.withMaximumSize(20)//设置线程池的最大大小,只有在设置allowMaximumSizeToDivergeFromCoreSize的时候才能生效
.withAllowMaximumSizeToDivergeFromCoreSize(true)//允许线程池大小自动动态调整,设置为true之后,maxSize就生效了
.withKeepAliveTimeMinutes(1)//设置保持存活的时间,单位是分钟,默认是1

.withMaxQueueSize(10))//设置等待队列的大小,但是在信号量模式不适用默认值是5



); 






this.productId = productId;
}


@Override
protected ProductInfo run() throws Exception {
// throw new Exception();//主动抛错,测试降级机制
System.out.println("调用接口,查询商品数据,productId=" + productId); 


//测试熔断器的实验或者是多级降级的实验(主动抛错,测试降级机制)
if(productId.equals(-1L)) {
throw new Exception();
}
//测试限流的实验
if(productId.equals(-2L)) {
Thread.sleep(3000);  
}


String url = "http://127.0.0.1:8080/getProductInfo?productId=" + productId;
String response = HttpClientUtils.sendGetRequest(url);
return JSONObject.parseObject(response, ProductInfo.class);  
}


@Override
protected String getCacheKey() {
return "product_info_" + productId;
}


/**
* 第一级fallback降级机制
*/
@Override
protected ProductInfo getFallback() {
return new FirstLevelFallbackCommand(productId).execute();
}


// 第一级的降级策略,因为这个command是运行在fallback中的
// 所以至关重要的一点是,在做多级降级的时候,要将降级command的线程池单独做一个出来
// 如果主流程的command都失败了,可能线程池都已经被占满了
// 降级command必须用自己的独立的线程池
private class FirstLevelFallbackCommand extends HystrixCommand<ProductInfo>{
Long productId;
FirstLevelFallbackCommand(Long productId){
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("GetProductInfoGroup"))
//设置当前command的key,默认值为当前类名
.andCommandKey(HystrixCommandKey.Factory.asKey("FirstLevelFallbackCommand"))
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("FirstLevelFallbackPool"))
);
this.productId= productId;
}
@Override
protected ProductInfo run() throws Exception {
// 这里,因为是第一级降级的策略,所以说呢,其实是要从备用机房的机器去调用接口
// 但是,我们这里没有所谓的备用机房,所以说还是调用同一个服务来模拟
if(productId.equals(-2L)) {
throw new Exception();
}
String url = "http://127.0.0.1:8082/getProductInfo?productId=" + productId;
String response = HttpClientUtils.sendGetRequest(url);
return JSONObject.parseObject(response, ProductInfo.class); 
}

/**
* 第二级fallback降级机制
*/
@Override
protected ProductInfo getFallback() {
System.out.println("第二级fallback降级");
//这里可以从缓存/数据库中拉去数据
ProductInfo productInfo=new ProductInfo();
productInfo.setName("降级商品");
return productInfo;  
}

}


}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值