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<com.netflix.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<com.netflix.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>com.netflix.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