春秋戰國時期,有位神醫被尊為“醫祖”,他就是“扁鵲”。一次,魏文王問扁鵲說:“你們家兄弟三人,都精於醫術,到底哪一位最好呢?”扁鵲答:“長兄最好,中兄次之,我最差。”文王又問:“那么為什么你最出名呢?”扁鵲答:“長兄治病,是治病於病情發作之前,由於一般人不知道他事先能鏟除病因,所以他的名氣無法傳出去;中兄治病,是治病於病情初起時,一般人以為他只能治輕微的小病,所以他的名氣只及本鄉里;而我是治病於病情嚴重之時,一般人都看到我在經脈上穿針管放血,在皮膚上敷葯等大手術,所以以為我的醫術高明,名氣因此響遍全國。”
監控在企業應用系統中屬於不可或缺的基礎建設
,一個完善的監控體系可以幫助我們發現系統瓶頸、了解系統狀態,最重要的是發現系統故障。
一些小型企業系統,可能更多的利用雲產品自帶的系統監控來監控系統CPU、磁盤、內存等指標,對程序運行只能通過日志來監控,比如定期grep一下日志中的Exception,或者Catch住異常然后發一份郵件,或者利用JMX來監控(但這個需要一直有人盯着)。 這種方式便捷又原始,不過也是,小型系統如果為了監控去引入Cat、Prometheus、Skywalking這類組件,從成本上來說得不償失。
這種在不能引入第三方組件的情況下,可以考慮對系統原有的Log組件做一些封裝,以Slf4j為例,我們可以通過實現它的Filter來做日志攔截,如果有Error日志,就通過釘釘或者企業微信的WebHook機器人進行統治,將異常情況實時通知給業務開發者。 當然這個組件可以像上面這樣簡單實現,也可以做的很復雜,比如做Error日志通知的黑白名單,除了Error日志,我們還可以在Http的Filter上判斷接口響應時間,如果接口處理超過一定時間就進行告警,此外Dubbo的Filter也是同理,如果系統又配置中心這一概念,還可以玩的更靈活。 當然,為了防止Error日志請求釘釘的耗時影響業務,這部分邏輯可以異步去處理,我們使用的組件是通過時間輪去異步發送釘釘消息,並且對時間片中相同的日志進行了合並。
上面這種方式是比較簡單粗暴的,它可以解決大部分的問題,如果你的Log打的比較規范,在系統崩潰前就可以收到很多告警消息,最直觀的就是請求響應超時的告警突增,這些都預示着你的系統有“病”,但是這種簡單粗暴的監控沒法告訴你是什么病,這時候系統壓力已經瀕臨極限,就需要扁鵲來穿針放血,排查系統問題,最有效的辦法是直接重啟系統,但這會丟掉病人發病時第一時間的資料,堆棧信息。
當然,現實情況可能比較復雜,說不定發生故障時系統已經封閉,進行上下線重啟操作,或者權限管理比較嚴格,無法第一時間連上故障機器進行排查,只能去Review代碼或者排查日志,都不好說。
智者千慮,必有一失。愚者千慮,必有一得。
這句話出自《晏子春秋》,用在監控系統也再合適不過,就算設計的再精妙的監控系統可能都逃不過系統病情嚴重后扁鵲出手,線上故障是無法避免的。所以監控系統應該作用於我們開發的三個階段。
開發時
開發中我們需要一個充當扁鵲大哥的角色,幫助我們直接發現代碼問題,比較直接的方式就是組內的Code Review,嚴格代碼提交規范,再業務再老道的人也難防提交一個Bug。此外就是引入Sonar這類靜態代碼掃描工具來排除隱藏Bug,以及規范我們的代碼提交。
運行時
這時監控系統的關鍵,這部分需要依賴第三方組件。
比如做鏈路監控的Skywalking、Cat,Skywalking通過給我們的請求添加TraceId,來分析從用戶發起請求到結束經過了那些系統處理、耗時、緩存、數據庫訪問等等。此外點評開源的Cat,功能強大,可以收集接口的平均響應時間、99線、95線、最大最小響應時間、失敗率等信息,還有接口的RT圖,系統上下游調用分析,堆棧快照,告警等功能,無論是系統性能優化時分析瓶頸,還是排查問題,Cat都是得力幫手,不過Cat現在的社區不是很活躍,對一些新技術支持不是很完善。
除了調用鏈路的監控,還有我們機器性能指標、業務監控等需求,常用的方案是Prometheus(普羅米修斯),Prometheus支持用戶利用其API自己開發Node Exporter插件,去監控不同的中間件指標,Prometheus默認的Node Exporter主要用於監控機器性能,還有一些第三方開發的Mysql Exporter、RocketMQ Exporter可以用於監控Mysql節點、RocketMQ的IO、生產消費量,消息大小等指標。
Prometheus的指標主要有四類:Counter,Gauge,Histogram,Summary。
- Counter
連續增加不會減少的計數器,例如:網站訪問人數,生成請求次數、錯誤次數等指標。Counter類型的指標,只包含一個inc()的方法,就是用於計數器+1 - Gauge
一個可增可減的動態指標值,可以用來統計 如CPU,內存使用率,線程池數量等,包含兩個主要的方法inc()和dec(),用於增加和減少計數 - Histogram
指標生成的是直方圖數據,主要用來統計數據的分布情況,類似一段時間內http請求響應小於0.005秒、小於0.01秒、小於0.025秒的數據分布情況 - Summary
Summary 類型是在客戶端直接聚合生成的百分位數
同樣,我們在設計監控項時需要考慮到Google提出的四個黃金指標。
- [X] 延遲:服務請求所花費的時間,需要區分成功請求和失敗請求。例如,失敗請求可能會以非常低的延遲返回錯誤結果。
- [X] 流量:針對系統,例如,每秒HTTP請求數,或者數據庫系統的事務。
- [X] 錯誤:請求失敗的速率,要么是HTTP 500錯誤等顯式失敗,要么是返回錯誤內容或無效內容等隱式失敗,或者基於策略原因導致的失敗——例如,強制要求響應時間超過30ms的請求視為錯誤。
- [X] 飽和度:應用程序有多“滿”,或者受限的資源,如內存或IO。這還包括即將飽和的部分,例如正在快速填充的磁盤。
故障時
故障處理也應當屬於我們監控系統的一部分,在這部分,我們需要在排查到問題原因后,對故障期間的錯誤數據進行修復,這就需要我們自己通過業務邏輯去開發相應的工具箱以及建立完整的SOP體系了,當然,這不是一蹴而就的事,需要在平常問題修復排查時進行沉淀。
為了防止故障發生,一些復雜的業務邏輯上線前一定要做灰度開關、功能開關或者降級服務,不需要設計的多么精妙,一個簡單的if邏輯判斷即可,保證業務可以平穩運行后,日后刪掉這部分開關再上線。降級開關可以用在一些預估有大流量或者接口本身響應時長就高的情況,防止系統或者下游被大流量直接打垮。
最后,本文只是簡單提了一些系統指標監控、故障監控,此外還有性能監控,是我們進行性能分析、性能優化的關鍵,這部分監控需要深入到應用程序運行時類加載、方法耗時、系統API、網絡請求首包耗時、DNS解析耗時的層次。建立一個精細的監控平台,是一個需要長久時間發展演進的過程,不管是千慮一得,還是千慮一失,都是難以避免的,當然最終要的是在血的教訓中積累經驗,避免問題再次發生。