服务治理-线程隔离

隔离

隔离是指将系统或资源分隔开,为了在系统发生故障时,减小影响范围,防止雪崩。常见的隔离有,环境隔离,资源隔离,线程隔离,进程隔离,集群隔离,机房隔离,读写隔离,动静隔离,爬虫隔离等等。。本篇主要讲线程隔离。

举个例子,在下单场景下,需要获取商家信息和商品信息,如果商家服务查询数据库发生缓慢情况,也会影响到商品服务,导致整个下单流程不能走完。像这种情况,我们可以采用降级策略,在服务发生故障的时候,进行熔断,返回一些托底数据,阻止雪崩。

我采用的是spring cloud这个框架集合,它提供了spring cloud-hystrix组件。hystrix是Netflix开源的一款容错系统,用来隔离分布式服务故障。

直入话题,下面是Hystrix的实战。

Hystrix提供了俩种隔离方式,信号量隔离和线程池隔离。

线程池隔离

//需引入的依赖包
<dependency>
    <groupId>com.netflix.hystrix</groupId>
    <artifactId>hystrix-core</artifactId>
    <version>1.5.12</version>
</dependency>
/**
 * @author jespon
 * @date 2018/4/16 14:44
 * @desc 代码方式配置。注意:一个command只能调用一次,不可以写单例,调用只能实例化
 */
public class GetStockCommand extends HystrixCommand<String> {

    private StockService stockService;

    public GetStockCommand(StockService stockService) {
        super(setter());
        this.stockService = stockService;
    }

    private static Setter setter(){

        //服务分组名称,相同分局服务聚合
        HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey("stock");
        //服务唯一标识
        HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey("getStock");
        //线程池名称
        HystrixThreadPoolKey poolKey = HystrixThreadPoolKey.Factory.asKey("stock-pool");

        HystrixThreadPoolProperties.Setter threadPoolProperties = HystrixThreadPoolProperties.Setter()
                .withCoreSize(10)    //核心线程池大小,核心线程一直存活
                .withKeepAliveTimeMinutes(5)     //线程池空闲线程的生存时间,超过则销毁
                .withMaxQueueSize(10000)     //线程池队列大小
                .withQueueSizeRejectionThreshold(100);      //动态队列大小调整,因为MaxQueueSize不会改变,通过这个属性来限制,当MaxQueueSize=-1(默认值)时,不生效

        //线程池隔离方式
        HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter()
                .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD);

        return HystrixCommand.Setter
                .withGroupKey(groupKey)
                .andCommandKey(commandKey)
                .andThreadPoolKey(poolKey)
                .andThreadPoolPropertiesDefaults(threadPoolProperties)
                .andCommandPropertiesDefaults(commandProperties);
    }

    //业务处理,开启一个新线程执行
    @Override
    protected String run() throws Exception {
        return stockService.getStock();
    }

    //降级处理
    @Override
    protected String getFallback() {
        return "降级处理";
    }
}
    //调用方代码
    public String getStock(){
        GetStockCommand getStockCommand = new GetStockCommand(stockService);
        String result = getStockCommand.execute();//同步调用
        //Future<String> future = getStockCommand.queue();String result = future.get();//异步非堵塞方式调用
        //Observable<String> observe = getStockCommand.observe(); observe.asObservable().subscribe((result) -> {System.out.println(result)});//响应式编程
        return result;
    }

以上是java代码方式配置线程池隔离,这个代码量确实让人有点不敢恭维,于是就有了javanica项目,提供了hystrix的注解配置方式。代码如下

//依赖包
<dependency>
    <groupId>com.netflix.hystrix</groupId>
    <artifactId>hystrix-javanica</artifactId>
    <version>1.5.12</version>
</dependency>
    @HystrixCommand(groupKey = "stock", commandKey = "getStock", threadPoolKey = "stock-pool",
                    threadPoolProperties = {
                        @HystrixProperty(name = "coreSize",value = "10"),
                        @HystrixProperty(name = "maxQueueSize",value = "10000"),
                        @HystrixProperty(name = "keepAliveTimeMinutes",value = "5"),
                        @HystrixProperty(name = "queueSizeRejectionThreshold",value = "100"),
                    },
                    fallbackMethod = "fallbackForGetStock")  //降级方法名
    public String getStockOne() {
        System.out.println("getone");
        return stockService.getStock();
    }

    public String fallbackForGetStock(){
        System.out.println("注解配置降级");
        return "注解配置fallback";
    }

信号量隔离

这里就只写注解配置方式了

 //信号量隔离方式,
    @HystrixCommand(
            commandProperties = {
                    @HystrixProperty(name = "execution.isolation.strategy", value = "SEMAPHORE"),
                    @HystrixProperty(name = "execution.isolation.semaphore.maxConcurrentRequests", value = "10"),   //并发数量
                    @HystrixProperty(name = "fallback.isolation.semaphore.maxConcurrentRequests", value = "50")  // 信号量配置,如果请求超过了并发信号量,则不走fallback,快速响应失败,抛出fallback execution rejected.这个异常
            },
            fallbackMethod = "fallbackForGetStock")
    public String getStockOneForSemaphore() {
        return stockFeign.getStock();
    }

线程池是控制线程的数量,信号量是用来控制并发数量的。信号量只是限制了总的并发数,服务使用主线程进行同步调用,因此,如果只是限制某个服务的并发数或者不涉及远程调用的情况,可以使用轻量级的信号量隔离。

阅读更多

没有更多推荐了,返回首页