高阶知识"/>
十一、 Hystrix的高阶知识
11.1 request collapser请求合并技术
第六章(Request Cache请求缓存)优化过一个批量查询的接口了,request cache来做优化,相同的请求参数就可以直接取用缓存了的记录。但仍需要一次业务操作接口中需要发送多次网络请求,调用多次接口,才能拿到结果。可以使用HystrixCollapser将多个HystrixCommand合并到一起,多个command放在一个command里面去执行,发送一次网络请求,就拉取到多条数据。用请求合并技术,将多个请求合并起来,可以减少高并发访问下需要使用的线程数量以及网络连接数量,这都是hystrix自动进行的,其实对于高并发的访问来说,是可以提升性能。
|
|
- 请求合并有很多种级别:
(1)global context,tomcat所有调用线程,对一个依赖服务的任何一个command调用都可以被合并在一起,hystrix就传递一个HystrixRequestContext。
(2)user request context,tomcat内某一个调用线程,将某一个tomcat线程对某个依赖服务的多个command调用合并在一起
(3)object modeling,基于对象的请求合并,如果有几百个对象,遍历后依次调用每个对象的某个方法,可能导致发起几百次网络请求,基于hystrix可以自动将对多个对象模型的调用合并到一起。
- 请求合并的优缺点(不针对那种访问延时特别低的请求的):
缺点:使用请求合并技术的开销就是导致延迟大幅度增加,因为需要一定的时间将多个请求合并起来。
优点:可以大幅度削减你的线程池的资源耗费,线程池。减少你对后端服务访问时的网络资源的开销。
- 请求合并模式及参数选择
将多个command请求合并到一个command中执行
请求合并时,可以设置一个batch size,以及elapsed time(控制什么时候触发合并后的command执行)
有两种合并模式,一种是request scope,另一种是global scope,默认是rquest scope,在collapser构造的时候指定scope模式。
request scope的batch收集是建立在一个request context内的,而global scope的batch收集是横跨多个request context的,所以对于global context来说,必须确保能在一个command内处理多个requeset context的请求
在netflix,是只用request scope请求合并的,因为默认是用唯一一个request context包含所有的command,所以要做合并,肯定就是request scope。请求合并技术,对于那种访问同一个资源的command,但是参数不同,是很有效的。
public static void main(String[] args) { String associatedIds = "1,2,3,3,4,4,5"; String url ="http://localhost:……?associatedIds="; List<Future<String>> futures = new ArrayList<Future<String>>(); for(String associatedId : associatedIds.split(",")) { JoinExamWholeAnalysisCollapser getUserInfosCollapser = new JoinExamWholeAnalysisCollapser(associatedId,url); futures.add(getUserInfosCollapser.queue()); } try { for(Future<String> future : futures) { System.out.println("CacheController的结果:" + future.get()); } } catch (Exception e) { e.printStackTrace(); } }
|
一个批量的查询ids过来以后,我们还是多个command的方式去执行,request collapser+request cache,相同的查询id还是就查询一次,不同的商品合并到一起通过一个网络请求得到结果。
private final class BatchCommand extends HystrixCommand<List<String>>{ public final Collection<CollapsedRequest<String,String>> requests; private String url;
public BatchCommand(Collection<CollapsedRequest<String,String>> requests, String url) { super(Setter .withGroupKey(HystrixCommandGroupKey.Factory.asKey("AssociatedExamAllCourses")) .andCommandKey(HystrixCommandKey.Factory.asKey("JoinExamWholeAnalysisesCollapserBatchCommand")) ); this.requests = requests; this.url = url; }
@Override protected List<String> run() throws Exception { StringBuilder paramsBuilder = new StringBuilder(""); for(CollapsedRequest<String, String> request : requests) { paramsBuilder.append(request.getArgument()).append(","); } String params = paramsBuilder.toString(); params = params.substring(0, params.length() - 1); // 在这里,我们可以做到什么呢,将多个id合并在一个batch内,直接发送一次网络请求,获取到所有的结果 String batchurl = url+"?associatedIds=" + params; String response = HttpClientUtils.simpleGetInvoke(batchurl, null); List<String> results = JSONArray.parseArray(response, String.class); for(String result : results) { System.out.println("BatchCommand内部,associatedId=" + result); } return results; } }
|
HystrixCollapser<BatchReturnType, ResponseType, RequestArgumentType>
public class JoinExamWholeAnalysisCollapser extends HystrixCollapser <List<String>, String, String>{ private String associatedId; private String url; public JoinExamWholeAnalysisCollapser(String associatedId,String url) { super(Setter .withCollapserKey(HystrixCollapserKey.Factory.asKey("JoinExamWholeAnalysisCollapser")) .andCollapserPropertiesDefaults(HystrixCollapserProperties.Setter() //控制一个Batch中最多允许多少个request被合并,然后才会触发一个batch的执行 //默认值是无限大,就是不依靠这个数量来触发执行,而是依靠时间 .withMaxRequestsInBatch(100) //控制一个batch创建之后,多长时间以后就自动触发batch的执行,默认是10毫秒 .withTimerDelayInMilliseconds(20) ) ); this.associatedId = associatedId; this.url = url; } @Override public String getRequestArgument() { return associatedId; } @Override protected HystrixCommand<List<String>> createCommand(Collection<comflix.hystrix.HystrixCollapser.CollapsedRequest<String, String>> requests) { StringBuilder paramsBuilder = new StringBuilder(""); for(CollapsedRequest<String, String> request : requests) { paramsBuilder.append(request.getArgument()).append(","); } String params = paramsBuilder.toString(); params = params.substring(0, params.length() - 1); System.out.println("createCommand方法执行,params=" + params); return new BatchCommand(requests,url); } @Override protected void mapResponseToRequests(List<String> batchResponse, Collection<comflix.hystrix.HystrixCollapser.CollapsedRequest<String, String>> requests) { int count = 0; for(CollapsedRequest<String, String> request : requests) { request.setResponse(batchResponse.get(count++)); } } /** * HystrixCommand和HystrixObservableCommand都可以指定一个缓存key, * 然后hystrix会自动进行缓存,接着在同一个request context内,再次访问的时候,就会直接取用缓存用请求缓存, * 可以避免重复执行网络请求 */ @Override protected String getCacheKey() { return "joint_examWholeAnalysis_" + associatedId; } } |
timeout问题解释:开发机上,特别慢,第一次请求的时候,几百毫秒,默认的timeout时长比较短,第二次的时候,访问的速度会快很多,就不会超时了
反应在系统上,第一次启动的时候,会有个别的超时,但是后面就好了,手动将timeout时长设置的大一些。
(1)maxRequestsInBatch
控制一个Batch中最多允许多少个request被合并,然后才会触发一个batch的执行
默认值是无限大,就是不依靠这个数量来触发执行,而是依靠时间
HystrixCollapserProperties.Setter()
.withMaxRequestsInBatch(int value)
(2)timerDelayInMilliseconds
控制一个batch创建之后,多长时间以后就自动触发batch的执行,默认是10毫秒
HystrixCollapserProperties.Setter()
.withTimerDelayInMilliseconds(int value)
super(Setter.withCollapserKey(HystrixCollapserKey.Factory.asKey("GetUserInfosCollapser"))
.andCollapserPropertiesDefaults(HystrixCollapserProperties.Setter()
.withMaxRequestsInBatch(100)
.withTimerDelayInMilliseconds(20)));
public JoinExamWholeAnalysisCollapser(String associatedId,String url) { super(Setter .withCollapserKey(HystrixCollapserKey.Factory.asKey("JoinExamWholeAnalysisCollapser")) .andCollapserPropertiesDefaults(HystrixCollapserProperties.Setter() //控制一个Batch中最多允许多少个request被合并,然后才会触发一个batch的执行 //默认值是无限大,就是不依靠这个数量来触发执行,而是依靠时间 .withMaxRequestsInBatch(100) //控制一个batch创建之后,多长时间以后就自动触发batch的执行,默认是10毫秒 .withTimerDelayInMilliseconds(20) ) ); this.associatedId = associatedId; this.url = url; } |
11.2 fail-fast和fail-slient高阶容错模式
fail-fast:就是不给fallback降级逻辑,HystrixCommand.run(),直接报错,直接会把这个报错抛出来。
public class FailureModeCommand extends HystrixCommand<Boolean> { private boolean failure; public FailureModeCommand(boolean failure) { super(HystrixCommandGroupKey.Factory.asKey("FailureModeGroup")); this.failure = failure; } @Override protected Boolean run() throws Exception { if(failure) { throw new Exception(); } return true; } } |
public class FailureModeCommandTest {
public static void main(String[] args) { try { FailureModeCommand failureModeCommand = new FailureModeCommand(true); failureModeCommand.execute(); } catch (Exception e) { e.printStackTrace(); } }
} |
fail-silent:给一个fallback降级逻辑,如果HystrixCommand.run()报错了,会走fallback降级,直接返回一个空值;
HystrixCommand,就给一个null;
HystrixObservableCommand,Observable.empty()。
public class FailureModeCommand extends HystrixCommand<Boolean> { private boolean failure; public FailureModeCommand(boolean failure) { super(HystrixCommandGroupKey.Factory.asKey("FailureModeGroup")); this.failure = failure; } @Override protected Boolean run() throws Exception { if(failure) { throw new Exception(); } return true; }
@Override protected Boolean getFallback() { return false; } } |
public class FailureModeCommandTest {
public static void main(String[] args) { try { FailureModeCommand failureModeCommand = new FailureModeCommand(true); System.out.println(failureModeCommand.execute()); } catch (Exception e) { e.printStackTrace(); } }
} |
11.3 stubbed fallback高阶降级模式
stubbed fallback,残缺的降级。用请求中的部分数据拼装成结果,然后再填充一些默认值,返回。比如说你发起了一个请求,然后请求中参数可能本身就附带了一些信息,如果主请求失败了,走到降级逻辑。在降级逻辑里面,可以将这个请求中的数据,以及部分本地缓存有的数据拼装在一起,再给数据填充一些简单的默认值,然后尽可能将自己有的数据返回到请求方。
@Override protected UserInfo getFallback() { UserInfo UserInfo = new UserInfo(); // 从请求参数中获取到的唯一条数据 UserInfo.setId(userId); // 从本地缓存Ehcache中获取一些数据 UserInfo.setName(UserCache.getName(UserInfo.getNameById(userId))); UserInfo.setCityId(UserCache.getCityByUserId(userId)); // 手动填充一些默认的数据 UserInfo.setName("默认商品"); UserInfo.setPicture ("default.jpg"); return UserInfo; } |
<!-- 缓存配置 --> <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"> <property name="configLocation" value="classpath: cache/ehcache-local.xml" /> </bean> |
<!—用户缓存配置. --> <userCache maxEntriesLocalHeap="100" eternal="false" timeToIdleSeconds="300" timeToLiveSeconds="600" overflowToDisk="true" maxEntriesLocalDisk="100000" />
<diskStore> : 当内存缓存中对象数量超过maxElementsInMemory时,将缓存对象写到磁盘缓存中(需对象实现序列化接口)
|
public class CacheUtils { private static CacheManager cacheManager = ((CacheManager)SpringContextHolder.getBean("cacheManager"));
private static Cache getCache(String cacheName){ Cache cache = cacheManager.getCache(cacheName); if (cache == null){ cacheManager.addCache(cacheName); cache = cacheManager.getCache(cacheName); cache.getCacheConfiguration().setEternal(true); } return cache; } } |
11.4 双层嵌套command实现的发送网络请求的降级模式
多级降级:command嵌套command,先降一级,尝试用一个备用方案去执行,如果备用方案失败了,再用最后下一个备用方案去执行。
常见的多级降级的做法,有一个操作,要访问MySQL数据库
mysql数据库访问报错,降级,去redis中获取数据
如果说redis又挂了,然后就去从本地ehcache缓存中获取数据
多级降级的策略:command,fallback,又套了一个command,第二个command其实是第一级降级策略。
public class GetUserInfoInfoCommand extends HystrixCommand<UserInfoInfo> {
public static final HystrixCommandKey KEY = HystrixCommandKey.Factory.asKey("GetUserInfoInfoCommand"); private Long userInfoId; public GetUserInfoInfoCommand(Long userInfoId) { super(HystrixCommandGroupKey.Factory.asKey("UserInfoInfoService")); this.userInfoId = userInfoId; }
@Override protected UserInfoInfo run() throws Exception { String url = "http://127.0.0.1:8082/getUserInfoInfo?userInfoId=" + userInfoId; String response = HttpClientUtils.sendGetRequest(url); return JSONObject.parseObject(response, UserInfoInfo.class); }
@Override protected UserInfoInfo getFallback() { return new FirstLevelFallbackCommand(userInfoId).execute(); } private static class FirstLevelFallbackCommand extends HystrixCommand<UserInfoInfo> {
private Long userInfoId; public FirstLevelFallbackCommand(Long userInfoId) { // 第一级的降级策略,因为这个command是运行在fallback中的 // 所以至关重要的一点是,在做多级降级的时候,要将降级command的线程池单独做一个出来 // 如果主流程的command都失败了,可能线程池都已经被占满了 // 降级command必须用自己的独立的线程池 super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("UserInfoInfoService")).andCommandKey(HystrixCommandKey.Factory.asKey("FirstLevelFallbackCommand")).andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("FirstLevelFallbackPool"))); this.userInfoId = userInfoId; } @Override protected UserInfoInfo run() throws Exception { // 这里,因为是第一级降级的策略,所以说呢,其实是要从备用机房的机器去调用接口 // 但是,我们这里没有所谓的备用机房,所以说还是调用同一个服务来模拟 String url = "http://127.0.0.1:8082/getUserInfoInfo?userInfoId=" + userInfoId; String response = HttpClientUtils.sendGetRequest(url); return JSONObject.parseObject(response, UserInfoInfo.class); } @Override protected UserInfoInfo getFallback() { UserInfo UserInfo = new UserInfo(); // 从请求参数中获取到的唯一条数据 UserInfo.setId(userId); // 从本地缓存Ehcache中获取一些数据 UserInfo.setName(UserCache.getName(UserInfo.getNameById(userId))); UserInfo.setCityId(UserCache.getCityByUserId(userId)); // 手动填充一些默认的数据 UserInfo.setName("默认商品"); UserInfo.setPicture("default.jpg"); return UserInfo; } } } |
11.5 基于facade command的服务接口的手动降级机制
在一个command它的主流程中,根据一个标识位,判断要执行哪个业务流程。如果现在知道有问题了,希望能够手动降级的话,动态给服务发送个请求在请求中修改标识位,自动就让command以后都直接过来执行备用command。
一般会有3个command,套在最外面的command,是用semaphore信号量做限流和资源隔离的,因为这个command不用去care timeout的问题,嵌套调用的command会自己去管理timeout超时的。
降级标志位:
public class IsDegrade { private static boolean degrade = false; public static boolean isDegrade() { return degrade; } public static void setDegrade(boolean degrade) { IsDegrade.degrade = degrade; } } |
套在最外面的command,是用semaphore信号量做限流和资源隔离的,不用去care timeout的问题。
public class GetUserInfoInfoFacadeCommand extends HystrixCommand<UserInfoInfo> { private Long userInfoId; public GetUserInfoInfoFacadeCommand(Long userInfoId) { super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("UserInfoInfoService")) .andCommandKey(HystrixCommandKey.Factory.asKey("GetUserInfoInfoFacadeCommand")) .andCommandPropertiesDefaults(HystrixCommandProperties.Setter() .withExecutionIsolationStrategy(ExecutionIsolationStrategy.SEMAPHORE) .withExecutionIsolationSemaphoreMaxConcurrentRequests(15))); this.userInfoId = userInfoId; } @Override protected UserInfoInfo run() throws Exception { if(!IsDegrade.isDegrade()) { return new GetUserInfoInfoCommand(userInfoId).execute(); } else { return new GetUserInfoInfoFromMySQLCommand(userInfoId).execute(); } }
@Override protected UserInfoInfo getFallback() { return new UserInfoInfo(); } } |
11.6 生产环境中的线程池大小以及timeout配置优化经验
(1)一开始先不要设置timeout超时时长,默认就是1000ms,也就是1s
(2)一开始也不要设置线程池大小,默认就是10
(3)直接部署hystrix到生产环境,如果运行的很良好,那么就让它这样运行好了
(4)让hystrix应用,24小时运行在生产环境中
(5)依赖标准的监控和报警机制来捕获到系统的异常运行情况
(6)在24小时之后,看一下调用延迟的占比,以及流量,来计算出让短路器生效的最小的配置数字
(7)直接对hystrix配置进行热修改,然后继续在hystrix dashboard上监控
(8)看看修改配置后的系统表现有没有改善
下面是根据系统表现优化和调整线程池大小,队列大小,信号量容量,以及timeout超时时间的经验
假设对一个依赖服务的高峰调用QPS是每秒30次
一开始如果默认的线程池大小是10
我们想的是,理想情况下,每秒的高峰访问次数 * 99%的访问延时 + buffer = 30 * 0.2 + 4 = 10线程,10个线程每秒处理30次访问应该足够了,每个线程处理3次访问
此时,我们合理的timeout设置应该为300ms,也就是99.5%的访问延时,计算方法是,因为判断每次访问延时最多在250ms(TP99如果是200ms的话),再加一次重试时间50ms,就是300ms,感觉也应该足够了
因为如果timeout设置的太多了,比如400ms,比如如果实际上,在高峰期,还有网络情况较差的时候,可能每次调用要耗费350ms,也就是达到了最长的访问时长
那么每个线程处理2个请求,就会执行700ms,然后处理第三个请求的时候,就超过1秒钟了,此时会导致线程池全部被占满,都在处理请求
这个时候下一秒的30个请求再进来了,那么就会导致线程池已满,拒绝请求的情况,就会调用fallback降级机制。因此对于短路器来说,timeout超时一般应该设置成TP99.5,比如设置成300ms,那么可以确保说,10个线程,每个线程处理3个访问,每个访问最多就允许执行300ms,过时就timeout了,这样才能保证说每个线程都在1s内执行完,才不会导致线程池被占满,然后后续的请求过来大量的reject
对于线程池大小来说,一般应该控制在10个左右,20个以内,最少5个,不要太多,也不要太少
大家可能会想,每秒的高峰访问次数是30次,如果是300次,甚至是3000次,30000次呢???
30000 * 0.2 = 6000 + buffer = 6100,一个服务器内一个线程池给6000个线程把
如果你一个依赖服务占据的线程数量太多的话,会导致其他的依赖服务对应的线程池里没有资源可以用了
6000 / 20 = 300台虚拟机也是ok的
虚拟机,4个cpu core,4G内存,虚拟机,300台
物理机,十几个cpu core,几十个G的内存,5~8个虚拟机,300个虚拟机 = 50台物理机
11.7 线程池的自动化动态扩容与缩容技术
- 弹性的线程资源调度的模式
可能会出现一种情况,比如说我们的某个依赖,在高峰期,需要耗费100个线程,但是在那个时间段,刚好其他的依赖的线程池其实就维持一两个就可以了。但是,如果我们都是设置死的,每个服务就给10个线程,那就很坑,可能就导致有的服务在高峰期需要更多的资源,但是没资源了,导致很多的reject。但是其他的服务,每秒钟就易一两个请求,结果也占用了10个线程,占着茅坑不拉屎
刚开始的时候,每个依赖服务都是给1个线程,3个线程,但是我们允许说,如果你的某个线程池突然需要大量的线程,最多可以到100个线程。如果你使用了100个线程,高峰期过去了,自动将空闲的线程给释放掉。
(1)coreSize
设置线程池的大小,默认是10
HystrixThreadPoolProperties.Setter() .withCoreSize(int value)
HystrixThreadPoolProperties.Setter().withCoreSize(10) //CoreSize:设置线程池的大小,默认是10,如果你不设置另外两个queue相关的参数,等待队列是关闭 |
(2)maximumSize
设置线程池的最大大小,只有在设置allowMaximumSizeToDivergeFromCoreSize的时候才能生效,默认是10。
HystrixThreadPoolProperties.Setter()
.withMaximumSize(int value)
//设置线程池的最大大小,只有在设置allowMaximumSizeToDivergeFromCoreSize的时候才能生效 .withMaximumSize(15) |
(3)allowMaximumSizeToDivergeFromCoreSize
允许线程池大小自动动态调整,设置为true之后,maxSize就生效了,此时如果一开始是coreSize个线程,随着并发量上来,那么就会自动获取新的线程,但是如果线程在keepAliveTimeMinutes内空闲,就会被自动释放掉
默认是fales
HystrixThreadPoolProperties.Setter().withAllowMaximumSizeToDivergeFromCoreSize(boolean value)
//允许线程池大小自动动态调整(默认为false),设置为true之后,maxSize就生效了,此时如果一开始是coreSize个线程,随着并发量上来,那么就会自动获取新的线程, 但是如果线程在keepAliveTimeMinutes内空闲,就会被自动释放掉 .withAllowMaximumSizeToDivergeFromCoreSize(true) |
(4)keepAliveTimeMinutes
设置保持存活的时间,单位是分钟,默认是1
如果设置allowMaximumSizeToDivergeFromCoreSize为true,那么coreSize就不等于maxSize,此时线程池大小是可以动态调整的,可以获取新的线程,也可以释放一些线程
如果coreSize < maxSize,那么这个参数就设置了一个线程多长时间空闲之后,就会被释放掉
//如果coreSize < maxSize,那么这个参数就设置了一个线程多长时间空闲之后,就会被释放掉 .withKeepAliveTimeMinutes(1) |
生产环境中,这块怎么玩儿的?
也是根据你的服务的实际的运行的情况切看的,比如说你发现某个服务,平时3个并发QPS就够了,高峰期可能要到30个,那么你就可以给设置弹性的资源调度。
注:因为有可能一个服务会有多个线程池,你要计算好,每个线程池的最大的大小加起来不能过大,30个依赖,30个线程池,每个线程池最大给到30,900个线程,很坑的
还有一种模式,就是说让多个依赖服务共享一个线程池,我们不推荐,多个依赖服务就做不到资源隔离,互相之间会影响的
11.8 Hystrix的metric高阶配置
1、为什么需要监控与报警?
HystrixCommand执行的时候,会生成一些执行耗时等方面的统计信息。这些信息对于系统的运维来说,是很有帮助的,因为我们通过这些统计信息可以看到整个系统是怎么运行的。hystrix对每个command key都会提供一份metric,而且是秒级统计粒度的。
这些统计信息,无论是单独看,还是聚合起来看,都是很有用的。如果将一个请求中的多个command的统计信息拿出来单独查看,包括耗时的统计,对debug系统是很有帮助的。聚合起来的metric对于系统层面的行为来说,是很有帮助的,很适合做报警或者报表。hystrix dashboard就很适合。
2、hystrix的事件类型
对于hystrix command来说,只会返回一个值,execute只有一个event type,fallback也只有一个event type,那么返回一个SUCCESS就代表着命令执行的结束
对于hystrix observable command来说,多个值可能被返回,所以emit event代表一个value被返回,success代表成功,failure代表异常
(1)execute event type
EMIT observable command返回一个value
SUCCESS 完成执行,并且没有报错
FAILURE 执行时抛出了一个异常,会触发fallback
TIMEOUT 开始执行了,但是在指定时间内没有完成执行,会触发fallback
BAD_REQUEST 执行的时候抛出了一个HystrixBadRequestException
SHORT_CIRCUITED 短路器打开了,触发fallback
THREAD_POOL_REJECTED 线程成的容量满了,被reject,触发fallback
SEMAPHORE_REJECTED 信号量的容量满了,被reject,触发fallback
(2)fallback event type
FALLBACK_EMIT observable command,fallback value被返回了
FALLBACK_SUCCESS fallback逻辑执行没有报错
FALLBACK_FAILURE fallback逻辑抛出了异常,会报错
FALLBACK_REJECTION fallback的信号量容量满了,fallback不执行,报错
FALLBACK_MISSING fallback没有实现,会报错
(3)其他的event type
EXCEPTION_THROWN command生命自周期是否抛出了异常
RESPONSE_FROM_CACHE command是否在cache中查找到了结果
COLLAPSED command是否是一个合并batch中的一个
(4)thread pool event type
EXECUTED 线程池有空间,允许command去执行了
REJECTED 线程池没有空间,不允许command执行,reject掉了
(5)collapser event type
BATCH_EXECUTED collapser合并了一个batch,并且执行了其中的command
ADDED_TO_BATCH command加入了一个collapser batch
RESPONSE_FROM_CACHE 没有加入batch,而是直接取了request cache中的数据
3、metric storage
metric被生成之后,就会按照一段时间来存储,存储了一段时间的数据才会推送到其他系统中,比如hystrix dashboard
另外一种方式,就是每次生成metric就实时推送metric流到其他地方,但是这样的话,会给系统带来很大的压力(不建议采用)
hystrix的方式是将metric写入一个内存中的数据结构中,在一段时间之后就可以查询到
hystrix 1.5x之后,采取的是为每个command key都生成一个start event和completion event流,而且可以订阅这个流。每个thread pool key也是一样的,包括每个collapser key也是一样的。
每个command的event是发送给一个线程安全的RxJava中的rx.Subject,因为是线程安全的,所以不需要进行线程同步
因此每个command级别的,threadpool级别的,每个collapser级别的,event都会发送到对应的RxJava的rx.Subject对象中。这些rx.Subject对象接着就会被暴露出Observable接口,可以被订阅。
4、metric统计相关的配置
(1)metrics.rollingStats.timeInMilliseconds
设置统计的rolling window,单位是毫秒,hystrix只会维持这段时间内的metric供短路器统计使用
这个属性是不允许热修改的,默认值是10000,就是10秒钟
HystrixCommandProperties.Setter()
.withMetricsRollingStatisticalWindowInMilliseconds(int value)
(2)metrics.rollingStats.numBuckets
该属性设置每个滑动窗口被拆分成多少个bucket,而且滑动窗口对这个参数必须可以整除,同样不允许热修改
默认值是10,也就是说,每秒钟是一个bucket
随着时间的滚动,比如又过了一秒钟,那么最久的一秒钟的bucket就会被丢弃,然后新的一秒的bucket会被创建
HystrixCommandProperties.Setter()
.withMetricsRollingStatisticalWindowBuckets(int value)
(3)metrics.rollingPercentile.enabled
控制是否追踪请求耗时,以及通过百分比方式来统计,默认是true
HystrixCommandProperties.Setter()
.withMetricsRollingPercentileEnabled(boolean value)
(4)metrics.rollingPercentile.timeInMilliseconds
设置rolling window被持久化保存的时间,这样才能计算一些请求耗时的百分比,默认是60000,60s,不允许热修改
相当于是一个大的rolling window,专门用于计算请求执行耗时的百分比
HystrixCommandProperties.Setter()
.withMetricsRollingPercentileWindowInMilliseconds(int value)
(5)metrics.rollingPercentile.numBuckets
设置rolling percentile window被拆分成的bucket数量,上面那个参数除以这个参数必须能够整除,不允许热修改
默认值是6,也就是每10s被拆分成一个bucket
HystrixCommandProperties.Setter()
.withMetricsRollingPercentileWindowBuckets(int value)
(6)metrics.rollingPercentile.bucketSize
设置每个bucket的请求执行次数被保存的最大数量,如果再一个bucket内,执行次数超过了这个值,那么就会重新覆盖从bucket的开始再写
举例来说,如果bucket size设置为100,而且每个bucket代表一个10秒钟的窗口,但是在这个bucket内发生了500次请求执行,那么这个bucket内仅仅会保留100次执行
如果调大这个参数,就会提升需要耗费的内存,来存储相关的统计值,不允许热修改
默认值是100
HystrixCommandProperties.Setter()
.withMetricsRollingPercentileBucketSize(int value)
(7)metrics.healthSnapshot.intervalInMilliseconds
控制成功和失败的百分比计算,与影响短路器之间的等待时间,默认值是500毫秒
HystrixCommandProperties.Setter()
.withMetricsHealthSnapshotIntervalInMilliseconds(int value)
11.9 基于hystrix dashboard的可视化分布式系统监控
1、安装metrics stream POM
<dependency> <groupId>comflix.hystrix</groupId> <artifactId>hystrix-metrics-event-stream</artifactId> <version>1.4.10</version> </dependency> |
2、在系统入口注册Servlet,拦截hystrix.stream
@Bean public ServletRegistrationBean indexServletRegistration() { ServletRegistrationBean registration = new ServletRegistrationBean(new HystrixMetricsStreamServlet()); registration.addUrlMappings("/hystrix.stream"); return registration; } |
3、下载tomcat7解压缩
4、下载hystrix-dashboard的war包,
cp hystrix-dashboard-*.war apache-tomcat-7.*/webapps/hystrix-dashboard.war
5、下载turbin(整个集群的监控)
下载并解压缩
cp turbine-web/build/libs/turbine-web-*.war ./apache-tomcat-7.*/webapps/turbine.war
在/WEB-INF/classes下放置配置文件 config.properties turbine.ConfigPropertyBasedDiscovery.default.instances=localhost turbine.instanceUrlSuffix=:8081/hystrix.stream |
6、启动我们的服务
7、启动tomcat中的hystrix dashboard和turbin
localhost:8080/hystrix-dashboard
http://localhost:8081/hystrix.stream,监控单个机器
http://localhost:8080/turbine/turbine.stream,监控整个集群
以上为配置在SpringBoot中集成Hystrix Dashboard,在SpringCloud中可以直接通过配置
<!---Hystrix Dashboard(只能看到单个应用内的服务信息) 的使用 可以单独部署应用 http://localhost:8761/hystrix http://localhost:8888/hystrix.stream--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId> </dependency> |
在启动类中添加注解@EnableHystrixDashboard
转存失败重新上传取消正在上传…重新上传取消转存失败重新上传取消
http://localhost:8761/hystrix
http://localhost:8888/hystrix.stream
更多推荐
十一、 Hystrix的高阶知识
发布评论