Hystrix实现线程隔离

目录

一、Hystrix目的

二、Hystrix原理

1. 执行流程

2. 执行方式

3. 隔离策略

三、实现实例

1. 自定义GetStockServiceCommand类

2. 调用Hystrix命令

3. 压测结果

四、参考资料


一、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线程池隔离

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

四、参考资料

微服务高可用利器——Hystrix熔断降级原理&实践总结_舒哥的blog-CSDN博客_hystrix熔断原理

熔断机制hystrix - 佳716 - 博客园

服务熔断、线程池和信号量隔离、Feign服务降级项目、数据监控dashboard、Turbine聚合 - 知乎

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值