摘要:為了讓大交通下的各業務線都能夠通過報警盡早發現問題解決問題,進而提升業務系統的服務質量,我們決定構建統一的監控報警系統。本文主要介紹馬蜂窩大交通業務監控報警系統的定位整體架構設計,以及我們在落地實踐過程中的一些踩坑經驗。
部門的業務線越來越多,任何一個線上運行的應用,都可能因為各種各樣的原因出現問題:比如業務層面,訂單量比上周減少了,流量突然下降了;技術層面的問題,系統出現 ERROR ,接口響應變慢了。拿大交通業務來說,一個明顯的特點是依賴很多供應商的服務,所以我們還需要關注調用供應商接口是否出現異常等等。
為了讓大交通下的各業務線都能夠通過報警盡早發現問題、解決問題,進而提升業務系統的服務質量,我們決定構建統一的監控報警系統。一方面在第一時間發現已經出現的系統異常,及時解決;另一方面盡早發現一些潛在的問題,比如某個系統目前來看沒有影響業務邏輯的正常運轉,但是一些操作耗時已經比較長等,這類問題如果不及時處理,將來就很可能影響業務的發展。
本文主要介紹馬蜂窩大交通業務監控報警系統的定位、整體架構設計,以及我們在落地實踐過程中的一些踩坑經驗。
架構設計與實現我們希望監控報警系統主要具備以下三個能力:
1. 常用組件自動報警:對于各業務系統常用的框架組件(如 RPC ,HTTP 等)創建默認報警規則,來方便框架層面的統一監控。
2. 業務自定義報警:業務指標由業務開發自定義埋點字段,來記錄每個業務和系統模塊的特殊運行狀況。
3. 快速定位問題:發現問題并不是目的,解決才是關鍵。我們希望在完成報警消息發送后,可以讓開發者一目了然地發現問題出現在什么地方,從而快速解決。
在這樣的前提下,報警中心的整體架構圖和關鍵流程如下圖所示:
縱向來看,Kafka 左側是報警中心,右側是業務系統。
報警中心的架構共分為三層,最上層是 WEB 后臺管理頁面,主要完成報警規則的維護和報警記錄的查詢;中間層是報警中心的核心;最下面一層是數據層。業務系統通過一個叫做 mes-client-starter 的 jar 包完成報警中心的接入。
我們可以將報警中心的工作劃分為五個模塊:
1. 數據收集我們采用指標采集上報的方式來發現系統問題,就是將系統運行過程中我們關注的一些指標進行記錄和上傳。上傳的方式可以是日志、 UDP 等等。
首先數據收集模塊我們沒有重復造輪子,可是直接基于 MES (馬蜂窩內部的大數據分析工具)來實現,主要考慮下面幾個方面的原因:一來數據分析和報警在數據來源上是相似的;二來可以節省很多開發成本;同時也方便報警的接入。
那具體應該采集哪些指標呢?以大交通業務場景下用戶的一次下單請求為例,整個鏈路可能包括 HTTP 請求、Dubbo 調用、SQL 操作,中間可能還包括校驗、轉換、賦值等環節。一整套調用下來,會涉及到很多類和方法,我們不可能對每個類、每個方法調用都做采集,既耗時也沒有意義。
為了以最小的成本來盡可能多地發現問題,我們選取了一些系統常用的框架組件自動打點,比如 HTTP、SQL、我們使用的 RPC 框架 Dubbo ,實現框架層面的統一監控。
而對于業務來說,每個業務系統關注的指標都不一樣。對于不同業務開發人員需要關注的不同指標,比如支付成功訂單數量等,開發人員可以通過系統提供的 API 進行手動埋點,自己定義不同業務和系統模塊需要關注的指標。
2. 數據存儲對于采集上來的動態指標數據,我們選擇使用 Elasticsearch 來存儲,主要基于兩點原因:
一是動態字段存儲。每個業務系統關注的指標可能都不一樣,每個中間件的關注點也不同,所以埋哪些字段、每個字段的類型都無法預知,這就需要一個可以動態添加字段的數據庫來存儲埋點。Elasticsearch 不需要預先定義字段和類型,埋點數據插入的時候可以自動添加。
二是能夠經得起海量數據的考驗。每個用戶請求進過每個監控組件都會產生多條埋點,這個數據量是非常龐大的。Elasticsearch 可以支持大數據量的存儲,具有良好的水平擴展性。
此外,Elasticsearch 還支持聚合計算,方便快速執行 count , sum , avg 等任務。
?3. 報警規則有了埋點數據,下一步就需要定義一套報警規則,把我們關注的問題量化為具體的數據來進行檢查,驗證是否超出了預設的閾值。這是整個報警中心最復雜的問題,也最為核心。
之前的整體架構圖中,最核心的部分就是「規則執行引擎」,它通過執行定時任務來驅動系統的運行。首先,執行引擎會去查詢所有生效的規則,然后根據規則的描述到 Elasticsearch 中進行過濾和聚合計算,最后將上一步聚合計算得結果跟規則中預先設定的閾值做比較,如果滿足條件則發送報警消息。
這個過程涉及到了幾個關鍵的技術點:
1). 定時任務
為了保證系統的可用性,避免由于單點故障導致整個監控報警系統失效,我們以「分鐘」為周期,設置每一分鐘執行一次報警規則。這里用的是 Elastic Job 來進行分布式任務調度,方便操控任務的啟動和停止。
2). 「三段式」報警規則
我們將報警規則的實現定義為「過濾、聚合、比較」這三個階段。舉例來說,假設這是一個服務 A 的 ERROR 埋點日志:
app_name=B???is_error=false??warn_msg=aa???datetime=2019-04-01?11:12:00 app_name=A???is_error=false????????????????datetime=2019-04-02?12:12:00 app_name=A???is_error=true???error_msg=bb??datetime=2019-04-02?15:12:00 app_name=A???is_error=true???error_msg=bb??datetime=2019-04-02?16:12:09
報警規則定義如下:
過濾:通過若干個條件限制來圈定一個數據集。對于上面的問題,過濾條件可能是:app_name=A , is_error=true , datetime between "2019-14-02 16:12:00" and "2019-14-02 16:13:00".
聚合:通過 count,avg,sum,max 等預先定義的聚合類型對上一步的數據集進行計算,得到一個唯一的數值。對于上面的問題,我們選擇 count 來計算出現 ERROR 的次數。
比較:把上一步得到的結果與設定的閾值比較。
對于一些復雜條件的報警,比如我們上邊提到的失敗率和流量波動,應該如何實現呢?
假設有這樣一個問題:如果調用的 A 服務失敗率超過 80%,并且總請求量大于 100,發送報警通知。
我們知道,失敗率其實就是失敗的數量除以總數量,而失敗的數量和總數量可以通過前面提到的「過濾+聚合」的方式得到,那么其實這個問題就可以通過如下的公式描述出來:
failedCount/totalCount>0.8&&totalCount>100
然后我們使用表達式引擎 fast-el 對上面的表達式進行計算,得到的結果與設定的閾值比較即可。
3) 自動創建默認報警規則
對于常用的 Dubbo, HTTP 等,由于涉及的類和方法比較多,開發人員可以通過后臺管理界面維護報警規則,報警規則會存儲到 MySQL 數據庫中,同時在 Redis 中緩存。
以 Dubbo 為例,首先通過 Dubbo 的 ApplicationModel 獲取所有的 provider 和 consumer,將這些類和方法的信息與規則模板結合(規則模板可以理解為剔除掉具體類和方法信息的規則),創建出針對某個類下某個方法的規則。
比如:A 服務對外提供的 dubbo 接口/ order / getOrderById 每分鐘平均響應時間超過 1 秒則報警;B 服務調用的 dubbo 接口/ train / grabTicket /每分鐘范圍 false 狀態個數超過 10 個則報警等等。
4. 報警行為目前在報警規則觸發后主要采用兩種方式來發生報警行為:
郵件報警:通過對每一類報警制定不同的負責人,使相關人員第一時間獲悉系統異常。
微信報警:作為郵件報警的補充。
之后我們會持續完善報警行為的策略,比如針對不同等級的問題采用不同的報警方式,使開發人員既可以迅速發現報警的問題,又不過多牽扯在新功能研發上的精力。
?5. 輔助定位為了能夠快速幫助開發人員定位具問題,我們設計了命中抽樣的功能:
首先,我把命中規則的 tracer_id 提取出來,提供一個鏈接可以直接跳轉到 kibana 查看相關日志,實現鏈路的還原。
其次,開發人員也可以自己設置他要關注的字段,然后我會把這個字段對應的值也抽取出來,問題出在哪里就可以一目了然地看到。
技術實現上,定義一個命中抽樣的字段,這個字段里面允許用戶輸入一個或者多個 dollar 大括號。比如我們可能關注某個供應商的接口運行情況,則命中抽樣的字段可能為下圖中上半部分。在需要發送報警消息的時候,提取出里面的字段,到 ES 中查詢對應的值,用 freemarker 來完成替換,最終發送給開發人員的消息是如下所示,開發人員可以快速知道系統哪里出了問題。
踩坑經驗和演進方向大交通業務監控報警系統的搭建是一個從 0 到 1 的過程,在整過開發過程中,我們遇到了很多問題,比如:內存瞬間被打滿、ES 越來越慢、頻繁 Full GC ,下面具體講一下針對以上幾點我們的優化經驗。
踩過的坑1. 內存瞬間被打滿
任何一個系統,都有它能承受的極限,所以都需要這么一座大壩,在洪水來的時候能夠攔截下來。
報警中心也一樣,報警中心對外面臨最大的瓶頸點在接收 Kafka 中傳過來的 MES 埋點日志。上線初期出現過一次由于業務系統異常導致瞬間大量埋點日志打到報警中心,導致系統內存打滿的問題。
解決辦法是評估每個節點的最大承受能力,做好系統保護。針對這個問題,我們采取的是限流的方式,由于 Kafka 消費消息使用的是拉取的模式,所以只需要控制好拉取的速率即可,比如使用 Guava 的 RateLimiter :
messageHandler?=?(message)?->?{ ??RateLimiter?messageRateLimiter?=?RateLimiter.create(20000); ??final?double?acquireTime?=?messageRateLimiter.acquire(); ??/** ???save.. ??*/ }
2. ES 越來越慢
由于 MES 日志量比較大,也有冷熱之分,為了在保證性能的同時方便數據遷移,我們按照應用 + 月份的粒度創建 ES 索引,如下所示:
3. 頻繁 Full GC
我們使用 Logback 作為日志框架,為了能夠搜集到 ERROR 和 WARN 日志,自定義了一個 Appender。如果想搜集 Spring 容器啟動之前(此時? TalarmLogbackAppender 還未初始化)的日志, Logback 的一個擴展 jar 包中的 DelegatingLogbackAppender 提供了一種緩存的方式,內存泄漏就出在這個緩存的地方。
正常情況系統啟動起來之后,ApplicationContextHolder 中的 Spring 上下文不為空,會自動從緩存里面把日志取出來。但是如果因為種種原因沒有初始化這個類 ApplicationContextHolder,日志會在緩存中越積越多,最終導致頻繁的 Full GC。
解決辦法:
1. 保證 ApplicationContextHolder 的初始化
2. DelegatingLogbackAppender 有三種模式:OFF SOFT ON ,如果需要打開,盡量使用 SOFT模式,這時候緩存被存儲在一個由 SoftReference 包裝的列表中,在系統內存不足的時候,可以被垃圾回收器回收掉。
近期規劃目前這個系統還有一些不完善的地方,也是未來的一些規劃:
更易用:提供更多的使用幫助提示,幫助開發人員快速熟悉系統。
更多報警維度:目前支持 HTTP,SQL, Dubbo 組件的自動報警,后續會陸續支持 MQ,Redis 定時任務等等。
圖形化展示:將埋點數據通過圖形的方式展示出來,可以更直觀地展示出系統的運行情況,同時也有助于開發人員對于系統閾值的設置。
小結?總結起來,大交通業務監控報警系統架構有以下幾個特點:
?支持靈活的報警規則配置,豐富的篩選邏輯
自動添加常用組件的報警,Dubbo、HTTP 自動接入報警
接入簡單,接入 MES 的系統都可以快速接入使用
線上生產運維主要做 3 件事:發現問題、定位問題、解決問題。發現問題,就是在系統出現異常的時候盡快通知系統負責人。定位問題和解決問題,就是能夠為開發人員提供快速修復系統的必要信息,越精確越好。
報警系統的定位應該是線上問題解決鏈條中的第一步和入口手段。將其通過核心線索數據與數據回溯系統( tracer 鏈路等),部署發布系統等進行有機的串聯,可以極大提升線上問題解決的效率,更好地為生產保駕護航。
不管做什么,我們最終的目標只有一個,就是提高服務的質量。
本文作者:宋考俊,馬蜂窩大交通平臺高級研發工程師。
(題圖來源:網絡)
關注馬蜂窩技術,找到更多你想要的內容
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/104299.html
摘要:為了幫助用戶更好地完成消費決策閉環,馬蜂窩上線了大交通業務。現在,用戶在馬蜂窩也可以完成購買機票火車票等操作。第二階段架構轉變及服務化初探從年開始,整個大交通業務開始從架構向服務化演變。 交通方式是用戶旅行前要考慮的核心要素之一。為了幫助用戶更好地完成消費決策閉環,馬蜂窩上線了大交通業務。現在,用戶在馬蜂窩也可以完成購買機票、火車票等操作。 與大多數業務系統相同,我們一樣經歷著從無到有...
摘要:為了幫助用戶更好地完成消費決策閉環,馬蜂窩上線了大交通業務。現在,用戶在馬蜂窩也可以完成購買機票火車票等操作。第二階段架構轉變及服務化初探從年開始,整個大交通業務開始從架構向服務化演變。 交通方式是用戶旅行前要考慮的核心要素之一。為了幫助用戶更好地完成消費決策閉環,馬蜂窩上線了大交通業務。現在,用戶在馬蜂窩也可以完成購買機票、火車票等操作。 與大多數業務系統相同,我們一樣經歷著從無到有...
閱讀 3011·2021-10-12 10:12
閱讀 3065·2021-09-22 16:04
閱讀 3297·2019-08-30 15:54
閱讀 2609·2019-08-29 16:59
閱讀 2920·2019-08-29 16:08
閱讀 874·2019-08-29 11:20
閱讀 3500·2019-08-28 18:08
閱讀 656·2019-08-26 13:43