章节索引 :

Hystrix 资源隔离概念讲解与实操

1. 前言

在本节中,我将为各位同学介绍 Hystrix 的最后一个特性,那就是服务资源隔离。虽然服务资源隔离是 Hystrix 的最后一个特性,但是其在 Hystrix 中占着举足轻重的地位,同时,也是治理微服务项目的重要举措,所以各位一定要学好本节内容。

本节主要内容:

  • 服务资源隔离概念介绍;

  • Hystrix 实现服务资源隔离。

2. 什么是服务资源隔离

在我们正式介绍什么是服务资源隔离之前,我们先来了解一些前置的概念,这些概念是理解服务资源隔离的前提。

进程与线程

进程:进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在当代面向线程设计的计算机结构中,进程是线程的容器。

我们可以把进程理解为我们项目运行的载体,就比如我们乘坐的公交车,公交车相对于我们来说就是一个载体,来承载我们到达不同的目的地,进程就是如此,只不过在进程中被承载的是线程罢了。

线程:线程(Thread)是操作系统能够进行运算调度的最小单位。我们可以把线程理解为,执行某一具体的计算机系统任务的执行者,比如在公交车中,负责开公交车的司机师傅就可以被当做一个线程。

在一个进程中,可以存在多个线程,即在一辆公交车中可以存在多名乘客,他们分别都去往不同的目的地,但是,一个线程只能属于一个进程,不属于不同的两个进程,即一名乘客同一时刻只能乘坐一辆公交车,不可能在同一时刻乘坐两辆公交车。

在理解了什么是进程与线程之后,我们来看一下在我们的 Web 项目中,进程与线程都是怎样存在的,以及他们之间的关系是怎样的。

Web 项目中的进程与线程

我们的每一个 Web 项目都可以被看作一个进程,且一个 Web 项目只能是一个进程。在我们的 Web 项目中,常规情况下只有两个线程,分别是主线程和工作线程,其中,主线程负责我们的项目启动以及一些项目初始化工作,而工作线程则主要负责项目中的请求处理与业务逻辑执行,项目中进程与线程的关系如下图所示:

Java Web 项目中进程与线程的关系

根据上图,我们可以这样理解:一个 Web 项目在计算机系统中就是一个进程,而在这个进程中,存在一个主线程和一个工作线程,并且主线程主要负责项目启动,而工作线程主要负责请求的处理。

在理解了这个关系之后,让我们来看一下什么是服务资源隔离。

服务资源隔离

在介绍服务资源隔离之前,我们需要先了解什么是服务资源。

服务资源一般来讲,指的是项目正常运行所需要的基础环境、基础设施、静态资源文件等内容,而对于 Web 项目来说,其项目本身即是一种服务资源,服务调用者通过调用项目提供的服务来满足他们的业务需求。

而对于服务提供者来说,这些业务需求的实现在项目中一般就是我们所开发的接口,所以,在项目中所实现的业务接口即是我们这里所说的服务资源。

那么,为什么需要把服务资源进行隔离呢?

我们知道,正常情况下,在 Web 项目中只有一个工作线程,且这个工作线程负责接口请求的处理。在正常应用场景下,服务调用者会调用我们项目所提供的接口来满足业务需求,这里假设我们的一个 Web 项目中具有 5 个接口,服务调用者会根据业务顺序来调用我们的接口,如果一切顺利,则业务即可正常顺利地进行下去。

但是,如果服务调用者在调用接口时,其中一个接口所需要处理的业务比较复杂,导致这个接口不能及时的结束,这就导致我们后续的接口调用只能等待,直到该接口处理完毕后才能继续向下执行,如果该接口一直不能处理完毕,则后续接口就会一直等待,从而影响业务的正常开展,这种现象就被称为服务资源等待,如下图所示:

服务资源等待产生原理

我们可以把上图中的工作线程访问理解为服务调用者,在服务调用者调用接口 2 时,由于接口 2 迟迟不能处理,导致接口 2 出现服务等待,并最终影响后续的接口 3、接口 4、接口 5 的调用,从而影响了业务的顺利进行。

如果通过采取某种措施,使满足同一业务需求的不同服务资源间进行隔离,来有效缓解或解决服务资源等待问题,那么业务就可以正常顺利地开展下去,所以人们就提出了服务资源隔离的概念

3. Hystrix 实现服务资源隔离

在 Hystrix 中,实现服务资源隔离有两种方式,分别是线程池隔离和信号量隔离。

3.1 线程池隔离实现服务资源隔离

通过对处理项目中的工作线程的隔离,来避免工作线程处理接口时所产生的阻塞行为,从而保证工作线程可以顺利地调用接口来满足业务需要。

而隔离工作线程的方式,就是为每个接口分配一个线程池,并在线程池中维护一定数量的线程,这样,当上述的接口 2 发生服务资源等待时,由于每个接口都分配了不同的线程池,所以不会影响到后续的 3 4 5 接口,如下图所示:

线程池隔离实现原理

可以看到,由于为每个服务接口均分配了不同的线程池,所以在接口 2 出现服务等待时,并不会影响后续接口的调用,从而保证了业务的顺利进行。

我们继续以 hello 方法为例,来看如何实现线程池隔离。

@RequestMapping(value = "hello", method = RequestMethod.GET)
@HystrixCommand(threadPoolKey = "HelloHystrix", threadPoolProperties = {
    @HystrixProperty(name = "coresize", value = "2"),
    @HystrixProperty(name = "allowMaximumSizeToDivergeFromCoreSize", value = "true"),
    @HystrixProperty(name = "maximumSize", value = "2"),
    @HystrixProperty(name = "maxQueueSize", value = "2")
})
@ResponseBody
public String hello() throws InterruptedException {
    return "helloWorld";
}

代码解释:

第 2 行,我们通过配置 HystrixCommand 注解的 threadPoolKey 属性来为本接口分配一个名称为 HelloHystrix 的线程池。

第 3 行,我们通过配置 threadPoolProperties 中的参数属性,来维护 HelloHystrix 线程池中的核心线程数量、最大线程数量。

通过添加上述注解并配置其中的属性,我们就可以通过线程池隔离的方式来实现服务资源隔离。

Tips: 线程池中的线程数量,一定要根据该接口所实现的业务需求来设置,设置过多,则会浪费资源空间,设置过少,则不能支撑业务需要,所以配置线程数量一定要谨慎。

3.2 信号量隔离实现服务资源隔离

信号量隔离和线程池隔离的方式很相似,只不过把分配线程池的方式改为了分配信号量(至于什么是信号量,请同学们自行查阅)。

在处理请求时,Hystrix 会分配一个信号量的阀值,当服务接收到一个请求后,信号量的阀值减 1 ,当请求处理完毕后,信号量的阀值加 1,当信号量的阀值减为 0 时,则不再接收请求,即该请求会被拒绝处理。

@RequestMapping(value = "hello", method = RequestMethod.GET)
@HystrixCommand(fallbackMethod="helloFail", commandProperties = {
@HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_STRATEGY, value = "SEMAPHORE"),
@HystrixProperty(name = HystrixPropertiesManager.EXECUTION_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS, value = "100")
})
@ResponseBody
public String hello() throws InterruptedException {
    return "helloWorld";
}

public String helloFail() {
    return "helloFailed";
}

代码解释:

第 4 行,通过指定 HystrixPropertiesManager.EXECUTION_ISOLATION_STRATEGY 参数的值为 SEMAPHORE ,来声明该接口使用信号量隔离。

第 7 行,通过指定 HystrixPropertiesManager.EXECUTION_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS 参数的值为 100 ,可以理解为设置信号量的阀值为 100 。

通过添加上述配置参数,我们就可以通过信号量隔离的方式来实现服务资源隔离。

Tips: 一定要合理设置信号量的阀值,不要随意设定,如果阀值设置过大,则请求不会停止,如果阀值设置过小,则不能满足业务需要。

4. 视频演示

5. 小结

本节内容概览

本小节从服务资源隔离的前提概念开始介绍,采用图文并茂的方式,详细介绍了进程和线程、Web 项目中的进程与线程、服务资源隔离产生的原因,以及服务资源隔离的概念;接着,我们采用代码实现的方式,对 Hystrix 中的线程池隔离和信号量隔离这两种实现服务资源隔离的措施进行了介绍,并对其中需要注意的地方做了补充。

服务资源隔离是微服务项目治理中的最后一关,同时也是至关重要的一关,微服务项目经常由于服务没有响应而导致后续服务瘫痪,所以,掌握服务资源隔离是保证微服务项目正常运行的关键所在。