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