讓人迷茫的原因只有一個:你本該拼搏的年紀,卻想得太多,做得太少。
–> 返回專欄總目錄 <–
代碼下載地址:https://github.com/f641385712/netflix-learning
目錄
- 前言
- 正文
- 累計統計流 BucketedCumulativeCounterStream
- CumulativeCommandEventCounterStream
- CumulativeThreadPoolEventCounterStream
- CumulativeCollapserEventCounterStream
- 淺談metrics指標釋意
- 分佈流 RollingDistributionStream
- RollingCommandUserLatencyDistributionStream
- RollingCommandLatencyDistributionStream
- RollingCollapserBatchSizeDistributionStream
- 最大併發流 RollingConcurrencyStream
- 配置流 HystrixConfigurationStream
- 功能流 HystrixUtilizationStream
- 使用示例
- 總結
前言
上篇文章 介紹了Hystrix
的“主流”:在滑動窗口內統計流、健康流。既然Hystrix
的指標數據收集是基於事件驅動,那麼自然可以多一些監聽流,那麼本文將做個收尾,對Hystrix
內置的累計統計流、分發流、最大併發流…等等分別做介紹,讓小夥伴們能對這種模式有個更深的理解,後面介紹的Hystrix各維度的監控都基於它們擴展出來的哦。
Hystrix已經內置了對事件監聽時各種流的實現,大多數數情況下無需自己來擴展實現的,當然若你着實要和第三方監控平臺深度集成,那麼你也可以自定義收集方式。
正文
累計統計流 BucketedCumulativeCounterStream
它和BucketedRollingCounterStream
的區別是:它在減桶的過程中,持續/無限累積計數。
public abstract class BucketedCumulativeCounterStream<Event extends HystrixEvent, Bucket, Output> extends BucketedCounterStream<Event, Bucket, Output> {
private Observable<Output> sourceStream;
private final AtomicBoolean isSourceCurrentlySubscribed = new AtomicBoolean(false);
protected BucketedCumulativeCounterStream(HystrixEventStream<Event> stream, int numBuckets, int bucketSizeInMs,
Func2<Bucket, Event, Bucket> reduceCommandCompletion,
Func2<Output, Bucket, Output> reduceBucket) {
super(stream, numBuckets, bucketSizeInMs, reduceCommandCompletion);
this.sourceStream = bucketedStream
.scan(getEmptyOutputValue(), reduceBucket) // 這是最大的區別,使用scan 一直掃描
.skip(numBuckets)
.doOnSubscribe(() -> isSourceCurrentlySubscribed.set(true))
.doOnUnsubscribe(() -> isSourceCurrentlySubscribed.set(false))
.share()
.onBackpressureDrop(); // 背壓:多餘的直接棄掉
}
// 實現父類方法
@Override
public Observable<Output> observe() {
return sourceStream;
}
}
最大的區別就是對bucketedStream
的處理上,滑動窗口使用的是window + flatMap
,而本處使用的是scan,代表着持續/無限累積計數。它有如下實現類:
CumulativeCommandEventCounterStream
CumulativeThreadPoolEventCounterStream
CumulativeCollapserEventCounterStream
以上實現類源碼此處均不展示,是因爲完全和BucketedRollingCounterStream
體系的實現一模一樣,請參照上篇文章即可。唯一的不同在父類:一個只統計指定窗口,一個持續不斷的累計統計。
淺談metrics指標釋意
監控是大型分佈式系統的必備系統,它們的數據均來自一些指標信息。收集指標信息的庫有很多,其中比較出名的有metrics-core
,它可以把收集到的信息提供給Meter、Histogram、Gauge...
等度量工具使用,從而可以畫出如下美圖:
當然本文並不講述metrics-core
如何用,而是以一段指標值爲例,稍加解釋:
{
"version":"3.0.0",
"timers":{
"count":0,
"max":0,
"mean":0,
"min":0,
"p50":0,
"p75":0,
"p95":0,
"p98":0,
"p99":0,
"p999":0,
"stddev":0,
"m15_rate":0,
"m1_rate":0,
"m5_rate":0,
"mean_rate":0,
"duration_units":"seconds",
"rate_units":"calls/second"
}
}
這個指標還是比較詳細的,裏面會有mean、p75、p99… 這個其實是很關鍵的數據指標。這些指標主要用於給你設置超時時間提供極有力的參考,如果你每每設置超時時間參考的是RT值
是mean平均值,那你和瞎蒙沒啥區別。
另外到底參考那個值,要看你的系統的整體量級,以及需要滿足幾個9,比如要滿足三個9,那麼超時時間是需要謹慎的。
分位數p50、p95、p999代表什麼意思?
count/max/min/mean這些都不用解釋,其它主要關心:
- p50:也叫中位數(注意中位數不是平均數)。它表示把數據總數分爲上下兩等分,中間的那個數值
- 分位數:分位數是將總體的全部數據按從小到大順序排列後,處於各等分位置的變量值。
p95 = 10ms
:代表95%的響應時間不大於10ms- p99、p999:含義同上
p表示:percent 百分比。
m15_rate
:15分鐘內。請求數/每秒的比率m1_rate
:1分鐘內…mean_rate
: 平均每秒請求數(平均QPS,意義不大)rate_units
:calls/second” 比率單位,這裏表示每秒鐘請求數
對於監控指標來說,一般來說平均值幾乎沒有意義,而分位數一般是重點關注的值。
分佈流 RollingDistributionStream
在指定時間窗口內分佈流。說到分佈,所以和統計、畫圖有關。。。
public class RollingDistributionStream<Event extends HystrixEvent> {
...
// 訂閱者可以訂閱消費消息,得到各種分位數,都存在CachedValuesHistogram裏呢
public Observable<CachedValuesHistogram> observe() {
return rollingDistributionStream;
}
}
雖然它不是抽象類,但它也沒標明具體監聽哪種事件,使用什麼數據流HystrixEventStream
。總之最終它會監聽一個消息流(比如HystrixCommandStartStream
它吧),然後通過RxJava的window操作符對一段時間內的數值進行運算操作,生成統計值放在Histogram對象中,然後重新發射。
它內部集成使用度量工具org.HdrHistogram.Histogram
來統計分析指標數據,並且給出非常詳細的分位數數據(最高達四個9 -> p9999)。它還有如下子類:
RollingCommandUserLatencyDistributionStream
LatencyDistribution
:延遲發佈。延遲的值來自於:調用方線程提交請求和響應可見之間的時間間隔executionResult.getUserThreadLatency()
。
RollingCommandLatencyDistributionStream
延遲發佈。和上的區別是延遲時間來自於:executionResult.getExecutionLatency()
表示:time spent in run() method
它們倆監聽的均是HystrixCommandCompletionStream
數據流~
RollingCollapserBatchSizeDistributionStream
監聽了HystrixCollapserEventStream
消息流,並且監聽窗口期內的ADDED_TO_BATCH
消息類型次數,通過Histogram計算後再發射出去。
最大併發流 RollingConcurrencyStream
它用於對最大併發進行統計:對一段時間內的執行併發量取最大值,如Command/ThreadPool的最大併發數。
// 竟然泛型都木有,乾淨利落
public abstract class RollingConcurrencyStream {
}
它監聽的是HystrixCommandExecutionStarted
事件,它會發送併發數過來,從而便可獲得event.getCurrentConcurrency()
,對比每個桶(一個桶代表1s),最後取出最大值Math.max(a, b)
。
RollingCommandMaxConcurrencyStream
RollingThreadPoolMaxConcurrencyStream
因爲監聽HystrixCommandExecutionStarted
事件的有兩種事件流:command的和ThreadPool的,所以必須用兩個類來表示。它倆除了關心的事件不一樣,其它都一樣~
配置流 HystrixConfigurationStream
這個類對當前的Hystrix配置進行採樣,並將其作爲流公開。
public class HystrixConfigurationStream {
...
private final Observable<HystrixConfiguration> allConfigurationStream;
...
public Observable<HystrixConfiguration> observe() {
return allConfigurationStream;
}
// 當然還可以當讀監控某一類配置
public Observable<Map<HystrixCommandKey, HystrixCommandConfiguration>> observeCommandConfiguration() {
return allConfigurationStream.map(getOnlyCommandConfig);
}
public Observable<Map<HystrixThreadPoolKey, HystrixThreadPoolConfiguration>> observeThreadPoolConfiguration() {
return allConfigurationStream.map(getOnlyThreadPoolConfig);
}
public Observable<Map<HystrixCollapserKey, HystrixCollapserConfiguration>> observeCollapserConfiguration() {
return allConfigurationStream.map(getOnlyCollapserConfig);
}
...
}
可使用hystrix.stream.config.intervalInMilliseconds = 5000
來配置多長時間採樣一次,默認5000ms也就是5秒採樣一次。另外com.netflix.hystrix.contrib.sample.stream.HystrixConfigSseServlet
就是用該流來獲取配置信息的。
功能流 HystrixUtilizationStream
Utilization
:使用、利用(使用率、利用率)。這個類對當前Hystrix資源的利用情況進行採樣,並將其公開爲流。
public class HystrixUtilizationStream {
// HystrixUtilization就是最終的數據結構格式,下面給使用示例
private final Observable<HystrixUtilization> allUtilizationStream;
...
public Observable<HystrixUtilization> observe() {
return allUtilizationStream;
}
public Observable<Map<HystrixCommandKey, HystrixCommandUtilization>> observeCommandUtilization() {
return allUtilizationStream.map(getOnlyCommandUtilization);
}
public Observable<Map<HystrixThreadPoolKey, HystrixThreadPoolUtilization>> observeThreadPoolUtilization() {
return allUtilizationStream.map(getOnlyThreadPoolUtilization);
}
}
可使用hystrix.stream.utilization.intervalInMilliseconds = 500
來配置多長時間採樣一次,默認500ms採樣一次。另外com.netflix.hystrix.contrib.sample.stream.HystrixUtilizationSseServlet
就是用該流來獲取資源利用信息的。
使用示例
public class CommandHelloWorld extends HystrixCommand<String> {
private final String name;
// 指定一個HystrixCommandGroupKey,這樣熔斷策略會按照此組執行
public CommandHelloWorld(String name) {
super(HystrixCommandGroupKey.Factory.asKey("MyAppGroup"));
this.name = name;
}
@Override
protected String run() {
if(name == null){
throw new NullPointerException();
}
return "Hello " + name + "!";
}
@Override
protected String getFallback() {
// super.getFallback():No fallback available.
return "this is fallback msg";
}
}
private static final String toJsonString(Object obj) {
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.writeValueAsString(obj);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
@Test
public void fun1() throws InterruptedException {
// 查看command、線程池的使用情況
HystrixUtilizationStream utilizationStream = HystrixUtilizationStream.getInstance();
// utilizationStream.observeThreadPoolUtilization()
utilizationStream.observe().subscribe(d -> System.out.println(toJsonString(d)));
// 查看配置情況
HystrixConfigurationStream configStream = HystrixConfigurationStream.getInstance();
configStream.observe().subscribe(d -> {
System.out.println(d);
});
// 累計統計流
HystrixCommandKey commandKey = HystrixCommandKey.Factory.asKey("CommandHelloWorld");
HystrixPropertiesCommandDefault properties = new HystrixPropertiesCommandDefault(commandKey, HystrixCommandProperties.Setter());
CumulativeCommandEventCounterStream counterStream = CumulativeCommandEventCounterStream.getInstance(commandKey, properties);
counterStream.observe().subscribe(d -> System.out.println(toJsonString(d)));
// 最大併發流
RollingCommandMaxConcurrencyStream concurrencyStream = RollingCommandMaxConcurrencyStream.getInstance(commandKey, properties);
concurrencyStream.observe().subscribe(d -> System.out.println(toJsonString(d)));
// 發送事件(發送多次)
CommandHelloWorld helloWorld = new CommandHelloWorld("YoutBatman");
helloWorld.execute();
helloWorld = new CommandHelloWorld("YoutBatman");
helloWorld.queue();
// 走fallabck
helloWorld = new CommandHelloWorld(null);
helloWorld.queue();
// 因爲配置5秒鐘才能打印一次
TimeUnit.SECONDS.sleep(5);
}
運行程序,控制檯輸出:
資源利用情況:
{
"commandUtilizationMap":{
"CommandHelloWorld":{
"concurrentCommandCount":0
}
},
"threadPoolUtilizationMap":{
"MyAppGroup":{
"currentActiveCount":0,
"currentCorePoolSize":10,
"currentPoolSize":3,
"currentQueueSize":0
}
}
}
這是功能流的數據,最明顯的是啓動了三次任務,線程池大小目前是3。另外,因爲配置流中的對應無法很好的用JSON序列化,這裏我只能採用笨拙的截圖的方式展示嘍(下面配置不生效哦,若配置了信號量,那麼ThreadPoolConfig這一欄就爲null了):
# hystrix.command.default.execution.isolation.strategy = SEMAPHORE
# hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests = 2
累計統計流的數據如下:
[0,2,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0]
對數字解釋如下:
- 2:index=1,對應事件爲
HystrixEventType.SUCCESS
- 1:index=2,對應事件爲
HystrixEventType.FAILURE
- 1:index=9,對應事件爲
HystrixEventType.FALLBACK_SUCCESS
如果你願意,你還可以自行模擬出
TIMEOUT
超時、FALLBACK_FAILURE
回滾失敗等等情況,建議親可試試,以加深理解。
最大併發流輸出的數據是1
,因爲很明顯1秒內最多才一個請求嘛~
HealthCountsStream
健康信息彙總:
{"errorCount":1,"errorPercentage":33,"totalRequests":3}
一共3個請求,失敗了一個,所以錯誤率是33%
。
說明:因爲
HealthCountsStream
它默認是500ms照一次快照,所以此處它會打印10次(共5s嘛)
總結
到此,關於Netflix Hystrix
指標收集,以及轉換爲Stream流式的實現已經全部講述完成了。最後用一張大佬手繪圖對此作出總結:
聲明
原創不易,碼字不易,多謝你的點贊、收藏、關注。把本文分享到你的朋友圈是被允許的,但拒絕抄襲
。你也可【左邊掃碼/或加wx:fsx641385712】邀請你加入我的 Java高工、架構師 系列羣大家庭學習和交流。
- [享學Netflix] 一、Apache Commons Configuration:你身邊的配置管理專家
- [享學Netflix] 二、Apache Commons Configuration事件監聽機制及使用ReloadingStrategy實現熱更新
- [享學Netflix] 三、Apache Commons Configuration2.x全新的事件-監聽機制
- [享學Netflix] 四、Apache Commons Configuration2.x文件定位系統FileLocator和FileHandler
- [享學Netflix] 五、Apache Commons Configuration2.x別樣的Builder模式:ConfigurationBuilder
- [享學Netflix] 六、Apache Commons Configuration2.x快速構建工具Parameters和Configurations
- [享學Netflix] 七、Apache Commons Configuration2.x如何實現文件熱加載/熱更新?
- [享學Netflix] 八、Apache Commons Configuration2.x相較於1.x使用上帶來哪些差異?
- [享學Netflix] 九、Netflix Archaius配置管理庫:初體驗及基礎API詳解
- [享學Netflix] 十、Netflix Archaius對Commons Configuration核心API Configuration的擴展實現
- [享學Netflix] 十一、Netflix Archaius配置管理器ConfigurationManager和動態屬性支持DynamicPropertySupport
- [享學Netflix] 十二、Netflix Archaius動態屬性DynamicProperty原理詳解(重要)
- [享學Netflix] 十三、Netflix Archaius屬性抽象Property和PropertyWrapper詳解
- [享學Netflix] 十四、Netflix Archaius如何對多環境、多區域、多雲部署提供配置支持?
- [享學Netflix] 十五、Netflix Archaius和Spring Cloud的集成:spring-cloud-starter-netflix-archaius
- [享學Netflix] 十六、Netflix Hystrix斷路器:初體驗及RxJava簡介
- [享學Netflix] 十七、Netflix Hystrix屬性抽象以及和Archaius整合實現配置外部化、動態化
- [享學Netflix] 十八、Netflix Hystrix配置之:全局配置和實例配置
- [享學Netflix] 十九、Netflix Hystrix插件機制:SPI接口介紹和HystrixPlugins詳解
- [享學Netflix] 二十、Netflix Hystrix跨線程傳遞數據解決方案:HystrixRequestContext
- [享學Netflix] 二十一、Netflix Hystrix指標數據收集(預熱):滑動窗口算法(附代碼示例)
- [享學Netflix] 二十二、Netflix Hystrix事件源與事件流:HystrixEvent和HystrixEventStream
- [享學Netflix] 二十三、Netflix Hystrix桶計數器:BucketedCounterStream
- [享學Netflix] 二十四、Netflix Hystrix在滑動窗口內統計:BucketedRollingCounterStream、HealthCountsStream