前言
監控系統是整個業務系統中至關重要的一環,它就像眼睛一樣,時刻監測機房、網絡、服務器、應用等運行情況,並且在出現問題時能夠及時做出相應處理。
美團點評剛開始使用的是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的詳細用法可參考:https://github.com/donnie4w/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的集成方法可以參考: https://github.com/ugorji/go/tree/master/codec#readme。
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改造
1. 內存優化
有很多監控指標上報上來后,業務方可能只是想在出問題時看下監控圖,並不想配置監控策略。據統計,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年加入原美團,一直負責監控體系建設。目前致力於故障自動追蹤與定位、故障自動處理、數據運營等,持續提升監控系統穩定性、易用性和拓展性。
不想錯過技術博客更新?想給文章評論、和作者互動?第一時間獲取技術沙龍信息?
請關注我們的官方微信公眾號“美團點評技術團隊”。現在就拿出手機,掃一掃: