您好,登錄后才能下訂單哦!
這篇文章給大家介紹怎么設計告警系統,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
告警的本質
告警對象
監控的指標和策略
理論與現實
異常檢測
基于曲線的平滑性檢測
基于絕對值的時間周期性
基于振幅的時間周期性
基于曲線回升的異常判斷
核心要點總結
告警的本質
沒有多少系統的告警是設計得當的。良好的告警設計是一項非常困難的工作。
如何知道你收到的告警是糟糕的?多少次你收到了告警之后,立即就關掉了的?是不是成天被這些沒有什么卵用的東西給淹沒?
最常見的告警設置:cpu使用率超過90%,然后告警。這種設置在大部分場合下是沒有辦法提供高質量的告警的。
高質量的告警應該是這樣的:每次收到之后你可以立即評估影響的范圍,并且每一個告警需要你做出分級響應。所謂每個告警都應該是,actionable的。
告警的實質可以用下圖表明:
服務器的設計應該是以這樣的無人值守為目的的。假設所有的運維全部放假了,服務也能7*24自動運轉。
告警的實質就是“把人當服務用”。在一些事情還沒有辦法做到程序化執行的時候,用告警通知人的方式去干預系統達到修正的目的。
一次告警就像一次服務調用一樣。如果告警了,但是收到告警的人并不需要做任何處理,那么這就是一種DDoS攻擊,攻擊的是運維的幸福生活。
很多時候,告警通知人去干的事情是真的可以被自動化掉的。比如服務器掛了,換一臺上來。
在小一點的系統里,可能就是停機一會,人工來處理換一臺冷備的機器上去。
大一點的系統,因為服務器多了,天天都掛可不行,必須是熱備的,系統自動切換到備機。
再大一點的系統,因為切換實在太頻繁了,故障機的退庫,備機的保有都變成了一種管理負擔,那么可以和其他的運維流程打通變成完全自動化的系統。
只是因為業務處理不同階段,選擇不同的實現策略而已。業務量小,拿血肉當機器用,有的時候更經濟而已。當然對于那個被當成機器人來用的哥們來說,生活確實有點不公平。
告警對象
告警對象可以分為兩種:
業務規則監控
系統可靠性監控
對于業務規則監控可以舉一個游戲的例子。
比如DNF的游戲角色在一定裝備的情況下,單次打擊的傷害輸出應該是有一個上限,如果超過了就說明有作弊的情況。
又比如斗地主游戲里一個人的連勝場次是有一定上限的,每天的勝率是有一定上限,如果超出平均值太多就可能是作弊。
業務規則監控的不是硬件,也不是軟件是否工作正常。而是軟件是否按照業務規則實現的,是否有漏洞。也可以理解為對“正確性”的監控。
系統可靠性監控是最常見的監控形式,比如發現是不是服務器掛掉了,服務是不是過載了等等。
對于大部分后臺服務,系統可以抽象建模成這個樣子:
對于這樣的系統可以采集什么指標?
請求數,請求到達速率
正常響應數,正常響應占比
錯誤響應數,錯誤響應占比
響應延時
隊列長度,排隊時間
實際的情況是,幾乎任何系統都不是孤立運行的。而是這樣的:
一個DB會依賴于底層的cpu,內存,磁盤等資源。一個Http服務會依賴于底層的DB服務。一個應用會依賴于數個底層的RPC服務。
于是又多了幾個指標:
資源A的調用量(比如CPU使用率)
資源B的調用量(比如內存分配和釋放)
資源C的調用量(比如網絡發送包量)
...
這種層次結構,一般來說簡單來說可以分為四層:
產品策略和營銷:它們決定了根本的請求到達的速率
應用層(更粗俗一點可以叫web層):最上層的膠水
服務層:db,各種RPC服務,以及層層嵌套的服務
硬件層:cpu,內存,磁盤,網絡
因為這樣的一個依賴層次。上一層對下一層的資源消耗量變成了下一層的請求數。
比如Http服務消耗了多少DB的資源,就對應了DB服務需要處理多少請求數。DB繁忙與否取決于Http服務請求,Http服務請求繁忙與否取決于多少人打開客戶端,多少人打開客戶端又取決于產品策略和營銷活動。
這種層次結構決定了單純跟蹤一個指標,比如絕對請求數,很難說明這一層的服務是否出現了故障。
有這么多層次,每層又有很多指標可以采集。那么應該采集什么指標,用什么告警策略去告警呢?
最前面已經提到了告警必須是actionable的,但是實際情況下只有這種綱領性要求仍然是不好操作的。至少可以提幾點不應該做的事情:
不應該用采集的難度決定你使用什么指標去告警。很多情況下cpu使用率可能是最好采集的,但是未必是最值得告警的。
不要給運維他們想要的告警,而是要做“真正”想要的告警。大部分情況下,人們告訴你的是一個解決方案。運維告訴你它需要對db進程的cpu使用率超過x%的時候告警,它給你的是一個他認為最優的解決方案。但是他真正想要的是知道db服務是否有異常,cpu使用率超過x%未必是最好的告訴你服務是否出現異常的指標。
盲目地采集那些容易獲取的指標,并隨意地設定閾值告警是大部分糟糕的告警質量的根源。
監控的指標和策略
那到底應該采集什么指標呢?我認為大部分的系統可靠性監控不外乎三個目標:
is the work getting done?系統是否在持續完成其設定的工作
is the user having good experience?用戶體驗是否好
where is the problem/bottleneck?問題或者瓶頸在哪里
其中最核心最關鍵的是第一個問題,is the work getting done。對于數據庫來說,我們可以采集:
cpu 使用率
網絡帶寬大小
db請求數
db響應數
db錯誤響應數
db請求延遲
顯然要回答一個db是否完成了其指定的工作,更應該關注的指標是這兩個:
db請求數的絕對量
db正確響應相對請求數的占比
這兩個指標相對于采集什么cpu使用率更能說明問題。不僅僅是db,各個層次的服務都可以用請求量和正確響應占比來反映其工作狀況。
比如http請求數(對比http正確響應數),比如app打開次數(對比服務端記錄的在線人數)等等。
為什么cpu使用率不能說明問題?大部分時候,我們并不關心cpu本身,而關心使用cpu為資源的服務。所以cpu使用率只是一種資源的請求數而已。
與請求數相關的一個概念是saturation(上限),當上限達到的時候,處理開始排隊,延遲開始變長,錯誤率開始升高。
那么cpu使用率是不是能夠說明上限呢?cpu使用率的上限以100%記,那么90%開始告警不是很合理嗎?畢竟cpu 100%了幾乎可以等同于db無法正常處理請求了。
這種利用底層資源調用量,評估其是否達到上限的做法有兩個根本缺陷:
你無法知道上層服務可以把底層資源利用到什么程度
底層資源的 saturation 未必可以容易度量
具體來說,db是不是可以真的100%利用cpu是未知的。假如請求里鎖,或者sleep,那么也許cpu永遠也無法達到100%,90%可能就是極限了。
而且現代的cpu是多核的,如果請求處理只能利用單核,處理在多個核之間跳躍,對于一個核來說永遠也不會一直保持100%。
對于cpu可能其上限真的有一個100%的值。但是對于很多非硬件的服務,比如你是一個登陸服務,依賴于一個db。那么這個db每秒可以處理的不同sql組合數是很難度量的,絕非和磁盤一樣有一個mb/s的極限絕對值可以做為對比。
而且度量底層資源的使用還有一個缺陷是你無法枚舉出所有依賴的資源的。所以與其這么繞彎子地通過底層資源來間接監控上層服務是否正常,還不如直接測量work是不是getting done呢。
對于第二個問題,is the user having good experience?可以采集的指標為
平均排隊時間,平均總響應延遲
99/95/90 percentile的排隊時間,99/95/90 percentile的響應延遲
這里的用戶不一定是指人或者玩家,可能是上一層的服務調用方,另外一個系統。
第三個問題就是所謂的故障定位。要是人工來做的話,最常見的做法是收到了告警,然后登陸CRT,開始敲各種命令查找原因。
對于系統來說,最合適的做法不是出了問題再去執行一堆命令,而是:
每個層次都對自己做告警
頂層服務出了告警觸發自動定位程序
按照服務的依賴關系和大致的時間范圍,定位到告警之間的關聯,從而找到出問題或者瓶頸的地方
當然實際情況是很復雜的。很多原因和結果是互為因果的。兩個告警是兩個現象,還是一個原因一個現象實際上很難說得清楚。
從告警算法的角度來講,對成功請求率,或者平均響應延遲做告警是非常容易的。靜態閾值大家看不起,覺得簡單。但是大部分告警用靜態閾值就可以解決問題。
理論與現實
那告警要不要高難度的算法?
我的觀點是采集到了正確的指標,是不需要復雜算法的,就是靜態閾值都可以搞得定。但是至少有三種場合需要算法:
無法直接采集到錯誤數:需要對錯誤日志的自動分類
無法直接采集到請求成功率:需要對請求數或響應數的絕對值做異常檢測
只有總數,無法采集到其中的每個細分構成項的占比:需要對參與的factor進行算法擬合
其實這三項都是一個主題的,當你無法直接獲取到告警所需的指標的時候,事情會變得復雜很多。
有一個比喻是:最近NASA宣布的地球孿生兄弟Kepler 452b。如果我們的探測器可以跑到1400光年之外,發現他將是非常容易的事情。
正是因為直接獲得數據非常困難,所以科學家才需要根據行星阻擋恒星時引起的亮度變化(所謂掩星法)來發現這些遙遠的星球。
采集所需的指標的困難可能是幾方面的因素。一種原因是采集本身是非常消耗資源的事情。
比如獲取每個mysql查詢所消耗的cpu。跟蹤每個請求處理過程是不可能的。這個時候就需要算法的幫助了,可以仔細看一下vividcortex的視頻:
http://www.youtube.com/watch?v=szAfGjwLO8k
更多情況是采集指標困難是D/O分離造成的溝通問題,運維需要的指標需要開發去埋點,而開發埋點的地方又需要運維去做告警。很多時候退而求其次就會造成,有什么指標就用什么指標的狀況。
比如雖然沒有請求響應的錯誤數,但是錯誤基本上都會有錯誤日志記錄,根據錯誤日志滾動的快慢可以大致知道是不是出了問題。
這就引入了一個非常困難的日志分類問題,什么日志代表了正常,什么日志代表了異常,異常又非了哪些類型?
這個方面算法做得好的是summo logic公司:
https://www.sumologic.com/
為什么這種opsdev(嘲諷devops那)公司如此熱衷于算法?
對于他們來說好處是顯而易見的,客戶需要做的改動越少,接入成本越低,客戶面就越廣。
但是拿機器算法去挖掘海量日志真的是回答:is the work getting done?的最佳手段?
顯然不是。這就是大炮打蚊子。日志的存在是用于解決問題,而不是有了海量日志了,如何用好“它們”變成了問題本身。
第三類情況是沒有辦法采集到請求成功率,只能對絕對的處理成功的量。只有這類數據要告警,就無法做簡單的靜態閾值了。
對于延遲,一般可以定一個業務上可以接受的延遲上限。對于成功率,也可以定一個可接受的成功率上限。但是對于絕對的處理量,是沒有辦法簡單地比較一個靜態閾值就可以判斷是正常還是異常的。
在討論如何實現之前,再強調兩點:
處理成功的量不是度量is work getting done的最佳指標。費事費力去搞算法,不如直接把成功率指標給采集了
處理成功的量,還取決于請求數。而請求數根本上是取決于上層服務。
你是一個dba,發現db的每秒處理的請求數陡降了。這說明是db故障了?還是app故障了?
都有可能……最最上層是產品和營銷。
你發現一個業務的注冊量相對前幾天變少了,這個是不是說明注冊服務出問題了?
也許是產品太爛了,游戲根本沒有人來玩。也可能是營銷手段的營銷,不送金幣了,玩家沒積極性了。
異常檢測
只有請求數,沒有參考的上限值(saturation),也沒有成功率,沒有失敗率,怎么檢測異常?
上圖的黃線是昨天的值,綠線是今天的值,大部分服務監控的曲線圖都長這樣。可以得出四個思路:
曲線平滑:故障一般是對近期趨勢的一個破壞,視覺上來說就是不平滑
絕對值的時間周期性:兩條曲線幾乎重合
波動的時間周期性:假設兩個曲線不重合,在相同時間點的波動趨勢和振幅也是類似的
有一個長度可觀的坑:當曲線開始回升到歷史范圍的時候,一般可以確認這個時間段是真的故障了
從這四種直覺展開,可以得出各種或復雜或簡單的算法。下面要講的算法都是非常簡單的,無需很高深的數學知識。
基于曲線的平滑性檢測
這種檢測的根據是在一個最近的時間窗口,比如1個小時。曲線會遵循某種趨勢,而新的數據點打破了這種趨勢,使得曲線不光滑了。
也就是說,這種檢測利用的是時間序列的temporal dependency,T對于T-1有很強的趨勢依賴性。
業務邏輯上來說,8:00 有很多人登陸,8:01 也有很多人來登陸的概率是很高的,因為吸引人來登陸的因素是有很強的慣性的。
但是7.1很多人來登陸,8.1也有很多人來登陸的慣性就要差很多。
基于近期趨勢做告警,就需要對曲線的趨勢進行擬合。
擬合有兩種方式,moving average 或者 regression。這兩種擬合方式有不同的bias(傾向)。
這就是一種moving average的算法圖,叫做exponentially weighted moving average。它的計算非常簡單
x是實際值,s是ewma計算出來的平均值。也就是下一點的平均值是由上一點的平均值,加上當前點的實際值修正而來。
這個修正的比例,就取決月這個alpha的decay factor的大小。視覺上來說就是ewma曲線是否緊跟實際曲線,也就是平滑程度。
有了平均值之后可以計算方差,方差乘以一定的倍數可以得出對于振幅的容忍范圍。比較實際的值是否超出了這個范圍就可以知道是否可以告警了。
超出了上界,可能是突然用戶量突然激增了。超出了下屆,可能是營銷活動結束了,用戶快速離開,也可能是光纖斷了,玩家掉線了。
想要了解更多關于ewma的算法細節:關注Baron Schwartz:
http://www.slideshare.net/vividcortex/statistical-anomaly-detection
moving average認為曲線是趨向于歷史的,如果曲線的勢頭是上升,那么它認為下一個點應該是開始下降的。
regression認為曲線是趨向于未來的,如果曲線的勢頭是上升,那么它認為下一個點應該是保持這個上升勢頭。
還有更復雜的模型是綜合了moving average和regression的。無論是哪種算法,用過去10分鐘預測下10分鐘是不可能精確的。如果這種預測可以精確,那么股神早就誕生了。
使用moving average,可能會掩蓋故障產生的下降(因為其bias是下降)
如果使用regression,那么又有可能把沒有上升得那么快當成故障了(因為其bias是上升)。
這種基于近期趨勢計算方差的算法還有一個缺陷是當前面幾個點振動很大的時候,方差值會被搞大。后面的故障就被掩蓋了,使得連續的故障點無法被檢測到。
其實也就是算法對于什么是正常是沒有概念的,它認為過去的歷史就是正常。如果過去幾分鐘處于故障中,那么故障的曲線就是正常。
實際使用中發現這種基于曲線平滑度的算法的優點有
依賴的數據少,只需要近期的歷史,不依賴于周期性
非常敏感,歷史如果波動很小,方差就很小,容忍的波動范圍也會非常小
缺點也是顯著的:
過于敏感,容易誤報。因為方差會隨著異常點的引入而變大,所以很難使用連續三點才告警這樣的策略
業務曲線可能自身有規律性的陡增和陡降
最佳的使用方式是不用一根曲線做告警。結合幾條相關的曲線,如果同時出現平滑度破壞的情況,而且與業務規律的趨勢相背離(比如在線人數降低,登陸請求數增高)則可以認定為業務出現故障。
基于絕對值的時間周期性
上圖中不同的顏色代表了不同日期的曲線。
很多監控曲線都有這樣以一天為周期的周期性(早上4點最低,晚上11點最高之類的)。一種利用時間周期性的最簡單的算法:
min(14 days history) * 0.6
對歷史14天的曲線取最小值。怎么個取最小值的方法?
對于12:05分,有14天對應的點,取最小值。對于12:06分,有14天對應的點,取最小值。這樣可以得出一條一天的曲線。
然后對這個曲線整體乘以0.6。如果幾天的曲線低于這條參考線則告警。
這其實是一種靜態閾值告警的升級版,動態閾值告警。
過去靜態閾值是一個根據歷史經驗拍腦袋的產物。用這個算法,其實是把同時間點的歷史值做為依據,計算出一個最不可能的下界。同時閾值不是唯一的一個,而是每個時間點有一個。如果1分鐘一個點,一天中就有1440個下界閾值。
實際使用中0.6當然還是要酌情調整的。而且一個嚴重的問題是如果14天歷史中有停機發布或者故障,那么最小值會受到影響。
也就是說不能把歷史當成正常,而是要把歷史剔除掉異常值之后再進行計算。一個務實的近似的做法是取第二小的值。
為了讓告警更加精確,可以累積計算實際曲線和參考曲線的差值之和。也就是相對于參考曲線下跌的面積。這個面積超過一定的值則告警。
對于深度下跌,則累積幾個點就可以告警。對于淺度下跌,那么多累幾個點也可以告警出來。
翻譯成人話就是,一下在跌了很多,則很有可能是故障了。或者連續好久都偏離正常值,那么也很有可能是出問題了。
優點:
計算簡單
可以確保發現大的故障,出了告警一定是大問題,可以直接打電話
缺點:
依賴周期性的歷史數據,計算量大,而且無法對新接入的曲線告警
非常不敏感,小波動無法發現
基于振幅的時間周期性
有些時候曲線是有周期性,但是兩個周期的曲線相疊加是不重合的。
比如上圖這樣的,曲線整體的趨勢是網上的。兩個周期的曲線一疊加,一個會比另外一個高出一頭。對于這種情況,利用絕對值告警就會有問題。
比如今天是10.1日,放假第一天。過去14天的歷史曲線必然會比今天的曲線低很多。那么今天出了一個小故障,曲線下跌了,相對于過去14天的曲線仍然是高很多的。這樣的故障如何能夠檢測得出來?
一個直覺的說法是,兩個曲線雖然不一樣高,但是“長得差不多”。那么怎么利用這種“長得差不多”呢?那就是振幅了。
與其用x(t)的值,不如用x(t) - x(t-1)的值,也就是把絕對值變成變化速度。可以直接利用這個速度值,也可以是 x(t) - x(t-1) 再除以 x(t-1),也就是一個速度相對于絕對值的比率。
比如t時刻的在線900人,t-1時刻的在線是1000人,那么可以計算出掉線人數是10%。這個掉線比率在歷史同時刻是高還是低?那么就和前面一樣處理了。
實際使用中有兩個技巧:可以是x(t) - x(t-1),也可以是x(t) - x(t-5)等值。跨度越大,越可以檢測出一些緩慢下降的情況。
另外一個技巧是可以計算x(t) -x(t-2),以及x(t+1) - x(t-1),如果兩個值都異常則認為是真的異常,可以避免一個點的數據缺陷問題。
優點:
比絕對值要敏感
利用了時間周期性,規避了業務曲線自身的周期性陡降
缺點:
要求原曲線是光滑的
周期性陡降的時間點必須重合,否則誤警
按百分比計算容易在低峰時期誤警
陡降不一定代表故障,由上層服務波動引起的沖高再回落的情況時有發生
這種異常告警算法是比較優秀的。缺點也很多。所以可以進行一些修補湊合用。
為了避免低峰時期,基于振幅百分比容易誤警,可以加入絕對振幅的下限。
業務上來說,就是小波動如果相對比率大,但是絕對影響范圍小也是沒關系的。對于沖高回落的問題,可以判斷一下沖高的情況,對于沖高之后屏蔽一段時間。
基于曲線回升的異常判斷
當我們看見圖2的時候比圖1更確認是故障了。為什么?
因為圖2中有一個明顯的回升。算法其實和人眼一樣。如果多等幾個時間點,發現曲線回升了可以更很準確地判斷“曾經”有一個故障。
但是這種基于回升的異常檢測是沒有多少“告警”意義上的機制的。
告警的作用就是讓人參與干預,去幫助曲線回升。如果曲線已經開始回升,再告警不是事后諸葛了嗎?
這種檢測的意義在于機器復制告警的確認。
當我們需要統計誤警率,漏警率的時候,用另外一種視角的算法重新跑一遍可以統計出很多原算法的問題。
同時也可以用半自動化的方式建立一個歷史故障的樣本庫。這個樣本庫可以變成更復雜的機器學習算法的訓練集。
核心要點:
高質量的告警是actionable的
不應該用采集的難度決定你使用什么指標去告警
不要別人做什么告警,你就做什么,要做“真正”有用的告警:特別是cpu使用率告警
is work getting done:請求數 + 成功率
is the user having good experience:響應延遲
只要采集對了指標,大部分時候告警不需要復雜算法
基于算法的異常檢測:算法不難,實在必要也是可以做到的
關于怎么設計告警系統就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。