導讀:阿里巴巴千億交易背後,如何儘可能避免發佈故障?在面對實際運維過程當中遇到的問題該如何解決?近日,在GOPS大會上,阿里巴巴運維技術專家少荃,給咱們帶來了解決方案和思路。java
做者:陸葉平(花名少荃),阿里巴巴研發效能事業部技術專家。目前從事運維中臺(阿里內部叫諾曼底)建設方面的工做,是集團內最大的應用發佈系統(海狼)負責人。算法
前言數據庫
近幾年,咱們在發佈效率和穩定性方面作了很多工做,其中效率簡單的說就是發佈耗時,一個是發佈的速度,好比一個應用是1個小時發佈完成,仍是5分鐘發佈完成?另外一個是人員介入,開發在發佈過程當中是否須要介入處理各類發佈過程當中出現的問題?這二者都作好了,才能說是發佈效率提高了。穩定性最基礎的是系統的穩定性,保障系統的可用,而最關鍵的是要保障經過系統來進行發佈的應用的穩定性,不會由於發佈而致使服務不可用等故障出現。安全
效率這塊咱們在集團內比較受好評的產品是SP2P的文件分發系統,叫作蜻蜓,咱們根據阿里自身的一些特色,實現了一套安全高效的P2P分發,同時在P2P的協議上引入了超級節點,就是S,提高了P2P網絡的啓動速度,目前已經開源。穩定性這塊咱們去年作了一個產品,叫作無人值守發佈,對發佈進行檢測,看看發佈是否會引發問題,來提高發布的可靠性,今天就和你們一塊兒交流下這方面的心得。網絡
咱們爲何要在穩定性方面投入大量精力呢?先讓咱們來看一個笑話。架構
變動故障運維
這個笑話可能沒那麼可笑,可是它真真切切的說明了一個問題:理想和現實的差別,你覺得是有四個單身狗陪你,可是實際倒是另外兩對情侶。這個和咱們作生產環境的發佈是同樣的,咱們覺得憑藉咱們出色的邏輯思惟能力,已經把全部場景都想到了,測試也作的很充分了,可是,發佈上線後,常常會遇到實際結果和預期不一致,故障發生了。咱們針對阿里的故障產生緣由作了統計,其中很大一部分都是線上變動引發的,相信在座各位也會遇到或者製造過故障,開發和運維的同窗對故障都是很敬畏的。機器學習
故障你們都遇到過,可是故障的影響差別會比較大。有些故障多是故障發現後處理了一會就恢復了,有些故障則可能會致使嚴重的後果。因此咱們須要儘可能避免變動帶來的故障。單元測試
業務挑戰:阿里的特殊業務場景學習
回到阿里,咱們都知道,去年雙11的成交額已經達到了1682億,想象下,這麼大的交易額下,若是出現了故障,那會怎麼樣?
阿里如今的業務多樣化發展,新零售、線下支付等一些新的業務場景,要求咱們對故障更加敏感,要可以更好地避免故障,更快地發現和處理故障。想一下,若是是線下場景,好比用支付寶坐地鐵,若是出現幾分鐘的服務不可用,那會怎麼樣?
那麼,如何才能在發佈的時候有效的避免故障發生呢?
靠「蒙」?你們知道確定不行。但是細想一下,不少時候確實或多或少在「蒙」。我我的是有過相似感覺的。咱們雖然不會隨便到不通過測試就進行線上發佈,可是雖然已經通過了多輪測試,確定仍是沒有辦法覆蓋線上各類複雜多樣的場景的,而這些沒有辦法覆蓋的場景,就只能靠運氣去"蒙"了,運氣好的,這些場景沒有問題,運氣很差,恰好就其中一個場景出問題,出現故障了。
一般來說,爲了儘量不要去「蒙」,咱們會對上線流程加入各類驗證環節,來保證發佈儘量可靠。例如發佈前,咱們會經過各類測試來驗證功能是否ok,包括單元測試、集成測試等,發佈過程當中,咱們會經過一些發佈策略,例如先預發(預發佈是一種特殊的線上環境,和線上使用一樣的資源,好比數據庫等,可是不會有用戶流量進來)、而後灰度、而後分批滾動發佈等方式,逐步將變動更新到線上,發佈完成後,又會藉助一些故障預警系統,例如像阿里有GOC來儘早的發現故障,進行處理,這些環節的這些手段都已經有成熟的系統來進行支持,可是發佈的時候,咱們經常仍是內心沒有底。
"人工智能"的解決方案
那麼,還有什麼辦法可以幫助咱們儘量地保障發佈質量呢?你們可能都已經在作了:就是"人工"智能的發佈保障。
在發佈過程當中,盯着各類屏幕,去看各類數據,來人肉的判斷本次發佈有沒有問題。在阿里,這些屏幕包括:監控、發佈單、機器、GOC故障預警等。監控可以反映出來當前系統的一些情況,例如機器的負載是否上去了,接口的成功率是否降低了,發佈單則能讓咱們瞭解當前的發佈狀況,有多少機器已經更新到新版本了,有多少還在跑舊版本,有多少機器啓動又遇到異常了等等,盯着機器則能夠看一些日誌信息,是否有一些新的異常出現了,異常的量是否很大等等,GOC讓咱們在故障發生的第一時間就能知道,結合本身發佈的內容判斷是不是本次發佈引發,須要進行處理。
這種方式相比以前讓人放心多了,是由於如今咱們看到的是最真實的線上環境的狀況,而不是單單的測試數據。可是這種人肉盯屏的方式也存在着很大的問題,首先是成本過高了,發佈過程當中須要有熟練工盯着各類屏幕去看,片刻不離,其次是人的因素太大了,一樣的發佈狀況,不一樣的人分析出來的結果可能徹底是不同的,即便是同一我的,由於狀態或者其餘方面的緣由,針對一樣的一些數據,可能分析出來的結果也不同,另外,人也有侷限性,各類數據刷新很快,肉眼分析的方式根本都來不及看。
既然這種盯屏的方式被證實是有效的,可是存在一些問題,那麼咱們就考慮經過系統化來解決這些問題,因此,就有了"無人值守發佈"。
無人值守發佈
無人值守發佈主要是把上述過程自動化、智能化。經過自動化採集這些實時的線上核心數據,進行智能化分析,迅速對發佈情況進行判斷,是否有故障發生,有的話則當即終止當前發佈。
無人值守發佈的兩大核心能力,一個是故障檢測,一個是異常推薦。故障檢測主要是發現如今的問題。異常推薦主要是防範於未然,是指發佈出現了問題,可是不必定會引發故障,這些異常給開發的同窗透明出來,須要開發注意,比較常見的是出現了一些異常,這些異常從絕對數量或者漲幅來看沒有很是明顯,但多是須要處理的。
首先是發佈單詳情頁面中的無人值守信息展現,發佈單詳情頁面是發佈過程當中最常會去看的頁面,因此咱們選擇把無人值守檢測出來的一些信息展現到這個頁面,在一個頁面中把能夠作的事情都作掉。固然,並非說開發同窗必定要本身去刷這個頁面纔可以知道當前發佈是否有異常,當發佈出現異常的狀況下,系統會先自動暫停當前的發佈,而後經過釘釘等一些通知方式,告知開發的同窗,你的某個發佈出現了異常,須要你去看下。
這些展現的信息包括了左側的當前發佈是否有異常的概要信息,經過概要信息,能夠知道當前發佈有沒有問題,若是有問題,能夠看右側的問題分類,是基礎監控指標出問題了,仍是業務指標出問題了,或者是日誌出問題了,日誌出問題具體是哪一個日誌有問題了,在這裏均可以看到。
若是這裏的信息還不夠來判斷是否發佈有問題,那麼點擊查看詳情,能夠看到更加詳細明確的異常信息,來進行判斷。
無人值守發佈的時候須要應用接入到無人值守發佈系統,固然大部分狀況下這是一個自動化的過程,系統會判斷應用是否符合接入標準,若是符合,會自動接入,可是也有一些狀況會致使應用沒法自動接入,這種狀況下,也會告知用戶當前應用是否接入了,若是未接入,須要作一些配置或者改造來接入。
無人值守發佈詳情
這個是無人值守發佈信息展現的詳情頁面,在這個上面,能夠看到更加明細的一些信息,好比異常數量的發佈先後趨勢對比,業務監控各個指標的變化狀況等。經過這個頁面,開發的同窗基本上有足夠的信息來判斷本次攔截是否有效,是否須要進行回滾等操做。
無人值守接入
這個是應用接入無人值守發佈的一個頁面,主要須要配置業務監控指標、日誌路徑等。
這是一個典型的案例,其中一些數據作了隱藏或者處理。發佈過程當中日誌中某個異常出現了大幅度增加,咱們能夠從左側看到異常的數量,點擊異常信息還能夠看到更加明確的異常堆棧信息,右側能夠看到異常數量出現了明顯增長,下面能夠看到這個檢測被用戶判斷爲確實有問題,最終執行了關閉發佈單進行回滾的操做。
用戶反饋
這些是用戶的一些反饋。應用接入無人值守發佈,對提高發布的穩定性起了立竿見影的效果。
指標
上面這些案例都表明了一部分用戶的感覺和反饋,那麼總體效果怎麼樣,仍是要拿數據來講話。
業界對於異常檢測這塊有兩個主要的指標:一個是召回率,一個是準確率。
召回率主要用來反映漏報的狀況,準確率主要用來反饋誤報的狀況。漏報和誤報的概念比較好理解。漏報就是原本有10個故障,系統報了9個,那麼漏報了1個,召回率是90%,誤報就是隻有10個故障,報了20個出來,多出來的10個就屬於誤報,那麼準確率就是50%。
目前準確率方面,咱們已經作到了60%左右,也就是說差很少每報2次,就有一次確實是有問題的,這種體驗應該算還不錯。
召回率方面,咱們已經作到了90%,這個90%是指出現了一次故障咱們沒有報出來,咱們有效攔截了9次,這9次中可能會引發故障,也可能只是有問題,可是不會形成故障,可是由於及時發現了,都沒有形成故障,很難明確說這9次裏面到底有多少是會形成故障的,因此計算召回率的時候沒有單獨計算故障的召回率,而是把故障和異常一塊兒計算進去了。
關於先重點抓哪一個指標,咱們也經歷過一些波折。一開始的目標是攔截儘量多的故障,因此比較注重召回率,致使長期一段時間內,準確率很低,攔是攔了很多,可是誤報至關多,報10次裏面可能只有一次是有效的,若是咱們是用戶,可能幾回誤報之後,就對這個產品失去信心了,這個致使咱們不敢大面積推廣。後來調整策略,優先解決準確率的問題,反正沒咱們系統以前這些故障也是存在,有了系統,能減小一些就是好的,因此先不追求召回率,把準確率作上去後,能夠大面積進行推廣了,受益面大了,避免的故障也天然多了。固然,後面仍是繼續抓了召回率的。
無人值守發佈實現
前面說了很多,可是都沒有提到系統的具體實現,接下來咱們看是怎麼去實現無人值守發佈的?
首先看下咱們的產品分層和業務流程。
咱們的系統大體分了三層,最上面一層是發佈系統層,咱們的產品叫海狼,主要是發佈單的提交、執行以及無人值守信息的展現和反饋,這一層是能夠擴展的,除了發佈系統外,也能夠對接其餘的一些變動系統。
中間是無人值守的核心繫統,根據收集到的分析任務,採集對應的數據,進行分析檢測。
最下面一層是離線分析層,主要用來作一些算法的訓練、回放驗證等,後面再具體介紹。
大體的業務過程是,用戶在發佈系統中提交了一個發佈計劃,這個時候會經過Normandy(諾曼底)這個平臺進行發佈(海狼是諾曼底平臺的一部分,負責發佈的執行),海狼開始執行發佈單後,無人值守系統就會收到發佈單執行的事件,而後開始分析,分析的時候會利用離線算出來的一些特徵集,而後和當前的指標進行比較檢測,若是有異常,那麼會經過海狼的接口進行暫停發佈單的操做,用戶能夠在發佈單頁面看到對應信息,而後進行一些判斷後提交反饋,是有效攔截,仍是誤報等。
上述是一個大體的過程,具體實現方面,咱們通過了兩個大的版本迭代,下面針對兩個版本分別介紹下。
1.0實現
經過前面的介紹,應該大體瞭解,無人值守發佈就是分析發佈過程當中各類指標數據,來判斷髮布是否有異常,那麼具體有哪些指標數據能夠用來分析呢?大體總結了下,有如下幾類:
首先是業務指標,這個最直接反應當前發佈有沒有問題,若是影響到了業務,那麼基本上就是有問題的。若是業務指標可以覆蓋全部的故障場景,那麼理論上只要分析業務指標就好了,可是現實每每是不少業務指標的完善都跟不上業務發展的,業務上去了,指標還沒上,這是很現實的事情。
其次是一些基礎指標,例如機器的內存使用狀況,cpu使用率,load狀況,磁盤io等,這些指標通常在發佈過程當中不太會發生明顯的變化,可是一旦發生了明顯變化,就可能有問題了。
還有些中間件的指標,阿里內部普遍使用的hsf、tair、metaq等,都有相應的qps、rt、成功率等指標,若是發佈後成功率忽然跌的比較明顯或者qps跌0等,那麼也頗有多是有問題了。
還有一個比較關鍵的是日誌,阿里比較多的應用是java的,咱們會在日誌中把一些異常的堆棧信息都打印出來,這些異常信息反映了代碼運行過程當中的一個不正常狀態,因此是一個很寶貴的指標數據。經過分析這些異常的出現狀況、漲幅狀況、或者是否出現了一些常見的容易引發故障的異常,例如ClassNotFound等,咱們能夠作出足夠有用的判斷。
指標和算法選取
指標這麼多,咱們一開始應該從哪入手呢?
第一個版本的時候,咱們選擇了基礎監控和日誌這兩方面入手。緣由比較簡單,基礎監控的覆蓋率夠高,有足夠多的數據可讓咱們分析,而日誌根據經驗則很是重要。至於業務監控和中間件指標,因爲數據方面等一些問題,第一個版本咱們沒有去考慮。
那怎麼對基礎監控和日誌的指標進行分析呢?咱們採用的是使用一些簡單的規則加上覆雜的算法共用的方式,針對一些狀況,例如出現了前面提到的危險異常等,採用規則的方式,直接進行攔截,針對異常的漲幅變化等,則採用算法來評判這個漲幅是否在合理範圍內。
如何實現
肯定好了指標和分析思路,咱們再看看須要作哪些事情。首先要作的是數據採集,咱們面臨的問題是須要採集哪些數據,怎麼儘快地採集這些數據。其次是對數據進行處理,原始的數據中會有一些干擾的數據,干擾的來源多是多方面的,多是數據採集系統自己的問題,也多是與業務自身的特色有關,須要把這些干擾的數據可以剔除掉。而後就是針對採集和處理後的這些數據,制定什麼樣的規則,使用什麼樣的算法,來對它們進行分析,儘量準確的判斷出發佈後的數據是否有問題。
數據如何採集
首先咱們來看看數據怎麼採集?
採集以前,先明確檢測的大體思路:發佈前和發佈後的指標進行對比,已發佈和未發佈的機器進行對比。因此,咱們要採集的是時間序列的數據,也就是每一個時間點某個指標是什麼樣的一個數據,例如某個時間點,系統的load是多少,某個時間點,某類異常出現了多少次等。
具體要採集哪些指標,上面已經明確了,只要把這些指標再作一個分析,把最重要最能反映故障狀況的一些指標挑選出來,採集過來就行。
而從哪些機器上採集指標呢?前面提到,咱們檢測思路中有一條是已發佈和未發佈的機器進行對比,因此咱們爲每一個應用設置了兩組機器,一個是發佈組,一個是參照組,只採集這兩組機器的數據,而不是全部機器的數據都採集。至於採集時間,也不用採集全部數據,只要採集發佈先後一段時間內的數據就能夠。
採集到數據之後,接下來就須要對數據進行一些處理,除了前面提到的一些干擾數據剔除外,咱們還須要進行一些維度的聚合,由於拿到的是一些單機數據,因此須要針對已發佈未發佈等一些維度進行數據聚合合併,最終生成了能夠分析的數據。
數據分析方法
數據分析的方法,咱們採用的是改進型的funnel檢測模型,它有這些優勢:能夠知足針對不一樣的指標,採用不一樣的算法的需求,不一樣的指標有各自的特色,使用同一個算法顯然不大合適;其次它的計算須要的資源少,同時檢測的速度又夠快,還支持不少指標一塊兒分析。
經過上述這些工做,咱們大體就把一個檢測系統創建run起來了,這第一個版本在準確率方面表現不是很好,離線跑的時候可以有30%、40%,可是線上實際跑的時候只有10%上下的準確率,因此咱們須要去提高準確率,那怎麼提高呢?
答案是不斷的分析誤報和漏報數據,而後對算法作一些微調。不停的微調算法又帶來了一個新的問題,針對這些誤報的數據,可能新的算法不會報出來了,可是以前的那些沒報的數據呢,用新的算法會不會又報出來了?以前那些報出來的有效攔截,會不會新的算法中就不報出來了?
因而咱們又搭建了以前產品架構中提到的離線回放系統,用來對算法進行回放驗證,從以前的誤報、有效攔截、未攔截等數據中抽取部分數據,每次算法調整後,經過回放系統對這些數據從新進行檢測分析,看看準確率和召回率是怎麼變化的,誤報的是否還在誤報,有效攔截的是否漏報了等等。
無人值守回放系統
整個無人值守回放系統大體過程以下:錄製模塊會將線上檢測過的發佈單的相關數據錄製到回放db,而後須要回放的時候,經過回放觸發接口,觸發無人值守進行檢測,檢測時候會調用回放系統提供的指標mock接口,從回放db獲取數據,而不是從實際的數據源獲取數據,將回放檢測的結果進行保存,產出回放結果報表。
算法的困境
經過無人值守回放系統,咱們創建了可靠的算法驗證機制,經過不斷的微調算法來提高召回率和準確率。可是,仍是遇到了一些問題。
首先是須要不斷的去分析檢測數據,而後調整算法,這個過程是至關耗費精力的,而且不必定可以有相應的回報。還有很重要的一點是,在實踐過程當中,咱們發現一些明顯的誤報信息在重複的誤報。
因此咱們須要去探索一個可以解決這些問題的方案。因而,第二個版本,咱們就採用了基於機器學習的方式在原來的基礎上作了一些改進。
機器學習的大概過程
首先會有一個離線學習的過程,經過一些歷史的發佈單的指標數據和攔截數據,以及用戶反饋的一些數據,計算出來應用發佈時候的一個特徵庫,發佈的時候,會首先採用一些算法來檢測出可疑指標,而後對可疑指標和特徵庫進行比較,若是發現這個可疑指標落在正常的特徵庫裏,那麼忽略掉,不然,就認爲發佈出現了異常進行攔截,攔截完成後,會根據發佈單最終的結果和用戶的反饋行爲將此次攔截是否有效等數據保存起來,做爲下次離線計算的一個輸入數據。
三大要素
機器學習也面臨幾個問題須要去解決,首先是去學習什麼樣的數據,其次是要經過什麼樣的方法去學習產出什麼樣的結果,還有一個就是怎麼樣把這個學習的結果用到後面的發佈檢測中去。
樣本
咱們首先看下樣本問題,就是學什麼數據。咱們有的數據大體有這些:發佈單數據、發佈過程當中的指標數據、攔截是否有效的數據、用戶反饋的一些數據。
這些數據看起來不少,天天的發佈單有好幾萬,每一個發佈單又有大量的指標數據,可是實際上,每一個應用的特徵都是不同的,因此學習的時候必定是基於應用的維度去學習的,而每一個應用的發佈數據就不多了,如何從這很少的數據去計算應用的發佈特徵呢?
計算的思路也有兩個,一個是算異常的,比較天然的想法,找出異常的特徵,下次若是匹配了異常特徵,那麼就能夠判斷髮布有問題,一個是算正常的,而應用維度異常的發佈每每遠少於正常發佈,甚至可能都歷來沒有過異常發佈,因此基於異常的維度去計算,也不大靠譜,相對比較靠譜點的,只能是經過正常的發佈單數據去計算出應用發佈的正常發佈特徵。
樣本中的一個挑戰是如何來判斷一個發佈真正是有問題的,咱們採起的是發佈單行爲和用戶反饋相結合的方式,若是發佈單被回滾了,那麼就認爲是異常的,若是用戶反饋說有異常,那麼也認爲是異常的。
關鍵和不靠譜是用來描述用戶反饋數據的兩個特色的,關鍵是指用戶反饋數據很是重要,是最可以幫助咱們去了解應用的各個指標對異常檢測是否有幫助的,可是用戶反饋數據又具備主觀性,發佈過程當中出現了某個異常,A開發同窗可能會反饋認爲沒有問題,而B同窗比較謹慎可能就會反饋認爲確實是有問題,如何去平衡這兩個特色也是比較棘手的。
這個就是剛纔提到的用戶反饋數據,經過這個反饋數據,咱們能夠明確的知道某個指標雖然異常了,可是對這個應用來講,多是徹底沒有用的,根本不須要做爲檢測的依據,那麼下次檢測的時候就能夠忽略掉該指標。
這個反饋數據的採集看似很容易,可是據我所知,在很多公司裏,採集這個數據阻力都是比較大的,開發同窗不肯意去填寫反饋這些信息,比較幸運的是,咱們經過一系列方式優化,儘量地減小這個反饋對開發的干擾,把這個反饋給強制開啓來了,採集到的數據對咱們的幫助確實至關大。
算法
樣本數據有了,接下來就要根據樣本數據計算出應用的發佈特徵了,咱們採用的是簡單的分類的方法,最初的想法是分紅正常、異常、未分類三大類,正常比較好理解,異常是指每次出現都會致使故障的,未分類則是一些新增的或者以前出現過沒有變化的一些指標,後面考慮到上面說的異常樣本很是小的問題,就把這三類統一成一類了,就是隻計算應用發佈時候各個指標的一個正常閾值,若是下次發佈的時候,指標的值超過了這個閾值,那麼可能就是有問題。
具體學習的過程比較簡單,總結起來一句話就是:找到正常發佈單中指標的最大值,做爲應用的正常指標閾值。具體過程是:首先是發佈過程當中若是出現了異常指標,那麼會去看此次發佈最終是不是有問題的發佈(經過發佈單的行爲是否回滾以及用戶的反饋等),若是是正常發佈,那麼和以前的正常閾值進行比較,若是比以前的正常閾值要小,那麼忽略,若是比以前的閾值大,那麼就更新正常閾值,而若是此次發佈是異常發佈,那麼理論上應該去判斷此次的指標是否比正常閾值小,若是小,那麼要更新正常閾值,可是實際上,此次發佈的問題可能並不必定是這個指標引發的,並且若是確實是這個指標引發的話,那麼以前指標比這個值更大的發佈應該也是異常的,考慮到這兩點,咱們現階段採起的是忽略異常發佈單的方式,只針對正常的發佈單進行閾值計算。
指標使用
正常閾值的使用也比較簡單。發佈過程當中,若是發現了異常指標,那麼會找到該指標對應的正常閾值作比較,若是小於正常閾值,那麼忽略掉,若是超過了正常閾值,那麼做爲可疑指標,在一個窗口期內進行多輪檢測,窗口期會根據檢測的結果作一些動態調整,若是在窗口期內屢次被斷定爲可疑指標,而且達到了必定比例,那麼最終會被斷定爲異常指標,對發佈進行攔截。
整個機器學習的改進過程大體就是這樣,經過這個改進,咱們一方面解決了以前遇到的一些問題,提高了召回率和準確率,尤爲是準確率方面有了顯著提高。另一方面,也釋放了大量精力出來,能夠更好的優化這個學習的算法。
詳情請閱讀原文