SpringCloud Hystrix
Hystrix简介
Hystrix是由Netflix开源的一个延迟和容错库,用于隔离访问远程系统、服务或者第三方库,防止级联失败,从而提升系统的可用性、容错性与局部应用的弹性,是一个实现了超时机制和断路器模式的工具类库。
听起来很官方,很难理解,我们先来看几个问题。
微服务之间会相互调用,这个调用不单单是两级或者一对一,也许会出现A调用B,B调用C,C还调用了D,E,F等等。假如此时D挂掉了,咋办?C得等着,C等着B就得等着,B等着A就得等着。这时候又来一个Q调用B,Q也得等着,巴拉巴拉。那你老等着哪里行啊?服务器的资源就那么多,等的请求多了,资源就没了,后面再来的请求咋办?于是出现了挂了一个D,慢慢整个系统都挂掉了。这就是微服务调用可能产生的雪崩效应。
以上,假如就算D并没有挂掉,但是网络这时候故障了,连不到D,咋办?
再假如,这时候D很忙啊,你的请求不知道排到哪里去了?你得一直等很久?咋办?
再再假如,一切都很正常,那效率问题呢?分布式情况下,各自服务是独立的,完后一个功能不单单一个服务就能解决的。解决问题需要时间,网络通信也需要时间啊。怎么把这个通信时间更优化呢?
现在,我们再说,Hystrix就是解决上述问题的解决方案。
Hystrix的设计原则
防止由于单个服务的故障,而耗尽整个系统容器(Tomcat,Jetty)的线程资源
避免请求排队和积压,采用限流和fail fast来控制故障
提供服务降级(ballback)处理机制
使用隔离技术(如舱壁隔离、永道和断路器模式)来隔离服务依赖之间的影响
通过实时的监控和告警,及时发现系统中的潜在问题
通过配置更改可以优化低延迟传播的恢复时间,并且Hystrix支持大多数属性的动态更改,从而允许开发者可以实时对低延迟反馈循序进行修改和优化
提供对整个所依赖客户端在执行过程中的故障保护与隔离,而不仅仅是网络流量
Hystrix功能
资源隔离
资源隔离分为两种,线程隔离和信号量隔离。不管是哪一种都可以设置阈值,线程池的大小啊,信号量的大小啊,来实现限流。
线程隔离
我们正常的请求是这样的,每次调用的接口都是一个线程池里面的资源。

当一个服务出现故障时会导致整个服务的宕机。

如果我们将服务分为一个线程池独立运行的时候则会防止整个系统的宕机。

因此,使用一个线程池来存储当前请求,线程池对请求作处理,设置任务返回处理超时时间,堆积的请求先入线程池队列。这种方式要为每个依赖服务申请线程池,有一定的资源消耗,好处是可以应对突发流量(流量洪峰来临时,处理不完可将数据存储到线程池队里慢慢处理)。
线程池隔离优缺点
优点:
保护应用程序以免受来自依赖故障的影响,指定依赖线程池饱和不会影响应用程序的其余部分。
当引入新客户端lib时,即使发生问题,也是在本lib中,并不会影响到其他内容。
当依赖从故障恢复正常时,应用程序会立即恢复正常的性能。
当应用程序一些配置参数错误时,线程池的运行状况会很快检测到这一点(通过增加错误,延迟,超时,拒绝等),同时可以通过动态属性进行实时纠正错误的参数配置。
如果服务的性能有变化,需要实时调整,比如增加或者减少超时时间,更改重试次数,可以通过线程池指标动态属性修改,而且不会影响到其他调用请求。
除了隔离优势外,hystrix拥有专门的线程池可提供内置的并发功能,使得可以在同步调用之上构建异步门面(外观模式),为异步编程提供了支持(Hystrix引入了Rxjava异步框架)。
注意:尽管线程池提供了线程隔离,我们的客户端底层代码也必须要有超时设置或响应线程中断,不能无限制的阻塞以致线程池一直饱和。
缺点:
线程池的主要缺点是增加了计算开销。每个命令的执行都在单独的线程完成,增加了排队、调度和上下文切换的开销。因此,要使用Hystrix,就必须接受它带来的开销,以换取它所提供的好处。
通常情况下,线程池引入的开销足够小,不会有重大的成本或性能影响。但对于一些访问延迟极低的服务,如只依赖内存缓存,线程池引入的开销就比较明显了,这时候使用线程池隔离技术就不适合了,我们需要考虑更轻量级的方式,如信号量隔离。
下面是一个网上的线程池隔离的例子,摘自知乎,如果看了之前的几篇博客,这里应该看的懂得:
@Service
public class ProductService {
@Autowired
private LoadBalancerClient loadBalancerClient;// ribbon负载均衡器
@HystrixCommand(groupKey="ego-product-provider", commandKey = "getUsers",
threadPoolKey="ego-product-provider",
threadPoolProperties = {
@HystrixProperty(name = "coreSize", value = "30"),//线程池大小
@HystrixProperty(name = "maxQueueSize", value = "100"),//最大队列长度
@HystrixProperty(name = "keepAliveTimeMinutes", value = "2"),//线程存活时间
@HystrixProperty(name = "queueSizeRejectionThreshold", value = "15")//拒绝请求
},
fallbackMethod = "fallback")
public List<Product> getUsers() {
System.out.println(Thread.currentThread().getName());
// 选择调用的服务的名称
// ServiceInstance 封装了服务的基本信息,如 IP,端口
ServiceInstance si = this.loadBalancerClient.choose("ego-product-provider");
// 拼接访问服务的URL
StringBuffer sb = new StringBuffer();
// http://localhost:9001/product/findAll
sb.append("http://").append(si.getHost()).append(":").append(si.getPort()).append("/product/findAll");
System.out.println(sb.toString());
// springMVC RestTemplate
RestTemplate rt = new RestTemplate();
ParameterizedTypeReference<List<Product>> type = new ParameterizedTypeReference<List<Product>>() {
};
// ResponseEntity:封装了返回值信息
ResponseEntity<List<Product>> response = rt.exchange(sb.toString(), HttpMethod.GET, null, type);
List<Product> list = response.getBody();
return list;
}
//返回托底数据的方法
public List<Product> fallback(){
System.out.println(Thread.currentThread().getName());
List<Product> list = new ArrayList<>();
list.add(new Product(-1, "我是托底数据"));
return list;
}
public void showThread(){
System.out.println(Thread.currentThread().getName());
}
}

信号量隔离
上面提到了线程池隔离的缺点,当依赖延迟极低的服务时,线程池隔离技术引入的开销超过了它所带来的好处。这时候可以使用信号量隔离技术来代替,通过设置信号量来限制对任何给定依赖的并发调用量。同时也是限流的一种表现。
这种方法就是,大家用的还是一个线程池,但是我给请求设置一个值上限就是信号量,代表的是当前处理请求的线程数,每来一个请求,我看信号量当前有没有达到上限,没达到,处理请求,信号量加一,处理完了返回,信号量减一,信号量达到上限了,你再来请求,fallback。先提一下,fallback是干嘛滴。就是说,请求满了,你等会再来吧,我现在处理不了你,而不是让你等着我处理完其他的再来处理你。当然这是最简单的处理模式,还有故障转移等。

@Service
public class ProductService {
@Autowired
private LoadBalancerClient loadBalancerClient;// ribbon负载均衡器
@HystrixCommand(
fallbackMethod = "fallback",
commandProperties = {
@HystrixProperty(name=HystrixPropertiesManager.EXECUTION_ISOLATION_STRATEGY,value="SEMAPHORE"),// 信号量 隔离
@HystrixProperty(name=HystrixPropertiesManager.EXECUTION_ISOLATION_SEMAPHORE_MAX_CONCURRENT_REQUESTS, value="100")//信号量最大并度
})
public List<Product> getUsers() {
System.out.println(Thread.currentThread().getName());
// 选择调用的服务的名称
// ServiceInstance 封装了服务的基本信息,如 IP,端口
ServiceInstance si = this.loadBalancerClient.choose("ego-product-provider");
// 拼接访问服务的URL
StringBuffer sb = new StringBuffer();
// http://localhost:9001/product/findAll
sb.append("http://").append(si.getHost()).append(":").append(si.getPort()).append("/product/findAll");
System.out.println(sb.toString());
// springMVC RestTemplate
RestTemplate rt = new RestTemplate();
ParameterizedTypeReference<List<Product>> type = new ParameterizedTypeReference<List<Product>>() {
};
// ResponseEntity:封装了返回值信息
ResponseEntity<List<Product>> response = rt.exchange(sb.toString(), HttpMethod.GET, null, type);
List<Product> list = response.getBody();
return list;
}
//返回托底数据的方法
public List<Product> fallback(){
System.out.println(Thread.currentThread().getName());
List<Product> list = new ArrayList<>();
list.add(new Product(-1, "我是托底数据"));
return list;
}
public void showThread(){
System.out.println(Thread.currentThread().getName());
}
}

由于Hystrix默认使用线程池做线程隔离,使用信号量隔离需要显示地将属性execution.isolation.strategy设置为ExecutionIsolationStrategy.SEMAPHORE,同时配置信号量个数,默认为10。客户端需向依赖服务发起请求时,首先要获取一个信号量才能真正发起调用,由于信号量的数量有限,当并发请求量超过信号量个数时,后续的请求都会直接拒绝,进入fallback流程。
信号量隔离主要是通过控制并发请求量,防止请求线程大面积阻塞,从而达到限流和防止雪崩的目的。

请求合并
先看没有请求合并的处理模型:

我们看到很多个请求是到同一个微服务的,但是有多少请求就开多少个线程,如果高并发的时候则会对整个的服务器造成压力,有合并的请求则是这种情况;

我们可以把很多个对同一个微服务的请求,打包一起发过去,只需要一个线程资源就搞定了,在高并发的情况下大大减少了服务器的压力。
总结一下:
在微服务架构中,我们将一个项目拆分成很多个独立的模块,这些独立的模块通过远程调用来互相配合工作,但是,在高并发情况下,通信次数的增加会导致总的通信时间增加,同时,线程池的资源也是有限的,高并发环境会导致有大量的线程处于等待状态,进而导致响应延迟,为了解决这些问题,Hystrix 提供了HystrixCollapser来实现请求的合并,以减少通信消耗和线程数的占用。HystrixCollapser实现了在 HystrixCommand之前放置一个合并处理器,将处于一个很短的时间窗(默认10毫秒)内对同一依赖服务的多个请求进行整合,并以批量方式发起请求的功能(前提是服务提供方提供相应的批量接口)。HystrixCollapser的封装多个请求合并发送的具体细节,开发者只需关注将业务上将单次请求合并成多次请求即可。
请求合并不是什么场景都适合的,看一下它的模式和开销
模式:请求合并模式会维护一个时间窗口,默认是10ms,那么就意味着,它会把10ms内的所有同一个微服务的请求打包,一起发出去。每10ms一次。
开销:用于请求合并的延迟时间窗会使得依赖服务的请求延迟增高。比如,某个请求不通过请求合并器访问的平均耗时为5ms,请求合并的延迟时间窗为l0ms , 那么当该请求设置了请求合并器之后,最坏情况下(在延迟时间 窗结束时才发起请求)该请求需要15ms才能完成。
适合请求合并的情况:
请求命令本身的延迟,对于单次请求而言,如果[单次请求平均时间/时间窗口]越小,对于单次请求的性能形象越小。如果依赖服务的请求命令本身是一个高延迟的命令,那么可以使用请求合并器,因为延迟时间窗的时间消耗显得微不足道了。
并发量,时间窗口内并发量越大,合并求情的性能提升越明显。如果一个时间窗内只有少数几个请求,那么就不适合使用请求合并器。相反,如果一个时间窗内具有很高的并发量,那么使用请求合并器可以有效减少网络连接数量并极大提升系统吞吐量,此时延迟时间窗所增加的消耗就可以忽略不计了。
@Service
public class ProductService {
//利用hystrix合并请求
@HystrixCollapser(batchMethod = "batchProduct", scope = com.netflix.hystrix.HystrixCollapser.Scope.GLOBAL,
collapserProperties = {
//请求时间间隔在20ms之内的请求会被合并为一个请求,默认为10ms
@HystrixProperty(name = "timerDelayInMilliseconds", value = "20"),
//设置触发批处理执行之前,在批处理中允许的最大请求数。
@HystrixProperty(name = "maxRequestsInBatch", value = "200"),
})
//consumer的controller调用的方法 该方法返回值必须要返回Future类型
public Future<Product> getProduct(Integer id){
System.out.println("=========="+id+"==========");
return null;
}
@HystrixCommand
//调用Provider服务的方法
public List<Product> batchProduct(List<Integer> ids){
for(Integer id:ids){
System.out.println(id);
}
//假设是调用provider服务后返回的list
List<Product> list = new ArrayList<>();
list.add(new Product(1, "电视"));
list.add(new Product(2, "电脑"));
list.add(new Product(3, "冰箱"));
list.add(new Product(4, "手电筒"));
list.add(new Product(100,"list............"));
System.out.println("ddddddddddddddddddddddd");
return list;
}
}

熔断器
我们之前介绍的都是正常情况下请求很多该咋整,那么不正常了咋办呢?比如,微服务挂了,网络故障了,难道还要一遍一遍的请求,一遍一遍的失败?有没有一种模式可以让一个请求知道服务器现在不能访问,不用问了,直接返回吧。就像是你去买车票,有些窗口直接给你一个暂停售票,你就知道,这不能提供服务了,难道还要一遍一遍的问,你这卖不卖票?当然是直接走开了。
现实生活中,可能大家都有注意到家庭电路中通常会安装一个保险盒,当负载过载时,保险盒中的保险丝会自动熔断,以保护电路及家里的各种电器,这就是熔断器的一个常见例子。Hystrix中的熔断器(Circuit Breaker)也是起类似作用,Hystrix在运行过程中会向每个commandKey对应的熔断器报告成功、失败、超时和拒绝的状态,熔断器维护并统计这些数据,并根据这些统计信息来决策熔断开关是否打开。如果打开,熔断后续请求,快速返回。隔一段时间(默认是5s)之后熔断器尝试半开,放入一部分流量请求进来,相当于对依赖服务进行一次健康检查,如果请求成功,熔断器关闭。
看一张图:

开始时断路器处于关闭状态(Closed)。
如果调用持续出错、超时或失败率超过一定限制,断路器打开进入熔断状态,后续一段时间内的所有请求都会被直接拒绝。
一段时间以后,保护器会尝试进入半熔断状态(Half-Open),允许少量请求进来尝试;如果调用仍然失败,则回到熔断状态,如果调用成功,则回到电路闭合状态;
熔断器啥时候打开,打开后多久重试,错误率是多少啊?可以配置:
circuitBreaker.enabled:是否启用熔断器,默认是TRUE。
circuitBreaker.forceOpen:熔断器强制打开,始终保持打开状态,不关注熔断开关的实际状态。默认值FLASE。
circuitBreaker.forceClosed:熔断器强制关闭,始终保持关闭状态,不关注熔断开关的实际状态。默认值FLASE。
circuitBreaker.errorThresholdPercentage:错误率,默认值50%,例如一段时间(10s)内有100个请求,其中有54个超时或者异常,那么这段时间内的错误率是54%,大于了默认值50%,这种情况下会触发熔断器打开。
circuitBreaker.requestVolumeThreshold:默认值20。含义是一段时间内至少有20个请求才进行errorThresholdPercentage计算。比如一段时间了有19个请求,且这些请求全部失败了,错误率是100%,但熔断器不会打开,总请求数不满足20。
circuitBreaker.sleepWindowInMilliseconds:半开状态试探睡眠时间,默认值5000ms。如:当熔断器开启5000ms之后,会尝试放过去一部分流量进行试探,确定依赖服务是否恢复。
总结,当触发熔断器打开的时候,所有的请求,全部fallback。直到熔断器关闭,再正常请求。
熔断器的工作流程:

第一步,调用allowRequest()判断是否允许将请求提交到线程池
如果熔断器强制打开,circuitBreaker.forceOpen为true,不允许放行,返回。
如果熔断器强制关闭,circuitBreaker.forceClosed为true,允许放行。此外不必关注熔断器实际状态,也就是说熔断器仍然会维护统计数据和开关状态,只是不生效而已。
第二步,调用isOpen()判断熔断器开关是否打开
如果熔断器开关打开,进入第三步,否则继续;
如果一个周期内总的请求数小于circuitBreaker.requestVolumeThreshold的值,允许请求放行,否则继续;
如果一个周期内错误率小于circuitBreaker.errorThresholdPercentage的值,允许请求放行。否则,打开熔断器开关,进入第三步。
第三步,调用allowSingleTest()判断是否允许单个请求通行,检查依赖服务是否恢复
如果熔断器打开,且距离熔断器打开的时间或上一次试探请求放行的时间超过circuitBreaker.sleepWindowInMilliseconds的值时,熔断器器进入半开状态,允许放行一个试探请求;否则,不允许放行。
此外,为了提供决策依据,每个熔断器默认维护了10个bucket,每秒一个bucket,当新的bucket被创建时,最旧的bucket会被抛弃。其中每个blucket维护了请求成功、失败、超时、拒绝的计数器,Hystrix负责收集并统计这些计数器。
回退降级
上边一直说fallback,有朋友就很懵,啥是fallback。就是回退降级。就是这个服务挂了或是怎么样了不能处理请求了,要么直接说,我不能处理请求,你先想想别的办法吧?要么说,我不能处理请求,你先拿一点缓存的数据去用一用救救急吧,要么说,我不能处理请求,我给你介绍个其他服务器,你去找它吧。等等。
降级,通常指务高峰期,为了保证核心服务正常运行,需要停掉一些不太重要的业务,或者某些服务不可用时,执行备用逻辑从故障服务中快速失败或快速返回,以保障主体业务不受影响。Hystrix提供的降级主要是为了容错,保证当前服务不受依赖服务故障的影响,从而提高服务的健壮性。保证上游服务的稳定性,当整体资源快不够了,将某些服务先关掉,待渡过难关,再开启回来。要支持回退或降级处理,可以重写HystrixCommand的getFallBack方法或HystrixObservableCommand的resumeWithFallback方法。
Hystrix在以下几种情况下会走降级逻辑:
执行construct()或run()抛出异常,就是执行请求时,出现异常。
熔断器打开导致命令短路
命令的线程池和队列或信号量的容量超额,命令被拒绝
命令执行超时
降级回退方式
快速返回
如果调用服务失败了,那么立即失败并返回。

在这个模式里面,fallback可以什么都不做,那么直接抛出异常。你可以写简单逻辑,比如返回特定信息,以便于你的客户端这边做相应的处理,或者返回空值等等。
故障转移
如果调用服务失败了,那么调用备用服务,因为备用服务也可能失败,所以也可能有再下一级的备用服务,如此形成一个级联。例如:如果服务提供者不响应,则从缓存中取默认数据。

主次模式
就是请求时,会有两个服务处理者,一个老大,一个老二,你发起请求,先找老大,老大整得了就整,忙不过来或者出了问题就说,你去找老二,于是你再去老二,老二整得了你也算成功,老二整不了,对不起,走fallback。
主要和次要逻辑涉及到不同的网络调用和业务逻辑,所以需要将主次逻辑封装在不同的Command中,使用线程池进行隔离。为了实现主从逻辑切换,可以将主次command封装在外观HystrixCommand的run方法中,并结合配置中心设置的开关切换主从逻辑。由于主次逻辑都是经过线程池隔离的HystrixCommand,因此外观HystrixCommand可以使用信号量隔离,而没有必要使用线程池隔离引入不必要的开销。
这里是别人写的一个例子,有助于理解。
public class CommandFacadeWithPrimarySecondary extends HystrixCommand<String> {
private final static DynamicBooleanProperty usePrimary = DynamicPropertyFactory.getInstance().getBooleanProperty("primarySecondary.usePrimary", true);
private final int id;
public CommandFacadeWithPrimarySecondary(int id) {
super(Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey("SystemX"))
.andCommandKey(HystrixCommandKey.Factory.asKey("PrimarySecondaryCommand"))
.andCommandPropertiesDefaults(
// 由于主次command已经使用线程池隔离,Facade Command使用信号量隔离即可
HystrixCommandProperties.Setter()
.withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE)));
this.id = id;
}
@Override
protected String run() {
if (usePrimary.get()) {
return new PrimaryCommand(id).execute();
} else {
return new SecondaryCommand(id).execute();
}
}
@Override
protected String getFallback() {
return "static-fallback-" + id;
}
@Override
protected String getCacheKey() {
return String.valueOf(id);
}
private static class PrimaryCommand extends HystrixCommand<String> {
private final int id;
private PrimaryCommand(int id) {
super(Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey("SystemX"))
.andCommandKey(HystrixCommandKey.Factory.asKey("PrimaryCommand"))
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("PrimaryCommand"))
.andCommandPropertiesDefaults( HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(600)));
this.id = id;
}
@Override
protected String run() {
return "responseFromPrimary-" + id;
}
}
private static class SecondaryCommand extends HystrixCommand<String> {
private final int id;
private SecondaryCommand(int id) {
super(Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey("SystemX"))
.andCommandKey(HystrixCommandKey.Factory.asKey("SecondaryCommand"))
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("SecondaryCommand"))
.andCommandPropertiesDefaults( HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(100)));
this.id = id;
}
@Override
protected String run() {
return "responseFromSecondary-" + id;
}
}
public static class UnitTest {
@Test
public void testPrimary() {
HystrixRequestContext context = HystrixRequestContext.initializeContext();
try {
ConfigurationManager.getConfigInstance().setProperty("primarySecondary.usePrimary", true);
assertEquals("responseFromPrimary-20", new CommandFacadeWithPrimarySecondary(20).execute());
} finally {
context.shutdown();
ConfigurationManager.getConfigInstance().clear();
}
}
@Test
public void testSecondary() {
HystrixRequestContext context = HystrixRequestContext.initializeContext();
try {
ConfigurationManager.getConfigInstance().setProperty("primarySecondary.usePrimary", false);
assertEquals("responseFromSecondary-20", new CommandFacadeWithPrimarySecondary(20).execute());
} finally {
context.shutdown();
ConfigurationManager.getConfigInstance().clear();
}
}
}
}
但是有一点,fallback逻辑是请求失败要返回的信息,所以这个里面的逻辑不要有可能失败的因素,出错那不是白写了吗。
运维监控
断路器的状况反应了一个程序的可用性和健壮性,它是一个重要指标。Hystrix Dashboard是作为断路器状态的一个组件,提供了数据监控和友好的图形化界面,通过监控该面板,可以很直观的看到每一个服务请求在短时间内(10s)的请求量,以及成功率,失败率,耗时等信息,可以给后期的系统优化提供依据。等下配置的时候再详细看看都有什么信息。
Hystrix简单配置
导入依赖
<!-- 导入hystrix依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
修改controller
package com.haogenmin.provider2.controller;
import com.haogenmin.model.Product;
import com.haogenmin.provider2.service.ProductService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/provider")
public class ProductController {
@Autowired
private ProductService productService;
@RequestMapping(value = "products", method = RequestMethod.POST)
public boolean add(@RequestBody Product product) {
return productService.add(product);
}
@HystrixCommand(fallbackMethod = "getFallback")
@RequestMapping(value = "products/{id}", method = RequestMethod.GET)
public Product get(@PathVariable("id") Long id) {
Product product = productService.get(id);
//模拟异常
if(product == null) {
throw new RuntimeException("ID=" + id + "无效");
}
return product;
}
@RequestMapping(value = "products", method = RequestMethod.GET)
public List<Product> list() {
return productService.list();
}
public Product getFallback(@PathVariable("id") Long id) {
return new Product(id,
"ID=" + id + "无效--@HystrixCommand",
"无有效数据库");
}
}
开启熔断
package com.haogenmin.provider2;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
/**
* @author :HaoGenmin
* @Title :Provider_02_Application
* @date :Created in 2020/6/28 10:37
* @description:
*/
@SpringBootApplication
@EnableEurekaClient
@EnableHystrix
public class Provider_02_Application {
public static void main(String[] args) {
SpringApplication.run(Provider_02_Application.class,args);
}
}
测试


运维监控简单配置

新建一个项目
导入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>parent</artifactId>
<groupId>com.haogenmin.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>hystrix_dashboard</artifactId>
<dependencies>
<dependency>
<groupId>com.haogenmin.springcloud</groupId>
<artifactId>model</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--导入 hystrix 与 hystrix-dashboard 依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
</dependencies>
</project>
开启服务监控
package com.haogenmin.hystrix_dashboard;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
/**
* @author :HaoGenmin
* @Title :DashboardApplication
* @date :Created in 2020/7/30 13:29
* @description:
*/
@EnableHystrixDashboard
@SpringBootApplication
public class DashboardApplication {
public static void main(String[] args) {
SpringApplication.run(DashboardApplication.class,args);
}
}
设定端口
server:
port: 9001
访问

为要被监控的服务添加配置
添加依赖
在需要被监控的服务里面进行一下修改,如在两个provider中进行如下修改。
<!--监控依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
暴露端点
在provider项目配置文件中添加
management:
endpoints:
web:
exposure:
include: hystrix.stream
测试

当我们访问8001的时候,监控图像如下

如何查看监控页面
7色 :右上角
1圈:实心圆共有两种含义。
它通过颜色的变化代表了实例的健康程度,它的健康度从绿色<黄色<橙色<红色递减。
该实心圆除了颜色的变化之外,它的大小也会根据实例的请求流量发生变化,流量越大该实心圆就越大。所以通过该实心圆的展示,就可以在大量的实例中快速的发现故障实例和高压力实例。
1线:曲线用来记录2分钟内流量的相对变化,可以通过它来观察到流量的上升和下降趋势。
图说明


浙公网安备 33010602011771号