使用算法檢測異常 - 問題描述

背景算法

任何一個產生環境的IT系統若是要長久下去,必須對其進行監控告警。常見的實現分爲三個部分服務器

  1. 採集目標系統的指標,並上報到中央服務器
  2. 對指標按時間窗口進行統計,並存儲成爲曲線
  3. 對曲線進行異常檢測,在必要的時候告警通知運維人員

在過去,對於第一、2兩點咱們已經積累很是多的文章和工具來談論如何來實施一個「監控系統」。可是對於如何有效檢測異常卻很是缺乏行業經驗的積累。若是要對有效進行量化的話主要是兩個指標:微信

  1. 誤警率:在全部產生的告警中,有多少表明了真正的故障
  2. 敏感度:在全部真正的故障中,有多少產生了告警

通常來講,誤警率能夠放寬一些。雖然可能會產生狼來了的結果,可是稍微多一兩條告警並不會產生什麼實質的危害。須要卡控得比較嚴格的是漏警的狀況。一旦監控系統漏警了,每每意味着一塊兒責任事故和不小的損失。網絡

曲線分類架構

首先,我不是一個理論工做者,對於自迴歸,方差等術語沒有特別偏好,也沒有通篇使用數學符號表達含義的表達能力。從經驗觀測的角度,我所知的曲線大概分爲下面三類(該分類絕對不是完整分類):併發

  1. 成功率曲線(success rate):最多見的成功率曲線好比網絡測量裏的丟包率,還有HTTP接口裏200到400之間返回碼的佔比。
  2. 延時曲線(latency):最多見的延時曲線好比網絡測量裏的網絡延遲(好比ping值),還有HTTP調用從請求發出到請求收到之間的耗時。
  3. 調用量曲線(arrival rate,queue length):最多見的調用量曲線好比網絡測量裏的收發包量,收發字節數,還有HTTP請求量。

而所須要作的監控也通常分爲兩類:運維

  1. 可用性監控(availability):只須要回答掛了仍是沒掛兩個問題,掛了就打電話,發短信,發微信通知運維人員,不然shut up。
  2. 性能監控(latency ~ user experience):通常不須要觸發當即的運維介入,而是用於過後回答過去一段時間的用戶體驗是變好了仍是變壞了。不須要運維介入是小的性能降低,通常運維沒有辦法,必需要開發發新版原本解決。而大的性能降低很快就會演變成可用性監控的範疇,因此無需在性能監控裏作回答。

性能監控主要關注併發處理的請求數,以及與延時的關係。而可用性監控若是可能的話,首選成功率。若是咱們能夠知道最近一段時間內500的HTTP返回顯著上升了,基本上能夠判定系統出了可用性的問題了。若是對URL作一個分類,而後某一個分類裏500顯著上升那麼這個推斷就更加精確了。這種異常檢測幾乎也無需太複雜的算法了,甚至一個絕對的閾值就能夠了。工具

特別注意的是成功率的曲線不必定非要在一個調用的地方有一個錯誤碼之類的東西,它能夠是來自同一個流程上兩個環節的數據。好比一個成功的業務過程,須要通過a,b,c三個點。咱們若是知道a點的調用量,b點的調用量,也就至關於知道了a點的成功率了。因此大部分時候,咱們是能夠計算出成功率曲線的。性能

可是有的時候,好比由於組織架構的緣由,沒法要求咱們的監控對象必須是某類曲線。假設咱們是一個互聯網的監控服務提供商,好比監控寶。咱們沒法要求咱們的用戶必須提供HTTP的成功率曲線給咱們,用戶只能給咱們HTTP調用的絕對數量。而後僅憑這麼一條調用量的曲線來檢測是否有異常。優化

本文的討論對象是當咱們僅有「調用量曲線」的時候,如何依靠算法檢測出異常。

整體思路

通常來講,所謂的算法來實現所謂的智能,有兩條道路。

  1. 搞一個牛b的算法,「自動」找出異常。而後人來解讀這個異常表明了什麼含義。
  2. 人根據經驗「知道」什麼樣的曲線表明了異常,而後想辦法搞一種算法來逼近人眼來看的效果。

對於算法檢測異常出告警這件事情來講,直覺智慧仍是佔了上風的。和高維度的聚類之類的場合不一樣,業務/系統指標的曲線對於異常能夠很是可視化地體現出來。若是咱們以算法爲第一位,直覺放第二位的話,會產生這樣的狀況:

  1. 不當心誤警了,可是從曲線上「看來」徹底沒問題,咱們沒法向運維人員解釋算法的細節
  2. 不當心漏警了,從曲線上「看來」很是明顯,咱們仍是沒法向運維人員解釋算法的細節

從明哲保身但求無過的角度來看,算法必須可以到達和運維人員肉眼觀察曲線類似的效果,不然沒法向「人」交代。在知足了這個前提下,纔去看那些單曲線沒法感知的,可是綜合多個曲線可能能夠推測出的系統性故障。

如網站的訪問人數之類的業務指標,自己具備週期性的波峯波谷,並且很是容易受到營銷事件的影響。好比下面這個曲線

圖片描述

曲線自身就一直在震盪,在這樣的曲線上如何檢測異常?異常長什麼樣?好比這個

圖片描述

這段區間的數據掉底了(數據爲零),這是很是顯而易見的異常。

圖片描述

這個異常就須要放大了才能觀察出來。在降低的過程當中,忽然陡降了一點,而後又有一個緩慢回升。

圖片描述

這個異常幾乎肉眼沒法分辨。若是不是那個時間點真的出了故障,也很難從曲線上找出來。

圖片描述

上面也是兩個真實的故障。全部上述的故障,人的肉眼能夠發現出來基本上我認爲都是由於人在觀察曲線的時候對於曲線的平滑和不平滑的交界處很是敏感。咱們的算法第一位的需求是要把人肉眼能夠觀察出來的波動,鋸齒,坑都檢測出來。
除了上面的這些狀況以外,還有一類異常,可能就會比較難以捕捉,不如:

圖片描述

上面的圖示一條曲線的七天疊加,也就是根據七天的規律,基本上波形是一致的。可是假如在紅線處,業務曲線實際上應該有一個波峯的時候,是一條水平線過去的,那是該告警呢,仍是不告警呢?若是單純看一根線是徹底沒有平滑不平滑的問題的,由於幾乎是直的。從歷史統計的角度來看,這樣平過去的狀況確定是異常了的,須要告警出來。更極端的的一些狀況,好比這個時間點有營銷資源的投放,案例曲線應該有明顯的擡升,可是實際曲線和往日差很少,那是否是也表明了異常?這樣的一些狀況的處理,我認爲是算法檢測的加分項,本職工做把人肉眼能夠觀察到的波動捕捉到就能夠了,對於第二種狀況就能作到多好就作到多好,實在沒檢測出來,也是能夠理解的,由於確實很難。

statistical process control

咱們搞工程的是沒有本事從新發明什麼算法的。IT系統的業務數據的監控告警,看似很新鮮,其實這是一個早就被研究多年的成熟領域了。它的名字叫statistical process control(基於統計的流程控制),簡稱SPC。最先的奠定人是 Walter Shewhart ,他發明的Shewhart Control Chart是最先的用於告警的曲線控制圖。在這個基礎之上,由於工業質量控制領域用途普遍,有了很是深刻的發展。著名統計軟件SAS,甚至有一個專門的工具SAS/QC用於這個領域。

最基本的shewhart control chart長成這個樣子:

shewhart_plot.png

假設這張圖表明瞭鑽探領域裏打的孔的孔徑。由於鑽頭的大小是固定的,因此孔徑應該會在一個範圍上下波動。在正常的狀況下,這個波動應該在一個合理的範圍。在鑽頭損壞的狀況下,波動應該會超過這個合理的範圍。咱們要作的告警就是檢測到鑽頭損壞這樣的場景。怎麼作?

根據shewhart control chart,首先須要根據歷史的統計數據獲得一個平均孔徑的大小。以及在鑽頭良好的狀況下,實際打的孔徑在這個平均上下波動的方差。什麼是方差?

49f102b5180cc271551b24b6cf684e5c.png

對應的方差就是

http://en.wikipedia.org/wiki/Standard_deviation
b959bb328932092baa95510e53687a8b.png
97d5812ea4aa747bfa37805c1ffa35f0.png
d37208199fdd6ec49ef9ff4243542e83.png

在統計上,方差的含義就是表明了一組數據的振動幅度。利用這些鑽頭良好狀況下的值得出的良好狀況下的振動幅度,咱們就能夠知道什麼是「合理的範圍」。好比,拍個腦殼,在兩倍振幅以內是合理的。振幅也就是歷史值的方差,數學符號叫sigma,因此能夠說在「兩個sigma」以內。因而乎,咱們能夠在圖上標記一個上界和下界。若是觀測的值超過了上界或者下界,那麼可能就是一個異常點。

用拍腦殼的方式決定「兩個sigma」也是很是不科學的。實際使用中,這個n sigma的n如何肯定也是頭大的問題。對於這個問題,咱們能夠用反推的方法來解決。在給定歷史數據的狀況下,先計算出sigma,而後再計算出歷史數據相對於歷史的平均值每一個點是幾倍的sigma。根據這些歷史數據對應的sigma的倍數(統計上叫zscore),咱們能夠知道大部分的歷史數據都是n個sigma以內的,從而把n求出來。

shewhart control chart的問題

shewhart control chart不是包治百病的,沒有任何一種control chart是適合全部類型的曲線的。shewhart control chart的適用範圍是:

  1. 目標的曲線是stationary的,也就是沒有明顯的上升和降低趨勢。也就是從統計上來講,每一個點的下一個點都是可升,可降的。(本人不是統計學出身,不要扣細節哈)
  2. 曲線的振動幅度是恆定的,不會隨着時間推移和變化,也沒有周期性規律

到這裏就須要引入行業特性了。若是咱們監控的是HTTP請求量這樣的曲線的話。通常來講都會有如下特徵:

  1. 曲線不是stationary的,而是一段時間內持續上升(好比晚上9點到11點),而一段時間持續降低(好比凌晨2點到4點)。
  2. 曲線的震動幅度也是很是不固定的,某個時間段可能發生很是劇烈的變化(好比特定時刻開始搶紅包之類的營銷手段影響),某個時間段又很是平穩。
  3. 曲線基本上以天爲週期單位循環

而咱們的目標就是,結合shewhart control chart開創的基本思想,與咱們監控的曲線的特徵,選擇一個最合適的算法來檢測出異常。

週期性規律

最容易被想起來利用的是週期性規律。好比,下面這個故障場景:

圖片描述

對比昨日和今日的曲線,咱們發如今非故障的時候兩條曲線基本重合,和故障的時候下跌明顯。那麼很容易就想到,爲何不用昨日的曲線,或者歷史的平均值來預測今日的曲線呢?
的確是能夠的,好比咱們能夠用過去7天的平均值來做爲今日的預測值。而後用過去7天的數據與預測值比較得出方差,用方差來肯定上下界。效果差很少是這樣的:

圖片描述

首先對於時間點xx:yy,咱們用過去3天的歷史數據得出一個平均值。而後咱們能夠用這些平均值得出一條預測曲線,也就是上圖中的綠色的線。而後用黃色的實際值作對比。咱們能夠發如今業務穩定的狀況下,近期的歷史是能夠很好的預測今天的實際曲線的。

圖片描述

可是實際查看歷史三天的曲線,咱們能夠發現上下是有波動的。這些波動就會形成方差的不穩定。

圖片描述

咱們能夠看到,三條曲線比較重合的時候,方差很是小,而有些時間點上方差變大很是大。

圖片描述

方差波動的後果就是咱們很難用方差來肯定所謂的「合理範圍」。
殘差 = 實際值 - 預測值
波動幅度 = 殘差 / 方差
上面這張圖就是波動幅度的曲線,而標了紅色方框的區域是故障時間段。能夠看到從統計特徵上來講,是明顯的,可是不夠明顯。用這種方式來告警,可能就會產生比較多的誤警。

實際使用的過程當中能夠考慮幾個優化:

  1. 預測值能夠選擇平均值,移動平均值,中位數,曲線擬合(好比自迴歸)
  2. 方差計算的過程當中要剔除掉明顯的異常點

這些優化能夠有改善,可是沒法從根本上克服業務自己的不規則上下波動形成的統計特徵的模糊。更要命的是由於業務常常總體上下移動,好比周末和節日。這些總體的上下會進一步擴大方差,使得原本異常的波動被認爲在合理的範圍以內,從而形成漏警。而咱們知道,漏警是致命的。

因此直接用歷史值的週期性規律來作預測和告警是很難作的,由於業務可能會昨日重複今日,可是積極上升中的業務不會每日都同樣。

相關文章
相關標籤/搜索