Hystrix实现线程隔离

一、Hystrix目的
隔离:防止服务级联失败;业务处理隔离(没有远程调用)

熔断:超时、失败率、信号量

降解:返回托底数据

二、Hystrix原理
1. 执行流程


step1:每次调用创建一个新的HystrixCommand,把依赖调用封装在run()方法中。
step2:执行execute()/queue做同步或异步调用。
step3:判断熔断器(circuit-breaker)是否打开,如果打开跳到步骤8,进行降级策略,如果关闭进入步骤。
step4:判断线程池/队列/信号量是否跑满,如果跑满进入降级步骤8,否则继续后续步骤。
step5:调用HystrixCommand的run方法。运行依赖逻辑
        step5a:依赖逻辑调用超时,进入步骤8。
step6:判断逻辑是否调用成功
        step6a:返回成功调用结果
        step6b:调用出错,进入步骤8。
step7:计算熔断器状态,所有的运行状态(成功, 失败, 拒绝,超时)上报给熔断器,用于统计从而判断熔断器状态。
step8:getFallback()降级逻辑。
         以下四种情况将触发getFallback调用:
         (1):run()方法抛出非HystrixBadRequestException异常
         (2):run()方法调用超时
         (3):熔断器开启拦截调用
         (4):线程池/队列/信号量是否跑满
        step8a:没有实现getFallback的Command将直接抛出异常
        step8b:fallback降级逻辑调用成功直接返回
        step8c:降级逻辑调用失败抛出异常
step9:返回执行成功结果

 

2. 执行方式

 


package com.netflix.hystrix;
 
import java.util.concurrent.Future;
 
import rx.Observable;
import rx.schedulers.Schedulers;
 
import com.netflix.hystrix.HystrixCommandProperties.ExecutionIsolationStrategy;
import com.netflix.hystrix.exception.HystrixBadRequestException;
import com.netflix.hystrix.exception.HystrixRuntimeException;
 
public interface HystrixExecutable<R> extends HystrixInvokable<R> {
 
    /**
     * 同步执行命令:当前线程需该命令执行完成后才能往下执行(阻塞)
     * @return R 执行结果
     * @throws HystrixRuntimeException 发生错误或fallback没有挽回,则抛出异常
     * @throws HystrixBadRequestException 请求参数无效异常
     */
    public R execute();
 
    /**
     * 异步执行命令:当前线程无需该命令执行完成后才能往下执行(非阻塞)
     * 异步返回Future来获取结果
     * 注意:如果不是线程池隔离,则与execute()执行相同都具有阻塞
     * @return Future<R> 执行结果
     * @throws HystrixRuntimeException 发生错误或fallback没有挽回,则抛出异常
     * @throws HystrixBadRequestException 请求参数无效异常
     */
    public Future<R> queue();
 
    /**
     * 响应式异步执行,Observable获取执行结果
     * 立即获取:与execute()、queue()相同
     * 延迟获取:与toObservable()相同
     * @return Observable<R> 返回执行结果(包括进入fallback)
     * @throws HystrixRuntimeException 发生错误或fallback没有挽回(熔断器打开,队列饱和),则抛出异常
     * @throws HystrixBadRequestException  请求参数无效异常
     * @throws IllegalStateException 多次调用
     */
    public Observable<R> observe();
 
}
package com.netflix.hystrix;
 
import rx.Observable;
import rx.schedulers.Schedulers;
 
import com.netflix.hystrix.HystrixCommandProperties.ExecutionIsolationStrategy;
import com.netflix.hystrix.exception.HystrixBadRequestException;
import com.netflix.hystrix.exception.HystrixRuntimeException;
 
public interface HystrixObservable<R> extends HystrixInvokable<R> {
 
    /**
     * 响应式异步执行,Observable获取执行结果
     * 立即获取:与execute()、queue()相同
     * 延迟获取:与toObservable()相同
     * @return Observable<R> 返回执行结果(包括进入fallback)
     * @throws HystrixRuntimeException 发生错误或fallback没有挽回(熔断器打开,队列饱和),则抛出异常
     * @throws HystrixBadRequestException  请求参数无效异常
     * @throws IllegalStateException 多次调用
     */
    public Observable<R> observe();
 
    /**
     * Used for asynchronous execution of command with a callback by subscribing to the {@link Observable}.
     * 响应式异步执行,Observable获取执行结果
     * 延迟获取
     * 立即获取:observe()
     * @return Observable<R> 返回执行结果(包括进入fallback)
     * @throws HystrixRuntimeException 发生错误或fallback没有挽回(熔断器打开,队列饱和),则抛出异常
     * @throws HystrixBadRequestException  请求参数无效异常
     * @throws IllegalStateException 多次调用
     */
    public Observable<R> toObservable();
 
}
总结执行方法:

方法

说明

R execute()
HystrixCommand
同步执行:当前线程需该命令执行完成后才能往下执行(阻塞)
Future<R> queue()
异步执行:当前线程无需该命令执行完成能往下执行(非阻塞)
Observable<R> observe()
HystrixObservableCommand
响应式异步执行:立即获取
Observable<R> toObservable()
响应式异步执行:惰性获取
3. 隔离策略
线程池(THREAD):默认,池与主线程互不影响、远程服务调用互不影响;开销大

信号量(SEMAPHORE):只限制总并发数,主线程同步调用;轻量级

类型    优点    不足    适用
线程    
支持排队和超时;

支持异步调用

线程调用和切换产生额外开销    不受信客户(比如第三方服务稳定性是无法推测的)
信号量    轻量且无额外开销    
不支持任务排队和超时;

不支持异步

受信客户、高频高速调用服务(网关、cache)
三、实现实例
1. 自定义GetStockServiceCommand类
package com.common.instance.demo.hystrix;
 
import com.common.instance.demo.entity.WcPendantTab;
import com.common.instance.demo.service.WcPendantTabService;
import com.netflix.hystrix.*;
 
import java.util.List;
 
/**
 * @description Hystrix使用
 * @author tcm
 * @version 1.0.0
 * @date 2021/9/27 11:00
 **/
public class GetStockServiceCommand extends HystrixCommand<List<WcPendantTab>> {
 
    private WcPendantTabService wcPendantTabService;
    private WcPendantTab tab;
 
    protected GetStockServiceCommand(WcPendantTabService wcPendantTabService, WcPendantTab tab) {
        super(setter());
        this.wcPendantTabService = wcPendantTabService;
        this.tab = tab;
    }
 
    private static Setter setter(){
        // 服务分组,默认一个服务名一个组
        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey("stock");
        // 服务标识,默认当前执行的方法名称
        HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey("getStock");
        // 线程池名称,相同线程池名称的线程池是同一个
        HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey("stock-pool");
        // 线程池配置
        HystrixThreadPoolProperties.Setter threadPoolProperties = HystrixThreadPoolProperties.Setter()
                // 最大并发执行数,默认10
                .withCoreSize(10)
                // 存活时间(控制一个线程从实用完成到被释放的时间),默认1min
                .withKeepAliveTimeMinutes(5)
                // BlockingQueue的最大长度,正数:队列将从同步队列改为阻塞队列,默认-1
                .withMaxQueueSize(Integer.MAX_VALUE)
                // 拒绝请求的临界值,默认5
                .withQueueSizeRejectionThreshold(100);
        // 命令属性配置
        HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter()
                // 隔离策略:THREAD(线程池_默认)、SEMAPHORE(信号量)
                .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD);
        return Setter
                .withGroupKey(groupKey)
                .andCommandKey(commandKey)
                .andThreadPoolKey(threadPoolKey)
                .andThreadPoolPropertiesDefaults(threadPoolProperties)
                .andCommandPropertiesDefaults(commandProperties);
    }
 
    // 执行任务
    @Override
    protected List<WcPendantTab> run() throws Exception {
        return wcPendantTabService.queryAll(this.tab);
    }
 
    // fallback
    @Override
    protected List<WcPendantTab> getFallback() {
        return null;
    }
 
}
2. 调用Hystrix命令
package com.common.instance.demo.hystrix;
 
import com.common.instance.demo.core.Response;
import com.common.instance.demo.entity.WcPendantTab;
import com.common.instance.demo.service.WcPendantTabService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
import javax.annotation.Resource;
import java.util.List;
 
/**
 * @description Hystrix测试
 * @author tcm
 * @version 1.0.0
 * @date 2021/9/27 17:47
 **/
@RestController
@RequestMapping("/hystrix")
@Api(tags = "Hystrix测试")
public class HystrixController {
 
    @Resource
    private WcPendantTabService wcPendantTabService;
 
    @PostMapping("/hystrixCommand")
    @ApiOperation("测试HystrixCommand")
    public Response<List<WcPendantTab>> testHystrixCommand(WcPendantTab tab) {
        GetStockServiceCommand getStockServiceCommand = new GetStockServiceCommand(wcPendantTabService, tab);
        List<WcPendantTab> result = getStockServiceCommand.execute();
        return Response.success(result);
    }
 
}
3. 压测结果

普通接口测试

 

 Hytrix线程池隔离

普通接口测试

Hytrix线程池隔离
两个压测的业务逻辑:800W条数据查询相同的数据,没有缓存配置;调用接口时,CPU=6%、内存=63%、磁盘=1%,网络=0%。压测条件相同,但是Hytrix线程池隔离的吞吐量5025/s比普通接口4054/s高出1000,主要是线程池提高了并发量。
 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值