天天看點

Mt-Falcon——Open-Falcon在美團點評的應用與實踐

前言

監控系統是整個業務系統中至關重要的一環,它就像眼睛一樣,時刻監測機房、網絡、伺服器、應用等運作情況,并且在出現問題時能夠及時做出相應處理。

美團點評剛開始使用的是Zabbix監控系統,幾經優化,在當時能夠達到2W+機器,450W+監控項的量。随着各業務線的發展,監控項越來越多,Zabbix的問題也越來越突出,當時針對Zabbix的吐槽問題有:

  • 不支援擴充,本身是一個單點,當機器規模超過萬台的時候會出現很明顯的性能問題。
  • 改造難度比較大,不支援定制化功能。
  • 配置比較複雜,學習成本較高。
  • 對外提供的API不夠豐富,很難與其他業務系統內建。

這個時候我們急于尋找一個替代的解決方案,經過篩選後,最終選擇引進最初由小米開源的Open-Falcon監控系統(文檔)。

下面本文将為大家詳細介紹Mt-Falcon在原來Open-Falcon的基礎上做出的一些改進。

Open-Falcon架構圖

圖檔轉載自Open-Falcon官網

Mt-Falcon的架構圖

Mt-Falcon相對Open-Falcon改造後,比較大的功能點有:報警禁用、報警ACK、報警更新、報警任務分布式消費、支援OpenTSDB存儲、字元串監控、多條件監控、索引資訊存儲改造、過期索引資訊自動删除且重新上報後會再次重建等。

改進清單

一、Agent改造

1. 提升Agent資料轉發的性能

異步化處理。之前是每調一次Agent的上報接口就會往Transfer上報一次,在資料量特别大,每次發送條數又比較少的情況下,有可能會出現資料丢失的情況。現在會把監控資料先緩存在Agent程式緩存裡面,每0.5秒往Transfer上報一次,每次最多發送1W條監控項。隻要一個上報周期(預設60s)上報的監控項個數<100W就不會出現性能問題。

2. 上報網卡流量時辨別出機器不同的網卡類型

業務方的機器有可能一部分在千兆叢集上,一部分在萬兆叢集上,不是很好區分。之前配置網卡監控的時候統一應用的是千兆網卡的監控名額,這樣就造成了萬兆叢集上面機器的網卡誤報警。在Agent采集網卡名額的時候自動打上網卡類型的Tag,就解決了上面的問題。現在機器網卡類型主要有4種,千兆、萬兆、雙千兆、雙萬兆,配置監控政策時可以根據不同的網卡類型設定不同的報警門檻值。

3. 支援程序級别的coredump監控

這個類似于普通的程序監控,當檢測到指定程序出現core時,上報特定的監控名額,根據這個監控名額配置相應的報警政策即可。

4. 日志自動切分

正常情況下Agent的日志量是很小的,對,正常情況下。但是,凡事總有意外,線上出現過Falcon-Agent的日志量達到過100多G的情況。

為了解決這個問題,我們引入了一個新的日志處理庫Go-Logger。Go-Logger庫基于對Golang内置Log的封裝,可以實作按照日志檔案大小或日志檔案日期的方式自動切分日志,并支援設定最大日志檔案儲存份數。改進版的Go-Logger,隻需要把引入的Log包替換成Go-Logger,其他代碼基本不用變。

Go-Logger的詳細用法可參考

5. 解決機器hostname重複的問題

系統監控項名額上報的時候會自動擷取本地的hostname作為Endpoint。一些誤操作,如本來想執行host指令的,一不小心執行了hostname,這樣的話本地的hostname就被人為修改了,再上報監控項的時候就會以新的hostname為準,這樣就會導緻兩台機器以相同hostname上報監控項,造成了監控的誤報。

為了解決這一問題,Falcon-Agent擷取hostname的方式改為從/etc/sysconfig/network檔案中讀取,這樣就避過了大部分的坑。另外,當已經發生這個問題的時候怎麼快速定位到是哪台機器hostname出錯了呢?這個時候可以選擇把機器的IP資訊作為一個監控名額上報上來。

6. 支援Falcon-Agent存活監控

Falcon-Agent會與HBS服務保持心跳連接配接,利用這個特性來監控Falcon-Agent執行個體的存活情況,每次心跳連接配接都去更新Redis中目前Falcon-Agent對應的心跳時間戳。

另外,啟動一個腳本定時擷取Redis中所有的Falcon-Agent對應的時間戳資訊,并與目前時間對應的時間戳做比對,如果目前時間對應的時間戳與Falcon-Agent的時間戳的內插補點大于5分鐘,則認為該Falcon-Agent跪掉了,然後觸發一系列告警。

二、HBS改造

1. 記憶體優化

在進行資料通信的時候有兩點比較重要,一個是傳輸協定,一個是資料在傳輸過程中的編碼協定。

HBS(HeartBeat Server)和Judge之間的通信,之前是使用JSON-RPC架構進行的資料傳輸。JSON-RPC架構使用的傳輸協定是RPC(RPC底層其實是TCP),編碼協定使用的是Go自帶的encoding/json。

由于encoding/json在進行資料序列化和反序列化時是使用反射實作的,導緻執行效率特别低,占用記憶體也特别大。線上我們HBS執行個體占用的最大記憶體甚至達到了50多G。現在使用RPC+MessagePack代替JSON-RPC,主要是編碼協定發生了變化,encoding/json替換成了MessagePack。

MessagePack是一個高效的二進制序列化協定,比encoding/json執行效率更高,占用記憶體更小,優化後HBS執行個體最大占用記憶體不超過6G。

關于RPC和MessagePack的內建方法可以參考

2. 提供接口查詢指定機器對應的聚合後的監控政策清單

機器和Group關聯,Group和模闆關聯,模闆與政策關聯,模闆本身又支援繼承和覆寫,是以最終某台機器到底對應哪些監控政策,這個是很難直覺看到的。但這個資訊在排查問題的時候又很重要,基于以上考慮,HBS開發了這麼一個接口,可以根據HostID查詢目前機器最終應用了哪些監控政策。

3. 解決模闆繼承問題,現在繼承自同一個父模闆的兩個子模闆應用到同一個節點時隻有一個子模闆會生效

兩個子模闆繼承自同一個父模闆,這兩個子模闆應用到同一個節點時,從父模闆中繼承過來的政策隻會有一個生效,因為HBS在聚合的時候會根據政策ID去重。如果兩個子模闆配置的是不同的報警接收人,則有一個模闆的報警接收人是收不到報警的。

為了解決這個問題,改為HBS在聚合的時候根據政策ID+ActionID去重,保證兩個子模闆都會生效。

4. 報警禁用

對于未來可以預知的事情,如伺服器重新開機、業務更新、服務重新開機等,這些都是已知情況,報警是可以暫時禁用掉的。

為了支援這個功能,我們現在提供了5種類型的報警禁用類型:

  • 機器禁用:會使這台機器的所有報警都失效,一般在機器處于維修狀态時使用。
  • 模闆禁用:會使模闆中政策全部失效,應用此模闆的節點都會受到影響。
  • 政策禁用:會使目前禁用的政策失效,應用此政策對應模闆的節點都會受到影響。
  • 指定機器下的指定政策禁用:當隻想禁用指定機器下某個政策時可以使用此方式,機器的其他監控政策不受影響。
  • 指定節點下的指定模闆禁用:這個功能類似于解除該模闆與節點的綁定關系,唯一不同點是禁用後會自動恢複。

為了避免執行完禁用操作後,忘記執行恢複操作,造成監控一直處于禁用狀态,我們強制不允許永久禁用。

目前支援的禁用時長分别為,禁用10分鐘、30分鐘、1小時、3小時、6小時、1天、3天、一周、兩周。

三、Transfer改造

1. Endpoint黑名單功能

Falcon的資料上報方式設計的特别友好,在很大程度上友善了使用者接入,不過有時也會帶來一些問題。有業務方上報資料的時候會把一些變量(如時間戳)作為監控項的構成上報上來,因為Transfer端基本沒有做資料的合法性校驗,這樣就造成了某個Endpoint下面對應大量的監控項,曾經出現過一個Endpoint下面對應數千萬個監控項。這對索引資料資料的存儲和查詢性能都會有很大的影響。

為了解決這個問題,我們在Transfer子產品開發了Endpoint黑名單功能,支援禁用整個Endpoint或者禁用Endpoint下以xxx開頭的監控名額。再出現類似問題,可與業務方确認後立即禁用指定Endpoint資料的上報,而不會影響其他正常的資料上報。

2. 指定監控項發送到OpenTSDB

有些比較重要的監控名額,業務方要求可以看到一段時間内的原始資料,對于這類特殊的名額現在的解決方案是轉發到OpenTSDB裡面儲存一份。Transfer會在啟動時從Redis裡面擷取這類特定監控項,然後更新到Transfer自己的緩存中。當Redis中資料發生變更時會自動觸發Transfer更新緩存,以此來保證資料的實時性和Transfer本身的性能。

四、Judge改造

有很多監控名額上報上來後,業務方可能隻是想在出問題時看下監控圖,并不想配置監控政策。據統計,80%的監控名額都是屬于這種。之前Judge的政策是隻要資料上報就會在Judge中緩存一份,每個監控名額緩存最近上報的11個資料點。

其實,對于沒有配置監控政策的監控名額是沒有必要在Judge中緩存的。我們針對這種情況做了改進,Judge隻緩存配置監控政策的監控項資料,對于沒有配置監控政策的監控項直接忽略掉。

2. 報警狀态資訊持久化到本地,解決Judge重新開機報警重複發出的問題

之前的報警事件資訊都是緩存到Judge記憶體中的,包括事件的狀态、事件發送次數等。Judge在重新開機的時候這些資訊會丢掉,造成之前未恢複的報警重複發出。

現在改成Judge在關閉的時候會把記憶體中這部分資訊持久化到本地磁盤(一般很小,也就幾十K到幾M左右),啟動的時候再把這些資訊Load進Judge記憶體,這樣就不會造成未恢複報警重複發出了。

據了解,小米那邊是通過改造Alarm子產品實作的,通過比對報警次數來判斷目前是否發送報警,也是一種很好的解決方案。

3. 報警更新

我們現在監控模闆對應的Action裡面有第一報警接收組和第二報警接收組的概念。當某一事件觸發後預設發給第一報警接收組,如果該事件20分鐘内沒有解決,則會發給第二報警接收組,這就是報警更新的含義。

4. 報警ACK

ACK的功能跟Zabbix中的ACK是一緻的,當已經确認了解到事件情況,不想再收到報警時,就可以把它ACK掉。

ACK功能的大緻實作流程是:

  • Alarm發送報警時會根據Endpoint+Metric+Tags生成一個ACK連結,這個連結會作為報警内容的一部分。
  • 使用者收到報警後,如果需要ACK掉報警,可以點選這個連結,會調用Transfer服務的ACK接口。
  • Transfer收到ACK請求後,會根據傳輸過來的Endpoint+Metric+Tags資訊把這個請求轉發到對應的Judge執行個體上,調用Judge執行個體的ACK接口。
  • Judge收到ACK請求後,會根據EventID把緩存中對應的事件狀态置為已ACK,後續就不會再發送報警。

5. Tag反選

大家都知道配置監控政策時善用Tag,可以節省很多不必要的監控政策。比方說我想監控系統上所有磁盤的磁盤空間,其實隻需要配置一條監控政策,Metric填上df.bytes.free.percent就可以,不用指定Tags,它就會對所有的磁盤生效。

這個時候如果想過濾掉某一塊特殊的盤,比方說想把mount=/dev/shm這塊盤過濾掉,利用Tag反選的功能也隻需要配置一條監控政策就可以,Metric填上df.bytes.free.percent,Tags填上^mount=/dev/shm即可,Judge在判斷告警的時候會自動過濾掉這塊盤。

6. 多條件報警轉發到plus_judge

Judge在收到一個事件後,會首先判斷目前事件是否屬于多條件報警的事件,事件資訊是在配置監控政策的時候定義的。如果屬于多條件報警的事件,則直接轉發給多條件報警處理子產品plus_judge。關于plus_judge,後面會重點介紹。

五、Graph改造

1. 索引存儲改造

索引存儲這塊目前官方的存儲方式是MySQL,監控項數量上來後,很容易出現性能問題。我們這邊的存儲方式也是改動了很多次,現在是使用Redis+Tair實作的。

建議使用Redis Cluster,現在Redis Cluster也有第三方的Go client了。詳情請參考:https://github.com/chasex/redis-go-cluster。

官方我看也在緻力于索引存儲的改造,底層使用BoltDB存儲,具體的可參考小米來炜的Git倉庫: https://github.com/laiwei/falcon-index。

這塊我們有專門做過Redis、Tair、BoltDB的性能測試,發現這三個存儲在性能上差别不是很大。

2. 過期索引自動删除且重新上報後會自動重建

監控項索引資訊如果超過1個月時間沒有資料上報,則Graph會自動删除該索引,删除Tair中存儲的索引資訊時會同步删除indexcache中緩存的索引資訊。

索引删除後,如果對應資料又重新進行上報,則會重新建立對應的索引資訊。

預設Graph在剛啟動的6個小時内(時間可配置)定為初始啟動狀态,資料放到unindexcache隊列裡面,意味着會重新建立索引。

3. 解決查詢曆史資料時最新的資料點丢失的問題

改造之前:

  • 查詢12小時内的監控資料時,會先從RRD檔案取資料,再把取到的資料與緩存中的資料內建。內建原則是RRD與緩存中相同時間點的資料一律替換為緩存中的資料,是以查詢12小時内的資料是可以正常傳回的。
  • 查詢超過12小時内的資料時,會直接從RRD檔案擷取,不再與緩存中資料內建,是以在取超過12小時内的資料時,最新的資料上報點的資料一直是空的。

改造之後:

  • 查詢12小時内的資料,處理原則不變。
  • 查詢超過12小時内的資料時,先從RRD檔案擷取,再與緩存中資料內建。內建原則是RRD與緩存中相同時間點的資料,如果RRD資料為空,則替換為緩存中的資料,如果RRD資料不為空,則以RRD資料為準。

這裡有一個問題,超過12小時内的資料都是聚合後的資料,緩存中的資料都是原始值,相同時間點RRD中為空的資料替換為緩存中的資料,相當于聚合後的資料用原始資料替換掉了,是有一定誤差的,不過有勝于無。

六、Alarm改造

1. 報警合并

重寫了Alarm子產品的報警合并邏輯:

  • 所有報警都納入合并範疇
  • 按照相同Metric進行合并
  • 前3次直接發,後續每分鐘合并一次
  • 如果5分鐘内沒有報警,則下次重新計數

2. 報警發散

報警發散的作用是在主控端特定監控名額觸發後,不僅要發給配置的報警組,還要發給主控端上虛拟機對應的負責人。

現在需要發散的主控端特定監控名額有:

  • net.if.in.Mbps 網卡入流量
  • net.if.out.Mbps 網卡出流量
  • icmp.ping.alive 機器存活監控
  • cpu.steal CPU偷取

根據機器所屬的環境不同,發給對應的負責人:

  • prod環境:發給SRE負責人+RD負責人
  • staging環境:發給RD責人
  • test環境:發給測試負責人

3. 報警白名單

報警白名單是指當某一個指定的Metric發生大量告警時,可以迅速屏蔽掉這個Metric的告警,這個比較簡單,就不多說了。

4. 報警任務分布式消費

未恢複報警資訊之前是存儲在Alarm記憶體裡面,現在改為存儲到Redis中。這樣就可以啟動多個Alarm執行個體,同時從Redis報警隊列中取任務進行消費。Redis本身是單線程的,可以保證一個報警發送任務隻會被一個Alarm執行個體擷取到,sender子產品使用同樣邏輯處理,進而實作了報警任務的分布式消費處理。

5. 報警方式改造

現在報警方式和事件優先級解綁,優先級隻是表示故障的嚴重程度,具體報警發送方式可以根據個人喜好自行選擇。在美團點評内部,可以通過内部IM大象、郵件、短信和電話等方式發送報警。

現在支援的優先級有:

  • p0: 最高優先級,強制發送短信,大象和郵件可以自行選擇。
  • p1: 高優先級,強制發送短信,大象和郵件可以自行選擇。
  • p2: 普通優先級,強制發送大象,郵件可以自行選擇。
  • p3: 低優先級,隻發送郵件。
  • p9: 特殊優先級,強制使用電話+短信+大象+郵件進行發送。

6. 報警持久化和報警統計

報警持久化這塊剛開始使用的是InfluxDB,不過InfluxDB不友善統計,而且還有一些其它方面的坑,後來就改成直接存到MySQL中了。

我們每天會對報警資訊做一個統計,會按服務、人、機器和監控項的次元分别給出Top10。

還會給出最近7天的報警量變化趨勢,以及在每個BG内部分别按服務、機器、人的次元給出目前Top20的異常數和周同比。

7. 報警紅盤

報警紅盤的作用是統計一段時間内每個服務新觸發報警的數量,把Top10的服務展示到頁面上。報警數>=90顯示紅色,50~90之間顯示黃色,當有事故發生時基本可以從紅盤上觀察出來哪個服務出現了事故,以及事故的影響範圍。

8. 監控模闆支援發給負責人的選項

監控模闆對應的Action中添加一個發給負責人的選項,這樣Action中的報警組可以設定為空,在觸發報警的時候會自動把報警資訊發給相應的負責人。可以實作不同機器的報警發給不同的接收人這個功能。

9. 觸發base監控的時候自動發給相應負責人

為避免報警消息通知不到位,我們設定了一批基礎監控項,當基礎監控項觸發報警的時候,會自動發給相應的負責人。

基礎監控項有:

  • "net.if.in.Mbps",
  • "net.if.out.Mbps",
  • "cpu.idle",
  • "df.bytes.free.percent",
  • "df.inodes.free.percent",
  • "disk.io.util",
  • "icmp.ping.alive",
  • "icmp.ping.msec",
  • "load.1minPerCPU",
  • "mem.swapused.percent",
  • "cpu.steal",
  • "kernel.files.percent",
  • "kernel.coredump",
  • "df.mounts.ro",
  • "net.if.change",

七、Portal/Dashboard改造

1. 綁定服務樹

建立模闆,添加政策,配置報警接收人等操作都是在服務樹上完成。

2. 提供一系列接口,支援所有操作接口化,并對接口添權重限認證

我們支援通過調用API的方式,把監控功能內建到自己的管理平台上。

3. 記錄記錄檔

引入公司統一的日志進行中心,把記錄檔都記錄到上面,做到狀态可追蹤。

4. shift多選功能

在Dashboard檢視監控資料時支援按住shift多選功能。

5. 繪圖顔色調整

繪圖時線條顔色統一調成深色的。

6. 索引自維護

系統運作過程中會出現部分索引的丢失和曆史索引未及時清除等問題,我們在Dashboard上開放了一個入口,可以很友善地添加新的索引和删除過期的索引。

7. Dashboard重新整理功能

通過篩選Endpoint和Metric檢視監控圖表時,有時需要檢視最新的監控資訊,點選浏覽器重新整理按鈕在資料傳回之前頁面上會出現白闆。為了解決這個問題我們添加了一個重新整理按鈕,點選重新整理按鈕會自動顯示最近一小時内的監控資料,在最新的資料傳回之前,原有頁面不變。

8. screen中單圖重新整理功能

screen中圖表太多的話,有時候個别圖表沒有刷出來,為了看到這個圖表還要重新整理整個頁面,成本有點高。是以我們做了一個支援單個圖表重新整理的功能,隻需要重新擷取這單個圖表的資料即可。

9. 支援按環境應用監控模闆

現在支援把監控模闆應用到指定的環境上,比方說把一個模闆直接應用到某個業務層節點的prod環境上,這樣隻會對業務層節點或者業務層節點的子節點的prod環境生效,staging和test環境沒有影響。

八、新增子產品

1. Ping監控

使用Fping實作的Ping存話監控和延遲監控,每個機房有自己的Ping節點,不同節點之前互相Ping,實作跨機房Ping監控。

2. 字元串監控

字元串監控跟數值型監控共用一套監控配置,也就是Portal和HBS是統一的。當上報上來的資料是字元串類型,會交由專門的字元串處理子產品string_judge處理。

3. 同比環比監控

同比環比監控類似于nodata的處理方式,自行設定跟曆史某個時間點資料做對比。因為資料會自動聚合,是以與曆史上某個時間點做對比的話,是存在一定誤差的。

官方提供了diff和pdiff函數,如果是對比最近10個資料點的話,可以考慮使用這種方式。也可以考慮把需要做同比環比監控的監控名額存入到OpenTSDB中,做對比的時候直接從OpenTSDB擷取曆史資料。

4. 多條件監控

有些異常情況,可能單個名額出現問題并沒有什麼影響,想實作多個名額同時觸發的時候才發報警出來。因為Judge是分布式的,多個名額很可能會落到不同的Judge執行個體上,是以判斷起來會比較麻煩。後來我們做了一個新的子產品plus_judge,專門用來處理多條件告警情況。

實作方案是:

  • 組成多條件監控的多個政策,按照政策ID正序排序後,生成一個唯一序列号,這些政策在存儲的時候會一并存下額處的3個資訊,是否屬于多條件監控,序列号,組成這個多條件監控的政策個數。
  • Judge在收到有多條件告警辨別的政策觸發的告警事件時,直接轉發給多條件監控處理子產品plus_judge。
  • plus_judge會根據序列号和多條件個數,判斷是否多個條件都同時滿足,如果全都滿足,則才會發報警。

總結

Mt-Falcon現在在美團點評已經完全替換掉Zabbix監控,接入美團點評所有機器,資料上報QPS達到100W+,總的監控項個數超過兩個億。下一步工作重點會主要放在美團點評監控融合統一,配置頁面改造,報警自動處理,資料營運等方面。

我們也一直緻力于推動Open-Falcon社群的發展,上面所列部分Feature已Merge到官方版本,後面也會根據需求提相應PR過去。

作者簡介

大閃,美團點評SRE組監控團隊負責人。曾就職于高德、新浪,2015年加入原美團,一直負責監控體系建設。目前緻力于故障自動追蹤與定位、故障自動處理、資料營運等,持續提升監控系統穩定性、易用性和拓展性。

繼續閱讀