萬級實例規模下的數據庫故障自愈探索實踐
精選1.背景
近幾年 vivo 數據庫運維規模快速增長,從數量上看增長了幾倍,達到了萬級別的規模,與此同時 DBA 每日需要處理200多條告警。
隨著運維規模越大,線上故障也就越多,DBA 對于每個故障的處理時效將會下降,如果沒有強有力的工具能提高故障的排查和修復效率,那么線上的穩定性就得不到保障。因此我們的想法是,我們固然要不斷提供更加豐富的工具,但無論工具再豐富,都需要人去主動使用,因此更重要的是改變以人為主、工具為輔的運維模式,引入自動化分析和自愈的手段來提升運維效率。
2.實現思路
2.1 短期和長期目標
目標確定后,接下來需要確定目標的實現思路。我們調研了業界的一些解決方案后,發現能力的發展可以總結為以下三個階段:
- 平臺化:能夠提供一些數據和統計信息,運維人員再基于這些信息來進行運維;
- 智能化:已經能夠提供分析和建議,但是否采納需要運維人員自行判斷;
- 自動化:已經有部分場景可以實現自動恢復,無需人工參與了。
通常平臺的發展過程如上所述,但是也需要結合我們自身的情況來決定,因為我們投入的人力較少,不是成團隊地投入這個工作,因此不太可能遵循這么一個發展策略。因此基于人力投入的情況,我們定下的目標是,短期內我們要做投入產出比最高的工作,以求達到立竿見影的效果,但長期來看,圖中成體系的基礎能力還是需要建設起來。
2.2 尋找切入點
為了短期達到立竿見影的效果,就需要尋找一個切入點。如果我們觀察一個故障的生命周期的話,可以看到故障的生命周期分為故障前、故障中和故障后:
- “故障前”包括故障預防 ;
- “故障中”包括故障發現、故障定位和故障恢復;
- “故障后”包括故障復盤。
那么從整個故障的生命周期來看的話,按照我們的經驗,DBA 大部分時間都是消耗在故障定位和故障恢復上的,而因為每類故障具有相似的定位路徑,所以比較容易去定義定位規則、沉淀專家經驗。因此我們的想法是將重點放在故障定位和故障恢復這兩個階段上,去提高 DBA 的運維效率,優先找一些投入產出比高的場景去實現故障自愈。
2.3 結合實際情況后的發展思路
結合前面提到的短期目標和長期目標,我們確定下來這么一個發展思路。
首先我們會重點去實現各類故障場景的自動分析和自愈,這些自動分析和自愈行為是由故障消息驅動的,這也是一個比較直觀的方式,因為 DBA 通常也是收到故障消息后,才去進行故障定位等操作。然后當過程中需要某類基礎能力時,就去重點發展該能力。
這樣我們的短期目標和長期目標就都能兼顧到。
2.4 如何在實現過程中保證數據庫可用性
在實現方案前,需要先思考一個問題,即我們如何在實現過程中保證數據庫的可用性?
之所以把數據庫可用性單獨提出來,是因為故障自愈是自動觸發、自動執行的,而且過程中通常需要去觸達數據庫,比如查詢數據庫的狀態或執行操作,那么這種自動的操作本身會帶來比較大風險,因此更加需要考慮實現過程中,如何避免對數據庫造成的可用性影響。那么如何避免可用性影響呢?我們的答案是將每個故障自愈方案上線的流程標準化。
3.具體實現
3.1 故障自愈方案上線流程
下圖是我們以可用性為第一考量的前提下,確定下來的故障自愈方案上線流程。
①確定方案:當有一個新的故障自愈場景需要實現時,首先需要把自愈方案確定下來,即確定在這個故障場景中,需要“做什么、怎么去做”。這里有兩種確定方案的方式,可以和 DBA 進行咨詢交流確定方案,也可以通過分析線上案例來確定方案
②開發測試:方案確定后進行程序的開發測試,此處不必贅述
③線上灰度:開發測試完成后,需進行線上灰度,這里我們支持針對具體對象進行灰度,比如某個集群經常發生該類故障,那么可以指定灰度該集 群。如果沒有具體對象,也可以設置百分比隨機灰度。當然如果某些故障場景發生的頻率很低,我們一開始也會進行線上演練,通過在線上模擬故障的方式來進行驗證
④全網生效:灰度完成后,開放全網生效
⑤演進方案:每個故障自愈方案不是上線后就是最終形態,還需要我們結合用戶反饋以及后續案例來不斷進行迭代優化
上述流程的五個步驟中,“確定方案”和“演進方案”是重點,因此下文展開介紹。
3.1.1 確定方案
在實踐中,我們通過和 DBA 咨詢交流以及分析線上案例的方式來確定故障自愈的方案。
- 咨詢交流
這里介紹下發生磁盤告警時自動清理 MySQL Binlog 的方案,通過和 DBA 咨詢交流的方式,我們確定了該方案。具體方案流程如下圖所示,其實整個方案就重點關注了兩個問題:
第一個問題,如何確定哪些 Binlog 是不可以清理的?答案是未備份的 Binlog 不能清理,因為會影響增量備份;備庫未同步的 Binlog 也不能清理,因為會影響復制同步。
第二個問題,如何保證刪除過程中的系統可用性?這里我們采用分批刪除、每次刪除睡眠一秒的方式來平滑刪除帶來的 IO 壓力。
- 案例分析
有時不是所有方案都能夠通過咨詢交流的方式確定下來,對于根因分析的場景,因為每個運維人員的運維經歷有所差別,如果要把所有可能的情況枚舉出 來,那么會導致方案十分冗長,因此一種更好的方法是通過分析線上真實案例來確定方案,這樣產出的方案是最貼合線上情況的,后續也可以不斷結合案例做迭代優化。
這里介紹下我們如何確定 SQL 類告警根因 SQL 分析方案。為了確定這個方案,我們分析了50個線上案例:首先找出哪些案例是能明顯看出有根因 SQL 的, 再對有根因 SQL 的類別進行細化,最后得到根因 SQL 的判斷步驟。
3.1.2 演進方案
針對某個故障場景的方案通常不是一步到位、直接擁有自動恢復故障的能力的,而是在實踐中不斷演進。我們把方案演進的過程分為下圖三個階段:
那么為什么要分階段去演進方案呢?
從效率的角度看,能夠先快速上線比較簡單的方案,可以快速地提高運維效率;
從可用性的角度看,前一階段是后一階段的基礎,只有前一階段驗證成熟了,再去不斷演進是比較安全的做法。
以 SQL 故障場景為例來演示方案的演進過程。我們的 SQL 故障場景方案一開始只是提供數據和統計,然后進一步地通過案例分析的方式,使其可以根據規則嘗試找出導致告警的根因 SQL,目前正在實現對根因 SQL 的自動優化建議,最終目標是可以具備對問題 SQL 自動優化、自動限流的能力。
3.2 故障自愈流程
基于上述的思路,我們實現了一個故障消息驅動、基于規則的故障自愈流程。
首先我們監聽了故障消息,當自愈系統接收到故障消息時,會根據這個消息類型去規則庫中查找對應的自愈流程,再通過流程編排引擎運行起來。流程中會去調用相關基礎能力,最后生成一個處理結果通知,發送到我們的工作溝通軟件。同時也會將這次流程的運行信息保存到分析中心,用戶后續可以在分析中心看到詳細的現場快照、分析結果,還能對這次分析進行評價標注。
下面對流程中的重點組件進行介紹。
3.2.1 故障消息
首先是故障消息,在一開始設計時,我們期望是可以支持接入各種故障消息,比如告警事件、巡檢事件等,但是在實踐中,我們還是優先針對 TOP 告警場景進行開發,因為故障消息中,絕大部分都是告警。而且據我們統計,TOP 5 的告警差不多占了所有告警的一半,優先針對 TOP 告警短期內能取得不錯的效果。
3.2.2 規則庫
規則庫保存了故障消息類型和自愈流程的綁定關系,自愈系統收到故障消息后,會根據這個消息類型去規則庫中查找對應的自愈流程。這里我們實現了一個簡單的流程編排功能,我們的想法是,先實現一些原子操作,再去將這些操作組合成一個流程,這樣可以讓操作具有的復用性,也更容易實現新的流程。
比如針對 CPU 告警,我們將 TOP 分析和 SQL 根因分析獨立成兩個原子操作,這樣這兩個操作也能復用在其他流程中。
3.2.3 分析中心
在分析中心,用戶可以看到監控告警詳情、現場快照、分析的結果,還可以通過這里向我們反饋這個告警的原因、如何排查等信息,幫忙我們去進行迭代優化。這樣自愈流程就不是一個黑盒了,也方便運維人員之間進行協作。
3.3 數據采集和計算
3.3.1 數據采集
故障自愈需要大量的數據支持,我們將數據分為三種類型。
監控數據:我們這邊的數據庫種類比較多,每種數據庫都有自己監控采集方式;
日志數據:采集流程中 Agent 先會向 Manager 查詢自己需要采集哪些日志,然后以類似 tail 的方式一行一行地采集,再上報給 Manager,最后由 Manager 根據配置的正則表達式解析成結構化數據,寫入 Kafka。這些日志包括慢日志、運行日志、全量日志等;
事件數據:我們開發了一個事件系統的 SDK,由各個服務使用這個 SDK,將自己服務的事件上報到事件系統。
3.3.2 數據計算
數據采集后,一些數據需要做計算處理。我們現在對數據做實時計算的場景比較少,下圖是近期的全量 SQL 需求。
首先由 Agent 采集 SQL LOG 文件,進行批量上報,為了降低 Kafka 的帶寬壓力,上報的時候需要進行壓縮。上報時指定實例地址作為 Kafka 分區 Key, 以保證同一個實例的數據能寫到同一個 Kafka 分區,因此也就能保證在實時計算端,同一個實例的數據會落在同一個處理線程上,這樣就能在接收到數據后,做一個預聚合,降低發往下游的網絡流量。然后通過逐層聚合的方式,先聚合出每分鐘每個 SQL_ID 的平均執行次數、平均響應時間等指標,再根據SQL_ID 的聚合數據,聚合出每分鐘每個 Table 的平均訪問次數指標。最后這份數據將用以支撐 SQL 趨勢、表流量統計、SQL 過載保護等功能。
4.成果和案例
4.1 成果
10+種故障場景分析和自愈能力:
使用6人月覆蓋線上70%以上告警:
4.2 案例
這里介紹一個案例:長時間執行的 SQL 數量達到閾值后,產生了告警,根據 SQL 根因分析得出,這是因為有一條長時間運行的 SQL 阻塞了其他 SQL,并把分析結果推送到故障處理群。從分析詳情可以看出,這是一個 MDL 鎖等待的經典場景,因為某條 SQL 長時間運行,備份進程執行 FLUSH 時請求 MDL 被阻塞,繼而引發后續 SQL 請求 MDL 阻塞。
5.未來展望
展望未來,仍有許多事項需要逐步建設完善:
建立可觀測、可跟蹤的效果度量機制。目前可觀測的指標只有告警覆蓋率,而對于每次分析的有效性和正確率,現在還無法度量,因此需要建立一套效果度量機制;
仍有許多基礎能力需要逐步建設完善,比如 SQL 優化建議、SQL 限流等功能;
基于規則的故障自愈方案容易碰到投入產出比降低、系統能力瓶頸等問題,因此需要借鑒業界方案,逐步使用 AI 技術,在各個功能場景進行嘗試。
作者介紹
林鋒英,vivo互聯網高級數據庫研發工程師。