時間序列異常檢測機制的研究

問題的引出

異常檢測的場景很多,例如硬體的故障檢測、流量的異常點的檢測等場景。這篇博客我們針對的是時間序列的異常檢測。時間序列異常的檢測演算法有很多,業界比較流行的比如普通的統計學習方法--3σ原則,它利用檢測點偏移量來檢測出異常。比如普通的回歸方法,用曲線擬合方法來檢測新的節點和擬合曲線的偏離程度,甚至有人講CNN和RNN技術應用到異常點的檢測。

通過普通的閾值來檢測lvs流量異常的方法效果比較差,本篇文章提出了一種新的檢測演算法,下面將重點介紹我們在實踐過程中的經驗。

數據分析

獲取過去7天的lvs流量的數據,我們可以大致將趨勢分為兩種:

一種是如下圖的具有周期性的數據,這種情況更多需要考慮周期性給數據帶來的影響。

而另一種如下圖的隨機的數據,不具有周期性,這種情況需要採用和周期性不一樣的策略來檢測。

檢測機制的研究

由於曲線就有周期性和非周期性的兩種趨勢,所以我們的檢測機制需要能夠處理兩種方式。下面我們將詳細介紹每個演算法。

演算法

短期環比(SS)

對於時間序列(是指將同一統計指標的數值按其發生的時間先後順序排列而成的數列)來說,T時刻的數值對於T-1時刻有很強的依賴性。比如流量在8:00很多,在8:01時刻的概率是很大的,但是如果07:01時刻對於8:01時刻影響不是很大。

首先,我們可以使用最近時間窗口(T)內的數據遵循某種趨勢的現象來做文章。比如我們將T設置為7,則我們取檢測值(now_value)和過去7個(記為i)點進行比較,如果大於閾值我們將count加1,如果count超過我們設置的count_num,則認為該點是異常點。

上面的公式涉及到threshold和count_num兩個參數,threshold如何獲取我們將在下節進行介紹,而count_num可以根據的需求進行設置,比如對異常敏感,可以設置count_num小一些,而如果對異常不敏感,可以將count_num設置的大一些。

動態閾值

業界關於動態閾值設置的方法有很多,今天介紹一種針對我們lvs流量異常檢測的閾值設置方法。通常閾值設置方法會參考過去一段時間內的均值、最大值以及最小值,我們也同樣應用此方法。取過去一段時間(比如T窗口)的平均值、最大值以及最小值,然後取max-avg和avg-min的最小值。之所以取最小值的原因是讓篩選條件設置的寬鬆一些,讓更多的值通過此條件,減少一些漏報的事件。

長期環比(LS)

上面短期環比參考的是短期內的數據,而僅僅有短期內的數據是不夠的,我們還需要參考更長時間內數據的總體走勢。

通常使用一條曲線對該趨勢進行擬合來反應曲線的走勢,如果新的數據打破了這種趨勢,使曲線變得不平滑,則該點就出現了異常。曲線擬合的方法有很多,比如回歸、moving average、……。在這篇文章中,我們使用EWMA,即指數權重移動平均方法來擬合曲線。在EWMA種,下一點的平均值是由上一點的平均值,加上當前點的實際值修正而來。對於每一個EWMA值,每個數據的權重是不一樣的,最近的數據將擁有越高的權重。

有了平均值之後,我們就可以使用3-sigma理論來判斷新的input是否超過了容忍範圍。比較實際的值是否超出了這個範圍就可以知道是否可以告警了。

同比(chain)

很多監控項都具有一定的周期性,其中以一天為周期的情況比較常見,比如lvs流量在早上4點最低,而在晚上11點最高。為了將監控項的周期性考慮進去,我們選取了某個監控項過去14天的數據。對於某個時刻,將得到14個點可以作為參考值,我們記為xi,其中i=1,...,14。

我們先考慮靜態閾值的方法來判斷input是否異常(突增和突減)。如果input比過去14天同一時刻的最小值乘以一個閾值還小,就會認為該輸入為異常點(突減);而如果input

比過去14天同一時刻的最大值乘以一個閾值還大,就會認為該輸入為異常點(突增)。

靜態閾值的方法是根據歷史經驗得出的值,實際中如何給max_threshold和min_threshold是一個需要討論的話題。根據目前動態閾值的經驗規則來說,取平均值是一個比較好的思路。

同比振幅(CA)

同比的方法遇到下圖的現象就不能檢測出異常。比如今天是11.18日,過去14天的歷史曲線必然會比今天的曲線低很多。那麼今天出了一個小故障,曲線下跌了,相對於過去14天的曲線仍然是高很多的。這樣的故障使用方法二就檢測不出來,那麼我們將如何改進我們的方法呢?一個直覺的說法是,兩個曲線雖然不一樣高,但是「長得差不多」。那麼怎麼利用這種「長得差不多」呢?那就是振幅了。

怎麼計算t時刻的振幅呢? 我們使用x(t) – x(t-1) 再除以 x(t-1)來表示振幅。舉個例子,例如t時刻的流量為900bit,t-1時刻的是1000bit,那麼可以計算出掉線人數是10%。如果參考過去14天的數據,我們會得到14個振幅值。使用14個振幅的絕對值作為標準,如果m時刻的振幅({m(t) – m(t-1)]/m(t-1))大於amplitude*threshold並且m時刻的振幅大於0,則我們認為該時刻發生突增,而如果m時刻的振幅大於amplitude*threshold並且m時刻的振幅小於0,則認為該時刻發生突減。

演算法組合

上面介紹了四種方法,這四種方法裡面,SS和LS是針對非周期性數據的驗證方法,而chain和CA是針對周期性數據的驗證方法。那這四種方法應該如何選擇和使用呢?下面我們介紹兩種使用方法:

一、根據周期性的不同來選擇合適的方法。這種方法需要首先驗證序列是否具有周期性,如果具有周期性則進入左邊分支的檢測方法,如果沒有周期性,則選擇進入右分支的檢測方法。

上面涉及到了如何檢測數據周期的問題,可以使用差分的方法來檢測數據是否具有周期性。比如取最近兩天的數據來做差分,如果是周期數據,差分後就可以消除波動,然後結合方差閾值判斷的判斷方法來確定數據的周期性。當然,如果數據波動範圍比較大,可以在差分之前先對數據進行歸一化(比如z-score)。

二、不區分周期性,直接根據「少數服從多數」的方法來去檢測,這種方法比較好理解,在此就不說明了。

這篇博客介紹了我們在lvs異常檢測中使用的方法,也許這些方法還不夠你所面臨的場景,需要去不斷豐富演算法,才能達到比較好的效果。所謂,理論結合實際,具體的問題需要具體的分析,才能將理論應用於實踐。

參考文獻:

1. Skyline timeseries異常判定演算法

2. 騰訊藍鯨數據平台之告警系統_Docker_傳送門


推薦閱讀:

QQ 相冊後台存儲架構重構與跨 IDC 容災實踐
MySQL 之多實例編譯安裝
運維體系中建立反饋機制的重要性
運維之道:16 張圖片帶你 1 小時學會 Ansible
效率篇-定時任務管理系統,替代crontab

TAG:運維 | 機器學習 | 異常檢測 |