Hystrix从原理到使用
文章目录
一、什么是Hystrix
- 源自Martin Fowler的Circuit Breaker,即断路器。“断路器”本身是一种开关装置,用于线路上的过载保护,当线路发生短路时,会及时切断故障电路,防止一系列问题。
- 在分布式架构中,断路器模式也是类似,当某个单元发生故障,及时切断联系,防止线程因调用故障服务而长时间等待而不被释放,最终导致故障在分布式系统中的蔓延。
- Hystrix实现的功能有:服务降级、服务熔断、线程和信号隔离、请求缓存、请求合并、以及服务监控等功能。(对于请求缓存功能,个人建议不要使用,除非该实例是单机运行,否则会出现数据不一致的问题)
二、Hystrix的原理
在讲解Hystrix的原理之前,先介绍两种设计模式,分别是:命令模式、观察者模式。
1、命令模式
以上就是命令模式的图示:Invoker为行为请求者、Receiver为行为实现者。以下列出这种模式的伪代码:
public class InvokerAndReceiver {
/**
* 命令的抽象
*/
interface Command {
void execute();
}
/**
* 调用者
*/
static class Invoker {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void execute() {
command.execute();
}
}
/**
* 业务的具体实现
*/
static class Receiver {
public void action() {
//do some task.
System.out.println("doing...");
}
}
/**
* 命令的封装
*/
static class CommandImpl implements Command {
private Receiver receiver;
public CommandImpl(Receiver receiver) {
this.receiver = receiver;
}
@Override
public void execute() {
receiver.action();
}
}
public static void main(String[] args) {
Receiver receiver=new Receiver();
Command command=new CommandImpl(receiver);
Invoker invoker=new Invoker();
invoker.setCommand(command);
invoker.execute();
}
}
2、观察者模式
观察者模式的实现模型与订阅模式类似,这里以Hystrix底层使用的RxJava作为介绍。
public static void main(String[] args) {
//被观察者,也是事件源
Observable<String> source=Observable.create(subscriber -> {
subscriber.onNext("Hello !");
subscriber.onNext("welcome to subscribe it.");
//事件源通知异常。
subscriber.onError(new NullPointerException("error"));
//结束
subscriber.onCompleted();
});
//观察者
Subscriber<String> subscriber=new Subscriber<String>() {
@Override
public void onCompleted() {
//完成后的工作
}
@Override
public void onError(Throwable throwable) {
//观察者在这处理异常的事务
}
@Override
public void onNext(String s) {
//获取事件源的持续信息,如果事件源持续发布事件。
System.err.println(s);
}
};
source.subscribe(subscriber);
}
以下是观察者模式的两种分类:
- 热观察
- 每个观察者都可以在事件源的中途加入,这会造成看到的是加入后的局部信息。
- 冷观察
- 事件源需要等待观察者加入后,才发布事件,这样,看到的是全部过程。
好了,介绍完这两种模式,我们才能够分析Hystrix的底层原理。
3、原理分析
首先,我们从@HystrixCommand注解入手。
@HystrixCommand(fallbackMethod = "fallBack")
public String hiService() {
return restTemplate.getForObject("http://provider/zone?",String.class);
}
@HystrixCommand注解会为当前方法创建一个HystrixCommand对象,这个类的主要作用是命令模式中对于Command的封装,执行命令有如下两个方法:
//用于异步请求,返回的是Future对象,包含服务执行结束时会返回的结果对象。
public Future<R> queue() {
/*
* The Future returned by Observable.toBlocking().toFuture() does not implement the
* interruption of the execution thread when the "mayInterrupt" flag of Future.cancel(boolean) is set to true;
* thus, to comply with the contract of Future, we must wrap around it.
*/
final Future<R> delegate = toObservable().toBlocking().toFuture();
final Future<R> f = new Future<R>() {
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
if (delegate.isCancelled()) {
return false;
}
if (HystrixCommand.this.getProperties().executionIsolationThreadInterruptOnFutureCancel().get()) {
interruptOnFutureCancel.compareAndSet(false, mayInterruptIfRunning);
}
final boolean res = delegate.cancel(interruptOnFutureCancel.get());
if (!isExecutionComplete() && interruptOnFutureCancel.get()) {
final Thread t = executionThread.get();
if (t != null && !t.equals(Thread.currentThread())) {
t.interrupt();
}
}
return res;
}
@Override
public boolean isCancelled() {
return delegate.isCancelled();
}
@Override
public boolean isDone() {
return delegate.isDone();
}
@Override
public R get() throws InterruptedException, ExecutionException {
return delegate.get();
}
@Override
public R get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
return delegate.get(timeout, unit);
}
};
/* special handling of error states that throw immediately */
if (f.isDone()) {
try {
f.get();
return f;
} catch (Exception e) {
Throwable t = decomposeException(e);
if (t instanceof HystrixBadRequestException) {
return f;
} else if (t instanceof HystrixRuntimeException) {
HystrixRuntimeException hre = (HystrixRuntimeException) t;
switch (hre.getFailureType()) {
case COMMAND_EXCEPTION:
case TIMEOUT:
// we don't throw these types from queue() only from queue().get() as they are execution errors
return f;
default:
// these are errors we throw from queue() as they as rejection type errors
throw hre;
}
} else {
throw Exceptions.sneakyThrow(t);
}
}
}
return f;
}
//用于同步执行,从依赖服务返回单一对象结果;调用的是queue.get
public R execute() {
try {
return queue().get();
} catch (Exception e) {
throw Exceptions.sneakyThrow(decomposeException(e));
}
}
除去HystrixCommand,还有HystrixObservableCommand,该类主要实现两个方法:
- observe() 这是一个热观察
- toObservable() 这是一个冷观察
实际上,excute() 的实现是queue(),而queue中,我们可以看到有如下:
//使用了冷观察;并且转化成为Future异步对象。
final Future<R> delegate = toObservable().toBlocking().toFuture();
因此,我们可以知道,Hstrix命令的运行有如下两个重要部分:
- 事件源处理(冷、热观察模式)
- 同、异步处理(同步等待返回结果,异步利用Future对象,可以异步处理其它工作,并且最后获取future中需要的结果返回即可)
以下说一下Hystrix的命令执行,用图说明:
在Hystrix中,断路器概念核心,以下是它的定义:
public interface HystrixCircuitBreaker {
//每个Hystrix命令请求,在执行之前,都会调用这个方法,判断当前是否可以执行。
public boolean allowRequest();
//判断开闭状态
public boolean isOpen();
//当断路器处于半开状态,且命令运行成功,则用于关闭断路器
void markSuccess();
}
断路器的实现有多个,采用内部类实现:
//都不实现
static class NoOpCircuitBreaker implements HystrixCircuitBreaker {
@Override
public boolean allowRequest() {
return true;
}
@Override
public boolean isOpen() {
return false;
}
@Override
public void markSuccess() {
}
}
//默认实现
static class HystrixCircuitBreakerImpl implements HystrixCircuitBreaker {
private final HystrixCommandProperties properties;
private final HystrixCommandMetrics metrics;
/* track whether this circuit is open/closed at any given point in time (default to false==closed) */
private AtomicBoolean circuitOpen = new AtomicBoolean(false);
/* when the circuit was marked open or was last allowed to try a 'singleTest' */
private AtomicLong circuitOpenedOrLastTestedTime = new AtomicLong();
//还有具体几个方法的实现。
}
对于断路器来说,断路器会根据本身的状态,即断路器是否开启,来决定这个HystrixCommand命令是否执行,还是调用fallBack进行降级,断路器开启和关闭的度量标准如下,由度量对象metrics获取healthCount进行判断,这个时间窗口默认为10S:
- QPS在预设的阈值之内,则返回false,默认为20。
- 如果错误请求百分比,在预设阈值之下,则返回false。
源码如下:
@Override
public boolean isOpen() {
if (circuitOpen.get()) {
return true;
}
HealthCounts health = metrics.getHealthCounts();
// check if we are past the statisticalWindowVolumeThreshold
if (health.getTotalRequests() < properties.circuitBreakerRequestVolumeThreshold().get()) {
// we are not past the minimum volume threshold for the statisticalWindow so we'll return false immediately and not calculate anything
return false;
}
if (health.getErrorPercentage() < properties.circuitBreakerErrorThresholdPercentage().get()) {
return false;
} else {
// our failure rate is too high, trip the circuit
if (circuitOpen.compareAndSet(false, true)) {
// if the previousValue was false then we want to set the currentTime
circuitOpenedOrLastTestedTime.set(System.currentTimeMillis());
return true;
} else {
return true;
}
}
}
判断是否允许:
@Override
public boolean allowRequest() {
//这个地方要注意,我们看到了,强制开启的优先级大于强制关闭。
if (properties.circuitBreakerForceOpen().get()) {
return false;
}
if (properties.circuitBreakerForceClosed().get()) {
isOpen();
return true;
}
//这里通过两个方法的结合使用,实现关闭、开启的切换
return !isOpen() || allowSingleTest();
}
//这个方法的功能是尝试允许命令请求;
public boolean allowSingleTest() {
long timeCircuitOpenedOrWasLastTested = circuitOpenedOrLastTestedTime.get();
// 1) if the circuit is open
// 2) and it's been longer than 'sleepWindow' since we opened the circuit
if (circuitOpen.get() && System.currentTimeMillis() > timeCircuitOpenedOrWasLastTested + properties.circuitBreakerSleepWindowInMilliseconds().get()) {
// We push the 'circuitOpenedTime' ahead by 'sleepWindow' since we have allowed one request to try.
// If it succeeds the circuit will be closed, otherwise another singleTest will be allowed at the end of the 'sleepWindow'.
if (circuitOpenedOrLastTestedTime.compareAndSet(timeCircuitOpenedOrWasLastTested, System.currentTimeMillis())) {
//尝试允许请求,则使得断路器处于半开状态。
return true;
}
}
return false;
}
以上是允许请求的实现:
- 通过allowSingleTest,尝试允许请求访问。
- 通过设置休眠时间,在休眠时间过去之后,则将断路器处于“半开状态”,这种半开状态,实际是就是允许命令请求的执行,如果执行又失败,或者超时,则又将断路器置于全开状态;并且在休眠时间之后,尝试允许,继续处于半开状态。
关闭断路器的实现如下:
public void markSuccess() {
if (circuitOpen.get()) {
//关闭断路器
if (circuitOpen.compareAndSet(true, false)) {
//win the thread race to reset metrics
//Unsubscribe from the current stream to reset the health counts stream. This only affects the health counts view,
//and all other metric consumers are unaffected by the reset
//重置统计信息
metrics.resetStream();
}
}
}
以上就是Hystrix的原理部分,但是,我们忽略了一个重要部分,即Hystrix的线程隔离。
a.舱壁模式
如果读者对Docker已经熟悉,那么,舱壁模式也一定不会陌生。Docker就是通过舱壁模式,实现进程之间的隔离,使得容器与容器之间不会互相影响。
而Hystrix则是使用该模式,对线程进行隔离,使得不同的Hystrix命令请求可以由不同的线程池(可以指定)创建线程去向服务提供者发送请求。
- 优点
- 应用自身得到保护,线程池被填满,应用其它部分正常工作。
- 线程池隔离,使得不同的服务依赖之间不会互相影响,能够保证服务的稳定。
- 缺点
- 使用线程池隔离,会使得请求发送会有一小部分的延时(几ms)。
综合以上优缺点,如果你的服务是一个要求实时性非常高,哪怕是几ms也不行,那么建议不要使用线程池隔离;而如果可以容忍几ms的延时,那么,使用线程池带来的稳定性是没法媲美的。
三、如何使用Hystrix
Hystrix的使用有两种方式:一种是使用优雅的注解形式,一种是使用灵活的代码继承。在这里,我只讲解注解形式的使用。
- 依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
- 启动主类
第一种方式
@SpringBootApplication
@EnableCircuitBreaker
第二种方式
@SpringCloudApplication
@SpringCloudApplication这个注解的具体内容如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public @interface SpringCloudApplication {
}
- 在服务方法上添加
@HystrixCommand
注解
/**
* 同步执行
*
* @return 返回一个直接结果
*/
@HystrixCommand(fallbackMethod = "fallbackMethod",ignoreExceptions = IOException.class,commandKey = "methodname",groupKey = "组键,一般按类名来",threadPoolKey = "线程池的key")
public String synRequest() {
return restTemplate.getForObject("URL", String.class);
}
注意:threadPoolKey 属性如果没有指定,那么,则会根据groupKey来分配线程池。
- 处理不同的命令执行的错误结果
/**
* private、public、protected all can define this method.
* but you should care of one tip, this method should be in thisClass.
*/
private String defaultFallBack(Throwable throwable) {
if (throwable instanceof IOException) {
//do io service fallback
} else if (throwable instanceof HttpClientErrorException) {
//do request error fallback
} else {
return "";
}
return "";
}
注意:通过添加Throwable throwable方法参数,并且对类型进行判断,则可以做不同的服务降级的处理。
- 异步请求
/**
* 异步
* can use ignoreException specify the type of ex to avoid service fallback by throwing anyEx
* expect HystrixBadRequestException.So,use this character,we can catch the different type of ex do different solve.
* just to add the <code>Throwable e</code> as the fallback Method parameter.
*
* @return 返回异步对象。
*/
@HystrixCommand(fallbackMethod = "defaultFallBack",commandProperties = {
//设置具体实例的超时时间,如果不设置,则采用全局的默认1S
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "5000"),
//下面的超时配置默认为启动,可以修改为false。来保证某个实例不启用超时
@HystrixProperty(name = "execution.timeout.enabled",value = "false")
})
public Future<String> asyncRequest() {
return new AsyncResult<String>() {
//这里是异步请求
@Override
public String invoke() {
return restTemplate.getForObject("URL", String.class);
}
};
}
- 请求合并
@HystrixCollapser(batchMethod = "batchRequest",collapserProperties = {
//等待时间
@HystrixProperty(name = "timeDelayInMillseconds",value = "100"),
//每个批处理最大的请求数
@HystrixProperty(name = "maxRequestsInBatch",value = "10"),
//不要开启请求缓存。这个功能就是个毫无意义的功能。
@HystrixProperty(name = "requestCacheEnabled",value = "false")
})
public String singleRequest(){
return null;
}
public List<String> batchRequest(){
return restTemplate.getForObject("URL",List.class);
}
注意:请求合并,需要服务端有多一个提供批量响应的接口。当每个用户请求过来,按照以上配置,每隔100ms就会将批量请求发送出去。或者满足达到最大批量处理数,则发送出去。这种情况很适合在网络繁忙或者线程资源紧张的时候,因为合并之后,只会发送一次网络请求。
合并前的请求图示:
合并请求后的图示:
关于Hystrix的使用就讲解到这里,后面会讲解详细配置与优化、监控
四、详细配置与Hystrix监控优化
1、详细配置
-
Command属性
execution配置 ,控制的是HystrixCommand.run()的执行。
#隔离策略;默认为THREAD 可通过@HystrixProperty (name="execution.isolation.strategy", value= "THREAD")注解设置 #value有两种,一种是线程THREAD;一种是信号量 SEMAPHORE。
execution.isolation. 七hread.timeoutinMilliseconds
#run方法执行超时策略;默认1000MS @HystrixProperty(name= "execution.isolation.thread.timeoutinMilliseconds",value="2000") 注解来设置
execution.timeout.enabled: 该属性用来配置HystrixCommand.run()的 执行是否启用超时时间。 默认为true, 如果设置为false,那么超时设置不起作用。
可通过@HystrixProperty(name= "execution.timeout.enabled", value="false")注解来设置
execution.isolation.thread.interruptOnTimeout: 该属性用来配置当 HystrixCommand.run()执行超时的时候是否要将它中断。
可通过@HystrixProperty(name="execution.isolation.thread.interruptOnTimeout", value="false")注解来设置
execution.isolation. thread.interruptOnCancel: 该属性用来配置当 HystrixCommand.run()执行被取消的时候是否要将它中断。
可通过@HystrixProperty(name="execution.isolation.thread.interruptOnCancel", value="false")注解来设置
-
fallback配置
fallback.isolation.semaphore.maxConcurrentRequests: 该属性用来 设置从调用线程中允许HystrixCommand.getFallback()方法执行的最大并发请求数。 当达到最大并发请求数时,后续的请求将会被拒绝并抛出异常。
#默认为20 @HystrixProperty (name="fallback.isolation.semaphore.maxConcurrentRequests", value="20")注解来设置
fallback.enabled: 该属性用来设置服务降级策略是否启用, 如果设置为false, 那么当请求失败或者拒绝发生时, 将不会调用HystrixCommand.getFallback() 来执行服务降级逻辑。
#默认为true 可通过@HystrixProperty(name= "fallback. enabled", value="false")注解来设置
-
circuitBreaker配置
circuitBreaker.enabled: 该属性用来确定当服务请求命令失败时, 是否使用 断路器来跟踪其健康指标和熔断请求。
#默认为true 可通过H@ystrixProperty(name="circuitBreaker. enabled",value="false")注解来设置
circuitBreaker.requestVolumeThreshold: 该属性用来设置在滚动时间窗 中,断路器熔断的最小请求数。 例如,默认该值为20的时候,如果滚动时间窗(默 认10秒)内仅收到了19个请求,即使这19个请求都失败了,断路器也不会打开。
#默认为20 可以@HystrixProperty(name= "circuitBreaker.requestVolumeThreshold", value="30")注解
circuitBreaker.sleepWindowinMilliseconds: 该属性用来设置当断路器 打开之后的休眠时间窗。 休眠时间窗结束之后,会将断路器置为 “半开” 状态,尝试熔断的请求命令,如果依然失败就将断路器继续设置为 “打开” 状态,如果成功 就设置为 “关闭” 状态。
#默认5000MS @HystrixProperty (name="circuitBreaker.sleepWindowinMilliseconds",value="3000") 注解来设置
circuitBreaker.errorThresholdPercentage: 该属性用来设置断路器打开 的错误百分比条件。 例如,默认值为 50 的情况下,表示在滚动时间窗中,在请求 数量超过circuitBreaker.reques七VolumeThreshold阅值的前提下,如果 错误请求数的百分比超过50, 就把断路器设置为 “打开” 状态, 否则就设置为 “关 闭 ” 状态。
可通 过@HystrixProperty (name="circuitBreaker.errorThresholdPercentage", value="40") 注解来设置
circuitBreaker.forceOpen: 如果将该属性设置为 true, 断路器将强制进入“打 开” 状态, 它会拒绝所有请求。 该属性优先于 circuitBreaker.forceClosed 属性。
@HystrixProperty (name="circuitBreaker. forceOpen", value="true")注解来设置
circuitBreaker.forceClosed: 如果将该属性设置为 true, 断路器将强制进入 “关闭” 状态, 它会接收所有请求。 如果 circuitBreaker.forceOpen 属性为 true, 该属性不会生效。
可通过@HystrixProperty(name= "circui七Breaker.forceClosed", value="true")注解来设置
- metrics配置
metrics.rollingStats.timeinMilliseconds: 该属性用来设置滚动时间窗 的长度, 单位为毫秒。 该时间用于断路器判断健康度时需要收集信息的持续时间。 断路器在收集指标信息的时候会根据设置的时间窗长度拆分成多个 “ 桶” 来累计各 度量值, 每个 “ 桶” 记录了一段时间内的采集指标。 例如, 当采用默认值10000毫 秒时, 断路器默认将其拆分成10个桶(桶的数量也可通过metrics.rollingStats.numBuckets参数设置), 每个桶记录1000毫秒内的指标信息。
@HystrixProperty(name="metrics.rollingStats.timeinMilliseconds", value="20000")注解来设置
metrics.rollingstats.numBuckets: 该属性用来设置滚动时间窗统计指标 信息时划分 “ 桶” 的数量。
@HystrixProperty(name="metrics.rollingStats.numBuckets",value="20")注 解来设置
注意:metrics.rollingStats.timeinMilliseconds与metrics.rollingStats.numBuckets必须存在整除关系。
metrics.rollingPercente.enabled: 该属性用来设置对命令执行的延迟 是否使用百分位数来跟踪和计算。 如果设置为false, 那么所有的概要统计都将返回 -1。
@HystrixProperty (name="metrics.rollingPercentile.enabled", value="false")注解 来设置
metrics.rollingPercentile.timeinMilliseconds: 该属性用来设置百分 位统计的滚动窗口的持续时间, 单位为毫秒。
默认值60000
@HystrixProperty(name="metrics.rollingPercentile.timeinMilli seconds", value="6OOOO")注解来设置
metrics.rollingPercentile.numBuckets: 该属性用来设置百分位统计滚 动窗口中使用 “桶 ”的数量。
默认值6
@HystrixProperty (name="metrics.rollingPercentile.numBuckets",value="6")注解来设 置
注意:以上两者同样保持整除关系。
metrics.rollingPercentile.bucketSize: 该属性用来设置在执行过程中 每个 “桶 ” 中保留的最大执行次数。 如果在滚动时间窗内发生超过该设定值的执行 次数, 就从最初的位置开始重写。 例如, 将该值设置为100, 滚动窗口为10秒, 若 在10秒内一个 “桶” 中发生了500次执行, 那么该 “桶” 中只保留 最后的100次执 行的统计。 另外, 增加该值的大小将会增加内存量的消耗, 并增加排序百分位数所 需的计算时间。
#de 100
@HystrixProperty(name="metrics. rollingPercentile.bucketSize",value= "120")注解来设置
metrics.healthSnapshot.intervalinMilliseconds: 该属性用来设置采 集影响断路器状态的健康快照(请求的成功、 错误百分比)的间隔等待时间。
#默认500
通过@HystrixProperty(name="metrics.healthSnapshot.intervalinMilliseconds",value= "600")注解来设置
-
collapser属性
@HystrixCollapser中的collapserProperties属性来设置.
maxRequestsinBatch: 该参数用来设置 一次请求合并批处理中允许的最大请求数。 默认为最大整数
timerDelayinMilliseconds: 该参数用来设置批处理过程中每个命令延迟的时 间,单位为毫秒。 默认为10MS -
thread Pool属性
配置方式
threadPoolProperties = {
@HystrixProperty(name = "coreSize",value = "20")
//线程池的最大队列长度。
,@HystrixProperty(name = "maxQueueSize",value = "-1"),
//队列最大拒绝阈值,没有达到队列最大值,也能拒绝。
@HystrixProperty(name = "queueSizeRejectionThreshold",value = "5")
}
2、监控优化
以上我们学习了Hystrix的详细配置,知道了这么多项的配置信息,每一项都与我们服务的性能、稳定性息息相关,但是,这么多的配置信息又令人有点乱,不知道如何入手,不知道自己的系统的配置到底应该是怎么的。
没关系,与Hystrix相对应的一款开源监控工具,Hystrix-DashBoard,也称为仪表盘,就是用于实时监控服务的性能、请求等信息。下面我将介绍怎么使用这款监控工具。
- 引入依赖
<!-- metrics 监控-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
- 启动类注解
@EnableHystrixDashboard//开启仪表盘
- 配置文件
management:
endpoints:
web:
exposure:
include: ["hystrix.stream"]
- SpringBoot2.0注册路径Bean
//在启动类中注册
@Bean
public ServletRegistrationBean servletRegistrationBean() {
ServletRegistrationBean registration = new ServletRegistrationBean(
new HystrixMetricsStreamServlet(), "/hystrix.stream");
registration.setName("hystrixServlet");
registration.setLoadOnStartup(1);
return registration;
}
- 启动浏览器访问IP:PORT/hystrix即可。有如下页面:
于是,我们可以根据服务的监控状况,对配置进行修改、优化,达到最符合我们应用需求的配置。
五、总结
- Hystrix提供服务降级、线程隔离、服务熔断等功能
- Hystrix至少涉及了:命令模式、观察者模式、舱壁模式
- Hystrix配置项很多,但是,我们可以根据具体要求进行优化。利用DashBoard的监控。
- Hystrix的特别要点:
- 同区域Zone的服务,降级后,可以访问其它服务。但是对于熔断的服务就采用降级策略。
- 对于不同Zone的服务,降级后,不可以访问其它Zone下的相同服务。
- 因此:使用时候,应注意,部分业务不跨区,使用Hystrix;部分业务跨区,不适用Hystrix。