专栏首页JavaEdge高可用服务架构设计(10)-Hystrix隔离策略细粒度控制
原创

高可用服务架构设计(10)-Hystrix隔离策略细粒度控制

0 Github

资源隔离两种策略

  • 线程池隔离
  • 信号量隔离

对于资源隔离,做更加深入一些的讲解,除了可以选择隔离策略,对选择的隔离策略,可以做一定的细粒度的控制

1 execution.isolation.strategy

指定HystrixCommand.run()的资源隔离策略

  • THREAD 基于线程池
// to use thread isolation
HystrixCommandProperties.Setter()
   .withExecutionIsolationStrategy(ExecutionIsolationStrategy.THREAD)
  • SEMAPHORE 基于信号量// to use semaphore isolation HystrixCommandProperties.Setter() .withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)线程池机制,每个command运行在一个线程中,限流是通过线程池的大小来控制的 信号量机制,command是运行在调用线程中,但是通过信号量的容量来进行限流

如何在线程池和信号量之间做选择呢?

默认的策略为线程池

线程池其实最大的好处就是对于网络访问请求,若超时,可以避免调用线程阻塞住

而使用信号量的场景,通常是针对超大并发量的场景下,每个服务实例每秒都几百的QPS

此时用线程池,线程一般不会太多,可能撑不住那么高的并发

要撑住,可能要耗费大量的线程资源,那么就是用信号量,来限流保护

一般用信号量常见于那种基于纯内存的一些业务逻辑服务,而不涉及到任何网络访问请求

netflix有100+的command运行在40+的线程池中,只有少数command是不运行在线程池中的,就是从纯内存中获取一些元数据,或者是对多个command包装起来的facacde command,是用信号量限流的

2 command名称 & command组

线程池隔离,依赖服务->接口->线程池,如何来划分

每个command,都可以设置一个自己的名称,同时可以设置一个自己的组

private static final Setter cachedSetter = 
    Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
        .andCommandKey(HystrixCommandKey.Factory.asKey("HelloWorld"));    

public CommandHelloWorld(String name) {
    super(cachedSetter);
    this.name = name;
}
  • command group 一个非常重要的概念,默认情况下,因为就是通过command group来定义一个线程池的,而且还会通过command group来聚合一些监控和报警信息

同一个command group中的请求,都会进入同一个线程池中

3 command线程池

ThreadPoolKey代表了一个HystrixThreadPool,用来进行统一监控,统计,缓存

默认的threadpool key就是command group名称

每个command都会跟它的ThreadPoolKey对应的ThreadPool绑定

如果不想直接用command group,也可以手动设置thread pool name

public CommandHelloWorld(String name) {
    super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
            .andCommandKey(HystrixCommandKey.Factory.asKey("HelloWorld"))
            .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("HelloWorldPool")));
    this.name = name;
}

command threadpool => command group => command key

  • command key
    代表了一类command,代表底层的依赖服务的一个接口
  • command group
    代表了某一个底层的依赖服务,合理,一个依赖服务可能会暴露出来多个接口,每个接口就是一个command key

command group

在逻辑上去组织起来一堆command key的调用,统计信息,成功次数,timeout超时次数,失败次数,可以看到某一个服务整体的一些访问情况

推荐是根据一个服务去划分出一个线程池,command key默认都是属于同一个线程池的

比如说你以一个服务为粒度,估算出来这个服务每秒的所有接口加起来的整体QPS在100左右

你调用那个服务的当前服务,部署了10个服务实例,每个服务实例上,其实用这个command group对应这个服务,给一个线程池,量大概在10个左右,就可以了,你对整个服务的整体的访问QPS大概在每秒100左右

一般来说,command group是用来在逻辑上组合一堆command的

举个例子,对于一个服务中的某个功能模块来说,希望将这个功能模块内的所有command放在一个group中,那么在监控和报警的时候可以放一起看

command group,对应了一个服务,但是这个服务暴露出来的几个接口,访问量很不一样,差异非常之大

你可能就希望在这个服务command group内部,包含的对应多个接口的command key,做一些细粒度的资源隔离

对同一个服务的不同接口,都使用不同的线程池

command key -> command group

command key -> 自己的threadpool key

逻辑上来说,多个command key属于一个command group,在做统计的时候,会放在一起统计

每个command key有自己的线程池,每个接口有自己的线程池,去做资源隔离和限流

但对于thread pool资源隔离来说,可能是希望能够拆分的更加一致一些,比如在一个功能模块内,对不同的请求可以使用不同的thread pool

command group一般来说,可以是对应一个服务,多个command key对应这个服务的多个接口,多个接口的调用共享同一个线程池

如果说你的command key,要用自己的线程池,可以定义自己的threadpool key,就ok了

4 coreSize

设置线程池的大小,默认是10

HystrixThreadPoolProperties.Setter()
 						   .withCoreSize(int value)

一般来说,用这个默认的10个线程大小就够了

5 queueSizeRejectionThreshold

控制queue满后reject的threshold,因为maxQueueSize不允许热修改,因此提供这个参数可以热修改,控制队列的最大值

HystrixCommand在提交到线程池之前,其实会先进入一个队列中,这个队列满了之后,才会reject

默认值是5

HystrixThreadPoolProperties.Setter()
   .withQueueSizeRejectionThreshold(int value)
  • 线程池+queue的工作原理

6 isolation.semaphore.maxConcurrentRequests

设置使用SEMAPHORE隔离策略的时候,允许访问的最大并发量,超过这个最大并发量,请求直接被reject

这个并发量的设置,跟线程池大小的设置,应该是类似的

但是基于信号量的话,性能会好很多,而且hystrix框架本身的开销会小很多

默认值是10,设置的小一些,否则因为信号量是基于调用线程去执行command的,而且不能从timeout中抽离,因此一旦设置的太大,而且有延时发生,可能瞬间导致tomcat本身的线程资源本占满

参考

  • 《Java工程师面试突击第1季-中华石杉老师》

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 开发人员必备Redis知识点基础命令键命令string命令hash结构listset结构sorted set

    JavaEdge
  • Hystrix 自动降级与依赖隔离1.背景2.Hystrix说明

    目前对于一些非核心操作,如增减库存后保存操作日志 发送异步消息时(具体业务流程),一旦出现MQ服务异常时,会导致接口响应超时,因此可以考虑对非核心操作引入服务降...

    JavaEdge
  • Thread 源码面试

    每个线程都有一个优先级。优先级高的线程优先于优先级低的线程执行。每个线程可能被标记为守护线程,也可能不被标记为守护线程。

    JavaEdge
  • 美团点评智能支付核心交易系统的可用性实践

    每个系统都有它最核心的指标。比如在收单领域:进件系统第一重要的是保证入件准确,第二重要的是保证上单效率。清结算系统第一重要的是保证准确打款,第二重要的是保证及时...

    静儿
  • 美团点评智能支付核心交易系统的可用性实践

    美团技术团队
  • 美团点评智能支付核心交易系统的可用性实践

    静儿
  • Linux电源驱动-Linux Cpuidle Framework

    现如今,Linux处理器电源管理重点聚焦在处理器处于运行状态时对其进行电源管理,主要的技术是Cpufreq: 根据cpu的负载,实时的改变cpu的频率或这电压...

    DragonKingZhu
  • 简单几步,教你做一名出类拔萃的配色交互师

    前言 很多小伙伴都说自己配色如屎,因为没学过色彩,没画过画,导致每次配色时都小心翼翼的。 然后去网上搜各种配色理论,看了什么冷暖、明暗等术语后开始照着去配色,然...

    BestSDK
  • 并发的核心:CAS 是什么?Java8是如何优化 CAS 的?

    大家可能都听说说 Java 中的并发包,如果想要读懂 Java 中的并发包,其核心就是要先读懂 CAS 机制,因为 CAS 可以说是并发包的底层实现原理。

    帅地
  • 并发的核心:CAS 是什么?Java8是如何优化 CAS 的?

    大家可能都听说说 Java 中的并发包,如果想要读懂 Java 中的并发包,其核心就是要先读懂 CAS 机制,因为 CAS 可以说是并发包的底层实现原理。

    猿天地

扫码关注云+社区

领取腾讯云代金券