1. 程式人生 > >基於滑動視窗的效能指標衡量演算法

基於滑動視窗的效能指標衡量演算法

前言


在複雜的分散式系統中,存在著各種效能指標,比如系統請求數,請求響應時間等等。這些指標在一定程度上可以反映出系統執行的快慢程度。但是這裡我們如何做到更加準確的判斷,而不是說只要出現異常指標,就認定系統有問題,顯然這是不合理的。今天,筆者來為大家講述基於滑動視窗的效能比較演算法。如何收集,利用歷史資料,來進行當前效能指標的比較。

基於滑動視窗的資料採集


當我們說系統出現“變慢”現象的時候,這個其實是和“過去的時間”作對比,所以我們感覺到它有點慢。同樣的,我們要想更加科學地比較這其中的效能差異,就需要用到歷史資料。

對於歷史資料而言,因為時間是連續的,所以我們要對時間做分片,也就是說,是一段,一段的。這一段的週期可以是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); } }

然後將此衰減操作,放在定時器裡,就能模擬出滑動視窗的效果了