DataX 中流的速度限制

概述

這裏的流的速度限制是指在單位時間窗口內,最多允許指定的單位數據通過。比如我們需要從源端 A 發送 1000 條數據到目的端 B,如果設置的速度限制爲最多 100 條每秒,那麼理論上需要 10 秒的時間才能將數據傳輸完成,即使當前的網絡允許在極短的時間便完成這個任務。

但是我們沒辦法嚴格控制每秒時間內的數量一定是小於等於 100 的,因爲我們不能每傳輸一條數據便進行速度與其控制的計算,這樣會極大的帶來性能的損耗。

所以這裏引入時間窗口的概念,因爲我們希望能夠通過計算一個時間窗口內的速度,來判斷是否需要進行速度控制。如果該時間窗口內的速度大於閾值,那麼便通過睡眠一定的時間,來使更長時間上的平均速度是不高於閾值的。比如一個時間窗口的大小爲 1s,閾值仍爲 100 條每秒,那麼如果在這 1s 以內傳輸了 300 條數據,則需要等待 2s 以後才能繼續進行數據傳輸。這樣,即使在前 1s 速度超過了閾值(300 > 100),但是因爲後 2s 的速度爲 0,所以從整體上來看,這 3s 的的平均速度仍然是不高於閾值的。最終它的速度走勢也許會類似下圖:

在這裏插入圖片描述
可以看見,雖然閾值爲 100 條每秒,但是仍然會有部分時間窗口內的總量超過閾值,不過通過限制之後時間內的速度,從而使整體平均的速度是不高於閾值的。

公式

根據前面概述,可推理出公式。設置一下變量:

  • 時間窗口的時間間隔爲:flowControlInterval(單位:毫秒)
  • 實際時間間隔爲:interval(單位:毫秒)
  • 實際時間間隔內傳輸的數據總量爲:numResults(單位:條)
  • 最大限制速度爲:maxSpeed(單位:條/秒)
  • 當前速度爲 currentSpeed(單位:條/秒)
  • 等待休眠的時間爲:limitSleepTime(單位:毫秒)

那麼已知 flowControlInterval、interval、numResults 的值,可得到:

當前速度:

currentSpeed = numResults * 1000 / interval;  

睡眠時間:

limitSleepTime = currentSpeed * interval / maxSpeed - interval;

使用 Java 代碼表示大致如下:

long interval = nowTimestamp - lastTimestamp;
if (interval >= flowControlInterval) {
    long numResults = totlaResults - lastResults;
    long currentSpeed = numResults * 1000 / interval;
    if (currentSpeed > maxSpeed) {
        // 計算休眠時間
        limitSleepTime = currentSpeed * interval / maxSpeed - interval;
    }
    if (limitSleepTime > 0) {
        Thread.sleep(limitSleepTime);
    }
}

這裏的 nowTimestamp、totlaResults 爲當前時間的時間戳與當前總共傳輸的數據總量,lastTimestamp、lastResults 爲上一次計算後記錄的時間的時間戳與數據傳輸總量,通過計算可得到實際的時間間隔與該時間段內的數據傳輸量。

注:以上算法與代碼均參考於阿里的開源項目 DataX,源碼路徑:https://github.com/alibaba/DataX/blob/master/core/src/main/java/com/alibaba/datax/core/transport/channel/Channel.java#L192。

總結:

通過以上方式限制流的速度,可以對包括數量、字節大小等所有可以量化的指標進行限制,雖然不能保證每一個單位時間內的速度總是不高於閾值,但是卻能使平均的速度是不高於閾值的。

參考:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章