
核心原理
滑動(dòng)時(shí)間窗口的核心原理是: 我們先確認(rèn)一個(gè)窗口,這個(gè)創(chuàng)建就是一個(gè)單位時(shí)間,比如10s, 統(tǒng)計(jì)10s內(nèi)某個(gè)Redis的Key訪問(wèn)次數(shù),這個(gè)10s就是一個(gè)單位時(shí)間窗口,如果僅僅以10s一個(gè)單位來(lái)做統(tǒng)計(jì),這個(gè)就太粗糙了,而且結(jié)果不準(zhǔn)確。
通常的做法是,將這個(gè)10s的窗口,進(jìn)行一個(gè)切分,比如切分10個(gè)小塊,每個(gè)小塊代表 1 秒,這個(gè)切分的步驟,它的思想是來(lái)源于 桶排序中,桶的劃分思想, 桶排序這個(gè)思想可以應(yīng)用于很多方面,利用桶排序思想,其實(shí)我們具體利用的不是他的排序功能,而是這個(gè) 桶 的功能。
比如 Java中的高性能計(jì)數(shù)器 LongAddr ,底層的邏輯核心思想也是 桶 的思想
核心邏輯
既然利用滑動(dòng)時(shí)間窗口做統(tǒng)計(jì), 這里面的最核心的一個(gè)步驟,我覺(jué)得并不是 如何 做統(tǒng)計(jì),而是 確認(rèn)當(dāng)前時(shí)間在窗口中的哪個(gè)小方塊中,具體統(tǒng)計(jì)的計(jì)算,只是很自然的一步。
這里我們把小方塊稱為 桶, 對(duì)于當(dāng)前時(shí)間,如何確定它應(yīng)該放在哪個(gè)桶里面呢?
其實(shí)很簡(jiǎn)單:
-
(當(dāng)前時(shí)間 - 窗口起始時(shí)間) / 1, 這里的 1 表示一個(gè)桶的規(guī)格,實(shí)際也可以是3,4,5等
直接看代碼
timeMillisPerSlice: 每個(gè)桶的大小
timeSliceSize:窗口內(nèi)共有多少桶
/**
* 計(jì)算當(dāng)前所在的時(shí)間片的位置
*/
private int currentIndex() {
long now = System.currentTimeMillis();
// 如果當(dāng)前的key已經(jīng)超出一整個(gè)時(shí)間片了,那么就直接初始化就行了,不用去計(jì)算了
if (now - lastAddTimestamp > timeMillisPerSlice * windowSize) {
reset();
}
return (int) (((now - beginTimestamp) / timeMillisPerSlice) % timeSliceSize);
}