基於滑動視窗的效能指標衡量演算法
前言
在複雜的分散式系統中,存在著各種效能指標,比如系統請求數,請求響應時間等等。這些指標在一定程度上可以反映出系統執行的快慢程度。但是這裡我們如何做到更加準確的判斷,而不是說只要出現異常指標,就認定系統有問題,顯然這是不合理的。今天,筆者來為大家講述基於滑動視窗的效能比較演算法。如何收集,利用歷史資料,來進行當前效能指標的比較。
基於滑動視窗的資料採集
當我們說系統出現“變慢”現象的時候,這個其實是和“過去的時間”作對比,所以我們感覺到它有點慢。同樣的,我們要想更加科學地比較這其中的效能差異,就需要用到歷史資料。
對於歷史資料而言,因為時間是連續的,所以我們要對時間做分片,也就是說,是一段,一段的。這一段的週期可以是10分鐘,或半小時等等。在這裡,我們用更加專業的詞語描述,就叫視窗。每個視窗對應一定的時間區間,隨著時間向前滑動。對於每個視窗內,都會有對應時間區間內的效能統計指標資料,比如說我們有該視窗內的總請求數,以及總耗時,這個時候我們可以求出這個視窗的平均響應時間。
那麼有了這些視窗資料,我們如何去使用這些資料呢?一個重要的原則是保證資料指標的平滑性。簡單地說,我們不能簡單暴力地直接使用上個視窗的資料,然後規定出一個規則,比如超出上個指標多少多少倍以上,當前系統就認定為“慢”的。
一種更平滑的做法是,在當前視窗即將結束時,獲取到上個視窗的資料,乘上衰減因子,再疊加當前視窗的即時資料,然後把這2個數據的和作為新的“上個視窗”的指標資料。等這個時間視窗過去了,這個衡量閾值就是剛剛過去的視窗的指標平均值。
圖示過程如下:
通過以上步驟算出的上個視窗的效能資料,就可以拿來與當前資料進行比較,如果數值超過前面的閾值資料,就表明,系統變得異常了。
基於滑動視窗的衰減演算法
下面是基於滑動視窗的衰減演算法(以系統響應時間為衡量指標),大家可以對照上面筆者闡述的過程。
/**
* 在當前視窗的尾聲階段,做視窗的滑動
* @param enableDecay
*/
void updateAverageResponseTime(boolean enableDecay) {
for (int i = 0; i < numLevels; i++) {
double averageResponseTime = 0;
// 獲取當前視窗的指標資料,算出平均響應時間
long totalResponseTime = responseTimeTotalInCurrWindow.get(i);
long responseTimeCount = responseTimeCountInCurrWindow.get(i);
if (responseTimeCount > 0) {
averageResponseTime = (double) totalResponseTime / responseTimeCount;
}
// 獲取上個視窗的資料
final double lastAvg = responseTimeAvgInLastWindow.get(i);
if (lastAvg > PRECISION || averageResponseTime > PRECISION) {
if (enableDecay) {
// 算出新的值,當前平均時間+上個視窗的衰減值得到
final double decayed = decayFactor * lastAvg + averageResponseTime;
// 新的值作為上個視窗的新的資料值
responseTimeAvgInLastWindow.set(i, decayed);
} else {
// 不考慮衰減的情況
responseTimeAvgInLastWindow.set(i, averageResponseTime);
}
} else {
responseTimeAvgInLastWindow.set(i, 0);
}
responseTimeCountInLastWindow.set(i, responseTimeCount);
if (LOG.isDebugEnabled()) {
LOG.debug("updateAverageResponseTime queue: {} Average: {} Count: {}",
i, averageResponseTime, responseTimeCount);
}
// 重置當前視窗資料,準備下個視窗的資料統計
responseTimeTotalInCurrWindow.set(i, 0);
responseTimeCountInCurrWindow.set(i, 0);
}
}
然後將此衰減操作,放在定時器裡,就能模擬出滑動視窗的效果了。