大牛都懂的Hystrix RPC保护的原理,RPC保护之舱壁模式,你还不学

RPC保护之舱壁模式

本节为大家介绍RPC保护的重要方法——舱壁模式,并且重点介绍Hystrix线程池隔离、信号量隔离的具体配置方式。

什么是舱壁模式

船舶工业为了使船不容易沉没,使用舱壁将船舶划分为几个部分,以便在船体破坏的情况下可以将船舶各个部分密封起来。泰坦尼克号沉没的主要原因之一就是它的舱壁设计不合理,水可以通过上面的甲板进入舱壁的顶部,导致整个船体淹没。

在RPC调用过程中,使用舱壁模式可以保护有限的系统资源不被耗尽。在一个基于微服务的应用程序中,通常需要调用多个服务提供者的接口才能完成一个特定任务。不使用舱壁模式,所有的RPC调用都从同一个线程池中获取线程,一个具体的实例如图5-4所示。在该实例中,服务提供者Provider A对依赖的Provider B、Provider C、Provider D的所有RPC调用都从公共的线程池获取线程。

大牛都懂的Hystrix RPC保护的原理,RPC保护之舱壁模式,你还不学

图5-4 公共的RPC线程池

在高服务器请求的情况下,对某个性能较低的服务提供者的RPC调用很容易“霸占”整个公共的RPC线程池,对其他性能正常的服务提供者的RPC调用往往需要等待线程资源的释放。最后,整个Web容器(Tomcat)会崩溃。现在假定Provider A的RPC线程个数为1000,且并发量非常大,其中有500个线程来执行Provider B的RPC调用,此时剩下的服务Provider C、Provider D总共可用的线程为500个。如果Provider B不小心宕机了,那么这500个线程都会超时,随着并发量的增大,剩余的500个线程估计也会被Provider B的RPC耗尽,然后Provider A进入瘫痪状态,最终导致整个系统的所有服务都不可用,这就是服务的雪崩效应。

为了最大限度地减少Provider之间的相互影响,一个更好的做法是:对于不同的服务提供者可以设置不同的RPC调用线程池,让不同RPC通过专门的线程池请求到各自的Provider服务提供者,像舱壁一样对Provider进行隔离。对于不同的服务提供者设置不同的RPC调用线程池,这种模式被称为舱壁模式,如图5-5所示。

大牛都懂的Hystrix RPC保护的原理,RPC保护之舱壁模式,你还不学

图5-5 舱壁模式的RPC线程池

使用舱壁可以避免对单个Provider的RPC消耗掉所有资源,从而防止由于某一个服务性能低而引起的级联故障和雪崩效应。在Provider A中,假定对服务Provider B的RPC调用分配专门的线程池Thread PoolB,其中有10个线程,只要对Provider B的RPC并发量超过10,后续的RPC就降级服务,即使服务Provider B挂了,最多导致Thread Pool B不可用,而不会影响系统中对其他服务的RPC。

一般来说,RPC线程与Web容器的IO线程也是需要隔离的。如图5-6所示,当Provider A的用户请求涉及Provider B和Provider C的RPC时,Provider A的IO线程会将任务交给对应的RPC线程池里面的RPC线程来执行,Provider A的IO线程就可以去干别的事情去了,当RPC线程执行完远程调用的任务之后,就会将调用的结果返回给IO线程。如果RPC线程池耗尽了,IO线程池也不会受到影响,从而实现RPC线程与Web容器的IO线程的相互隔离。

大牛都懂的Hystrix RPC保护的原理,RPC保护之舱壁模式,你还不学

图5-6 RPC线程与Web容器的IO线程相互隔离

Hystrix提供了两种RPC隔离方式:线程池隔离和信号量隔离。由于信号量隔离不太适合使用在RPC调用的场景,因此这里重点介绍线程池隔离。虽然线程在就绪状态、运行状态、阻塞状态、终止状态间转变时需要由操作系统调度,这会带来一定的性能消耗,但是Netflix详细评估了使用异步线程和同步线程带来的性能差异,结果表明在99%的情况下异步线程带来的延迟仅仅几毫秒,这种性能的损耗对于用户程序来说完全是可以接受的。

 Hystrix线程池隔离

Hystrix既可以为HystrixCommand命令默认创建一个线程池,又可以关联上一个指定的线程池。每一个线程池都有一个Key,名为Thread Pool Key(线程池名)。如果没有为HystrixCommand指定线程池,Hystrix就会为HystrixCommand创建一个与GroupKey(命令组Key)同名的线程池,当然,如果与Group Key同名的线程池已经存在,就直接进行关联。也就是说,默认情况下,HystrixCommand命令的Thread Pool Key与GroupKey是相同的。总体来说,线程池是Hystrix中RPC调用隔离的关键,所有的监控、调用、缓存等都围绕线程池展开。

如果要指定线程池,可以通过如下代码在Setter中定制线程池的Key和属性:

/**
*在Setter实例中指定线程池的Key和属性
*/
HystrixCommand.Setter rpcPool1_setter = HystrixCommand.Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey("group1"))
.andCommandKey(HystrixCommandKey.Factory.asKey("command1"))
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("threadPool1"))
.andThreadPoolPropertiesDefaults(
HystrixThreadPoolProperties.Setter()
.withCoreSize(10) //配置线程池里的线程数
.withMaximumSize(10)
);

然后,可以通过HystrixCommand或者HystrixObservableCommand的构造函数将Setter配置实例传入:

@Slf4j
public class HttpGetterCommand extends HystrixCommand<String>
{
private String url;
...
public HttpGetterCommand(String url, Setter setter)
{
super(setter);
this.url = url;
}
...
}

HystrixThreadPoolKey是一个接口,它有一个辅助工厂类Factory,其asKey(String)方法专门用于创建一个线程池的Key,示例代码如下:


HystrixThreadPoolKey.Factory.asKey("threadPoolN")下面是一个完整的线程池隔离的演示例子:

创建两个线程池threadPool1和threadPool2,然后通过这两个线程池发起简单的RPC远程调用,其中通过threadPool1线程池访问一个错误连接ERROR_URL,通过threadPool2访问一个正常连接HELLO_TEST_URL。在实验过程中,可以通过调整RPC的次数多次运行程序,然后通过结果查看线程池的具体隔离效果。

线程池隔离实例的代码如下:

package com.crazymaker.demo.hystrix;
//省略import
@Slf4j
public class IsolationStrategyDemo
{
/**
*测试:线程池隔离
*/
@Test
public void testThreadPoolIsolationStrategy() throws Exception
{
/**
*RPC线程池1
*/
HystrixCommand.Setter rpcPool1_Setter = HystrixCommand.Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey("group1"))
.andCommandKey(HystrixCommandKey.Factory.asKey("command1"))
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("threadPool1"))
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withExecutionTimeoutInMilliseconds(5000) //配置执行时间上限
).andThreadPoolPropertiesDefaults(
HystrixThreadPoolProperties.Setter()
.withCoreSize(10) //配置线程池里的线程数
.withMaximumSize(10)
);
/**
*RPC线程池2
*/
HystrixCommand.Setter rpcPool2_Setter = HystrixCommand.Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey("group2"))
.andCommandKey(HystrixCommandKey.Factory.asKey("command2"))
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("threadPool2"))
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withExecutionTimeoutInMilliseconds(5000) //配置执行时间上限
).andThreadPoolPropertiesDefaults(
HystrixThreadPoolProperties.Setter()
.withCoreSize(10) //配置线程池里的线程数
.withMaximumSize(10)
);
/**
*访问一个错误连接,让threadpool1 耗尽
*/
for (int j = 1; j <= 5; j++)
{
new HttpGetterCommand(ERROR_URL, rpcPool1_Setter)
.toObservable()
.subscribe(s -> log.info(" result:{}", s));
}
/**
*访问一个正确连接,观察threadpool2是否正常
*/
for (int j = 1; j <= 5; j++)
{
new HttpGetterCommand(HELLO_TEST_URL, rpcPool2_Setter)
.toObservable()
.subscribe(s -> log.info(" result:{}", s));
}
Thread.sleep(Integer.MAX_VALUE);
}
}

运行这个示例程序,输出的结果部分节选如下:

[hystrix-threadPool1-4] INFO c.c.d.h.HttpGetterCommand - req1 begin...
[hystrix-threadPool1-3] INFO c.c.d.h.HttpGetterCommand - req4 begin...
[hystrix-threadPool2-3] INFO c.c.d.h.HttpGetterCommand - req10 begin...
[hystrix-threadPool2-5] INFO c.c.d.h.HttpGetterCommand - req7 begin...
[hystrix-threadPool1-5] INFO c.c.d.h.HttpGetterCommand - req9 begin...
[hystrix-threadPool2-1] INFO c.c.d.h.HttpGetterCommand - req6 begin...
[hystrix-threadPool1-1] INFO c.c.d.h.HttpGetterCommand - req8 begin...
[hystrix-threadPool1-2] INFO c.c.d.h.HttpGetterCommand - req2 begin...
[hystrix-threadPool2-4] INFO c.c.d.h.HttpGetterCommand - req5 begin...
[hystrix-threadPool2-2] INFO c.c.d.h.HttpGetterCommand - req3 begin...
[hystrix-threadPool1-1] INFO c.c.d.h.HttpGetterCommand - req8 fallback: 熔断false,直接失败false
[hystrix-threadPool1-4] INFO c.c.d.h.HttpGetterCommand - req1 fallback: 熔断false,直接失败false
[hystrix-threadPool1-2] INFO c.c.d.h.HttpGetterCommand - req2 fallback: 熔断false,直接失败false
[hystrix-threadPool1-3] INFO c.c.d.h.HttpGetterCommand - req4 fallback: 熔断false,直接失败false
[hystrix-threadPool1-5] INFO c.c.d.h.HttpGetterCommand - req9 fallback: 熔断false,直接失败false
...
[hystrix-threadPool2-4] INFO c.c.d.h.HttpGetterCommand - req5 end: {"respCode":0,"respMsg":"操作成功...}
[hystrix-threadPool2-2] INFO c.c.d.h.HttpGetterCommand - req3 end: {"respCode":0,"respMsg":"操作成功...}
[hystrix-threadPool2-3] INFO c.c.d.h.HttpGetterCommand - req10 end: {"respCode":0,"respMsg":"操作成功...}
[hystrix-threadPool2-1] INFO c.c.d.h.HttpGetterCommand - req6 end: {"respCode":0,"respMsg":"操作成功...}
[hystrix-threadPool2-5] INFO c.c.d.h.HttpGetterCommand - req7 end: {"respCode":0,"respMsg":"操作成功...}
...

从上面的输出结果可以看出:threadPool1的线程使用和threadPool2的线程使用是完全相互独立和相互隔离的,无论threadPool1是否耗尽,threadPool2的线程都可以正常发起RPC请求。

默认情况下,在Spring Cloud中,Hystrix会为每一个Command Group Key自动创建一个同名的线程池。而在Hystrix客户端,每一个RPC目标Provider的Command Group Key默认值为它的应用名称(Application Name),比如,demo-provider服务的CommandGroup Key默认值为它的名称demo-provider。所以,如果某个Provider(如uaaprovider)需要发起对demo-provider的远程调用,那么Hystrix为该Provider创建的RPC线程池的名称默认为demo-provider,专门用于对demo-provider的REST服务进行RPC调用和隔离,如图5-7所示。

大牛都懂的Hystrix RPC保护的原理,RPC保护之舱壁模式,你还不学

图5-7 对demo-provider服务进行RPC调用的专用线程池

Hystrix线程池隔离配置

在Spring Cloud服务提供者中,如果需要使用Hystrix线程池进行RPC隔离,就可以在应用的配置文件中进行相应的配置。下面是demoprovider的RPC线程池配置的实例:

hystrix:
threadpool:
default:
coreSize: 10 #线程池核心线程数
maximumSize: 20 #线程池最大线程数
allowMaximumSizeToDivergeFromCoreSize: true #线程池maximumSize最大线程数是否生效
keepAliveTimeMinutes:10 #设置可空闲时间,单位为分钟
command:
default: #全局默认配置
execution: #RPC隔离的相关配置
isolation:
strategy: THREAD #配置请求隔离的方式,这里为线程池方式
thread:
timeoutInMilliseconds: 100000 #RPC执行的超时时间,默认为1000毫秒
interruptOnTimeout: true #发生超时后是否中断方法的执行,默认值为true

对上面的实例中用到的与Hystrix线程池有关的配置项介绍如下:

(1)
hystrix.threadpool.default.coreSize:设置线程池的核心线程数。

(2)
hystrix.threadpool.default.maximumSize:设置线程池的最大线程数,起作用的前提是allowMaximumSizeToDivergeFromCoreSize的属性值为true。

maximumSize属性值可以等于或者大于coreSize值,当线程池的线程不够用时,Hystrix会创建新的线程,直到线程数达到maximumSize的值,创建的线程为非核心线程。

(3)
hystrix.threadpool.default.allowMaximumSizeToDivergeFromCoreSize:该属性允许maximumSize起作用。

(4)
hystrix.threadpool.default.keepAliveTimeMinutes:该属性设置非核心线程的存活时间,如果某个非核心线程的空闲超过keepAliveTimeMinutes设置的时间,非核心线程就会被释放。其单位为分钟,默认值为1,默认情况下,表示非核心线程空闲1分钟后释放。

(5)
hystrix.command.default.execution.isolation.strategy:该属性设置RPC远程调用HystrixCommand命令的隔离策略。它有两个可选值:

THREAD和SEMAPHORE,默认值为THREAD。THREAD表示使用线程池进行RPC隔离,SEMAPHORE表示通过信号量来进行RPC隔离和限制并发量。

(6)
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds:设置调用者等待HystrixCommand命令执行的超时限制,超过此时间,HystrixCommand被标记为TIMEOUT,并执行回退逻辑。超时会作用在HystrixCommand.queue(),即使调用者没有调用get()去获得Future对象。

以上配置是application应用级别的默认线程池配置,覆盖的范围为系统中的所有RPC线程池。有时需要为特定的Provider服务提供者进行特殊的配置,比如当某个Provider接口访问的并发量非常大,是其他Provider的几十倍,它的远程调用需要更多的RPC线程时,就可以单独为其进行专门的RPC线程池配置。作为示例,在demo-Provider中对uaaProvider的RPC线程池配置如下:

hystrix:
threadpool:
default:
coreSize: 10 #线程池核心线程数
maximumSize: 20 #线程池最大线程数
allowMaximumSizeToDivergeFromCoreSize: true #线程池最大线程数是否有效
uaa-provider:
coreSize: 20 #线程池核心线程数
maximumSize: 100 #线程池最大线程数
allowMaximumSizeToDivergeFromCoreSize: true #线程池最大线程数是否有效

上面的配置中使用了
hystrix.threadpool.uaa-provider配置项前缀,其中uaa-provider部分为RPC线程池的Thread Pool Key,也就是默认的Command Group Key。

在调用处理器HystrixInvocationHandler的invoke(...)方法内设置断点,在调试时,通过查看hystrixCommand对象的值可以看出,demo-provider中针对服务提供者uaa-provider的RPC线程池配置已经生效,如图5-8所示。

大牛都懂的Hystrix RPC保护的原理,RPC保护之舱壁模式,你还不学

图5-8 针对uaa-provider的RPC线程池配置已经生效

Hystrix信号量隔离

除了使用线程池进行资源隔离之外,Hystrix还可以使用信号量机制完成资源隔离。

信号量所起到的作用就像一个开关,而信号量的值就是每个命令的并发执行数量,当并发数高于信号量的值时就不再执行命令。比如,如果Provider A的RPC信号量大小为10,那么它同时只允许有10个RPC线程来访问服务Provider A,其他的请求都会被拒绝,从而达到资源隔离和限流保护的作用。

Hystrix信号量机制不提供专用的线程池,也不提供额外的线程,在获取到信号量之后,执行HystrixCommand命令逻辑的线程还是之前Web容器的IO线程。

信号量可以细分为run执行信号量和fallback回退信号量。

IO线程在执行HystrixCommand命令之前需要抢到run执行信号量,成功之后才允许执行HystrixCommand.run()方法。如果争抢失败,就准备回退,但是在执行
HystrixCommand.getFallback()回退方法之前,还需要争抢fallback回退信号量,成功之后才允许执行HystrixCommand.getFallback()回退方法。如果都获取失败,操作就会直接终止。

在图5-9所示的例子中,假设有5个Web容器的IO线程并发进行RPC远程调用,但是执行信号量的大小为3,也就是只有3个IO线程能够真正地抢到run执行信号量,这些线程才能发起RPC调用。剩下的两个IO线程准备回退,去抢fallback回退信号量,争抢成功后执行
HystrixCommand.getFallback()回退方法。

大牛都懂的Hystrix RPC保护的原理,RPC保护之舱壁模式,你还不学

图5-9 5个Web容器的IO线程争抢信号量

下面是一个模拟Web容器进行RPC调用的演示程序,其中使用一个拥有50个线程的线程池模拟Web容器的IO线程池,并使用随书编写的HttpGetterCommand命令模拟RPC调用。

实验之前,需要提前启动demo-provider服务的REST接口/api/demo/hello/v1。

为了演示信号量隔离,演示程序所设置的run执行信号量和fallback回退信号量都为4,并且通过IO线程池同时提交了50个模拟的RPC调用去争抢这些信号量,演示程序的代码如下:

package com.crazymaker.demo.hystrix;
//省略import
@Slf4j
public class IsolationStrategyDemo
{
 /**
 *测试: 信号量隔离
 */
 @Test
 public void testSemaphoreIsolationStrategy() throws Exception
 {
 /**
 *命令属性实例
 */
 HystrixCommandProperties.Setter commandProperties = HystrixCommandProperties.Setter()
 .withExecutionTimeoutInMilliseconds(5000) //配置时间上限
 .withExecutionIsolationStrategy(
 //隔离策略为信号量隔离
 HystrixCommandProperties.ExecutionIsolationStrategy
.SEMAPHORE
 )
 //HystrixCommand.run()方法允许的最大请求数 .withExecutionIsolationSemaphoreMaxConcurrentRequests(4)
 //HystrixCommand.getFallback()方法允许的最大请求数目
 .withFallbackIsolationSemaphoreMaxConcurrentRequests(4);
 /**
 *命令的配置实例
 */
 HystrixCommand.Setter setter = HystrixCommand.Setter
 .withGroupKey(HystrixCommandGroupKey.Factory.asKey("group1"))
 .andCommandKey(HystrixCommandKey.Factory.asKey("command1"))
 .andCommandPropertiesDefaults(commandProperties);
 /**
 *模拟Web容器的IO线程池
 */
 ExecutorService mock_IO_threadPool =
 Executors.newFixedThreadPool(50);
 /**
 *模拟Web容器收到50并发请求
 */
 for (int j = 1; j <= 50; j++)
 {
 mock_IO_threadPool.submit(() ->
 {
 /**
 *RPC调用
 */
 new HttpGetterCommand(HELLO_TEST_URL, setter)
 .toObservable()
 .subscribe(s -> log.info(" result:{}", s));
 });
 }
 Thread.sleep(Integer.MAX_VALUE);
 }
}

执行此演示实例之前需要提前启动crazydemo.com(指向127.0.0.1)主机上的demoprovider服务提供者。demo-provider启动之后再执行上面的演示程序,运行的结果节选如下:

[pool-2-thread-35] INFO c.c.d.h.HttpGetterCommand - req3 fallback:熔断false,直接失败true,失败次数3
[pool-2-thread-45] INFO c.c.d.h.HttpGetterCommand - req4 fallback:熔断false,直接失败true,失败次数4
[pool-2-thread-7] INFO c.c.d.h.HttpGetterCommand - req2 fallback:熔断false,直接失败true,失败次数2
[pool-2-thread-15] INFO c.c.d.h.HttpGetterCommand - req1 fallback:熔断false,直接失败true,失败次数1
[pool-2-thread-35] INFO c.c.d.h.IsolationStrategyDemo - result:req3:调用失败
...
[pool-2-thread-27] INFO c.c.d.h.HttpGetterCommand - req7 begin...
[pool-2-thread-18] INFO c.c.d.h.HttpGetterCommand - req6 begin...
[pool-2-thread-13] INFO c.c.d.h.HttpGetterCommand - req5 begin...
[pool-2-thread-48] INFO c.c.d.h.HttpGetterCommand - req8 begin...
[pool-2-thread-18] INFO c.c.d.h.HttpGetterCommand - req6 end: {"respCode":0,"respMsg":"操作成功...}
[pool-2-thread-48] INFO c.c.d.h.HttpGetterCommand - req8 end: {"respCode":0,"respMsg":"操作成功...}
[pool-2-thread-27] INFO c.c.d.h.HttpGetterCommand - req7 end: {"respCode":0,"respMsg":"操作成功...}
[pool-2-thread-13] INFO c.c.d.h.HttpGetterCommand - req5 end: {"respCode":0,"respMsg":"操作成功...}
[pool-2-thread-13] INFO c.c.d.h.IsolationStrategyDemo - result:req5:{"respCode":0,"respMsg":"操作成功...}
...

通过结果可以看出:

(1)执行RPC远程调用的线程就是模拟IO线程池中的线程。

(2)虽然提交了50个RPC调用,但是只有4个RPC调用抢到了执行信号量,分别为req5、req6、req7、req8。(3)虽然失败了46个RPC调用,但是只有4个RPC调用抢到了回退信号量,分别为req1、req2、req3、req4。

使用信号量进行RPC隔离是有自身弱点的。实际RPC远程调用最终是由Web容器的IO线程来完成,这样就带来了一个问题,由于RPC远程调用是一种耗时的操作,如果IO线程被长时间占用,就会导致Web容器请求处理能力下降,甚至会在一段时间内因为IO线程被占满而造成Web容器无法对新的用户请求及时响应,最终导致Web容器崩溃。所以,信号量隔离机制不适用于RPC隔离。但是,对于一些非网络的API调用或者耗时很小的API调用,信号量隔离机制的效率比线程池隔离机制的效率更高。

再来看信号量的配置,这一次使用代码的方式进行命令属性配置,涉及Hystrix命令属性配置器
HystrixCommandProperties.Setter()的实例方法如下:

(1)
withExecutionIsolationSemaphoreMaxConcurrentRequests(int):此方法设置执行信号量的大小,也就是HystrixCommand.run()方法允许的最大请求数。如果达到最大请求数,后续的请求就会被拒绝。

在Web容器中,抢占信号量的线程应该是容器(比如Tomcat)IO线程池中的一小部分,所以信号量的数量不能大于容器线程池的大小,否则就起不到保护作用。执行信号量的大小默认值为10。

如果使用属性配置而不是代码的方式进行配置,那么以上代码配置所对应的配置项为:

hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests

(2)withFallbackIsolationSemaphoreMaxConcurrentRequests(int):

此方法设置回退信号量的大小,也就是
HystrixCommand.getFallback()方法允许的最大请求数。

如果达到最大请求数,后续的回退请求就会被拒绝。

如果使用属性配置而不是代码的方式进行配置,那么以上代码配置所对应的配置项为:

hystrix.command.default.fallback.isolation.semaphore.maxConcurrentRequests

最后介绍信号量隔离与线程池隔离的区别,分别从调用线程、开销、异步、并发量4个维度进行对比,具体如表5-1所示。

大牛都懂的Hystrix RPC保护的原理,RPC保护之舱壁模式,你还不学

表5-1 调用线程、开销、异步、并发量4个维度的对比

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Hystrix底层实现原理主要包括以下几个方面: 1. Hystrix使用了大量的RxJava,它是基于观察者模式的实现。RxJava原理可以简单了解一下。 2. Hystrix可以使用基于信号量的隔离机制,信号量用于控制并发访问量。了解一下信号量的作用和原理。 3. Hystrix使用命令模式来封装具体的服务调用逻辑,并在命令模式中添加了服务调用失败后的降级逻辑。可以通过继承HystrixCommand类或HystrixObservableCommand类来实现。在命令的构造方法中可以定义当前服务的线程池和熔断器的相关参数。 总结起来,Hystrix底层实现原理涉及了RxJava、观察者模式、信号量和命令模式。这些原理的理解对于理解Hystrix的工作机制是很有帮助的。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Spring Cloud教程 第五弹 Hystrix底层原理基础篇](https://blog.csdn.net/xl_1803/article/details/109674023)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Hystrix、Feign技术底层实现原理](https://blog.csdn.net/yzdx22697400/article/details/106353149)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值