引言
在基于Java的物聯(lián)網(wǎng)分布式微服務(wù)架構(gòu)體系中,海量異構(gòu)設(shè)備的實(shí)時(shí)數(shù)據(jù)接收及處理對(duì)微服務(wù)的協(xié)同處理能力提出了嚴(yán)峻挑戰(zhàn)。特別是在高并發(fā)場(chǎng)景下,系統(tǒng)常面臨消息隊(duì)列堵塞、服務(wù)響應(yīng)延遲、程序數(shù)據(jù)堆積導(dǎo)致內(nèi)存溢出等運(yùn)行故障,這些問(wèn)題的隱蔽性和突發(fā)性嚴(yán)重威脅著平臺(tái)的服務(wù)質(zhì)量。因此如何高效、及時(shí)地發(fā)現(xiàn)并處置系統(tǒng)的各種故障,是確保系統(tǒng)穩(wěn)定運(yùn)行的核心需求。本文所提出的非侵入式高性能微服務(wù)監(jiān)控框架的核心機(jī)理,是通過(guò)Java動(dòng)態(tài)字節(jié)碼生成與植入等技術(shù),對(duì)SLF4J日志適配層與Kafka消息中間件實(shí)施運(yùn)行時(shí)字節(jié)碼植入,實(shí)現(xiàn)多維度的異常感知機(jī)制,為平臺(tái)的平穩(wěn)運(yùn)行提供了堅(jiān)實(shí)保障,所以本文的研究成果具有較強(qiáng)的實(shí)踐價(jià)值。
1.研究背景與目標(biāo)
1.1研究背景
目前,常見(jiàn)的故障監(jiān)控方法均存在各種缺陷。
(1)基于代碼埋點(diǎn)的侵入式監(jiān)測(cè)。在各微服務(wù)內(nèi)部大量埋點(diǎn)以捕獲異常并發(fā)出通知。該方法須深度耦合業(yè)務(wù)邏輯,不僅工作量巨大,還造成代碼冗余,且存在遺漏風(fēng)險(xiǎn)。
(2)利用系統(tǒng)監(jiān)控工具對(duì)JVM的內(nèi)存、CPU等資源使用情況進(jìn)行監(jiān)控(zabbix、prometheus等),并通過(guò)配置告警閾值來(lái)發(fā)出通知[]。該方法依賴(lài)于值配置,然而由于JVM內(nèi)存指標(biāo)在垃圾回收機(jī)制下的動(dòng)態(tài)波動(dòng)特性,其閾值難以準(zhǔn)確配置。例如,有時(shí)候內(nèi)存占用即便達(dá)到了 99% ,程序也沒(méi)有真正發(fā)生內(nèi)存溢出,內(nèi)存可以通過(guò)垃圾回收機(jī)制自動(dòng)回收[2;當(dāng)系統(tǒng)并發(fā)量增加時(shí),CPU占用增高也是正?,F(xiàn)象,因此該方法準(zhǔn)確性欠佳,容易誤報(bào),而且該方法能監(jiān)控的指標(biāo)也僅包括CPU、內(nèi)存等,難以擴(kuò)展。
(3)借助日志分析框架(如ELK等)對(duì)分布式系統(tǒng)產(chǎn)生的海量日志進(jìn)行收集與分析,用以發(fā)現(xiàn)系統(tǒng)異常[3]。盡管該方法具備跨節(jié)點(diǎn)故障追蹤能力,但CPU、內(nèi)存、存儲(chǔ)等資源消耗大,日志實(shí)時(shí)處理須消耗 22%~35% 的CPU資源,且索引存儲(chǔ)需求隨日志量呈線(xiàn)性增長(zhǎng),導(dǎo)致硬件成本激增,顯著提高系統(tǒng)運(yùn)行成本[4。該方法對(duì)日志內(nèi)容的分析和異常識(shí)別依賴(lài)人工定義的正則規(guī)則庫(kù),這些規(guī)則定義也較為煩瑣復(fù)雜,而且當(dāng)日志格式發(fā)生變化時(shí),須重新開(kāi)發(fā)解析規(guī)則并適配,容易遺漏和出錯(cuò),也會(huì)額外產(chǎn)生更多的維護(hù)成本。
(4)使用基于全鏈路追蹤的透明化監(jiān)控體系(如SkyWalking等)[5]。該方法采用JavaAgent技術(shù)通過(guò)JVMTI接口在類(lèi)加載階段動(dòng)態(tài)注入監(jiān)控探針,從而實(shí)現(xiàn)非侵入式的調(diào)用鏈追蹤,但是依然存在存儲(chǔ)效率及性能損耗等技術(shù)約束。全鏈路追蹤需要持久化Span元數(shù)據(jù)(包括TraceID、RPC上下文、耗時(shí)標(biāo)簽等),加上整個(gè)接口調(diào)用的全流程均要監(jiān)控,導(dǎo)致存儲(chǔ)成本暴增。動(dòng)態(tài)植入的監(jiān)控指令(如方法執(zhí)行時(shí)間戳采集)使關(guān)鍵路徑的字節(jié)碼膨脹率達(dá) 15% ~22% ,引發(fā)性能衰減,在高吞吐場(chǎng)景下將引發(fā)系統(tǒng)吞吐量下降 10% 以上。
總體而言,這些方法存在資源消耗較大、維護(hù)成本高、可靠性不足、實(shí)現(xiàn)復(fù)雜度高的缺點(diǎn)。同時(shí),這些方法僅能做到告警發(fā)現(xiàn)與通知,缺少告警自動(dòng)處置的功能,如果僅依靠人工處置,故障修復(fù)的時(shí)間將大大增加,尤其是在晚上。在高并發(fā)物聯(lián)網(wǎng)平臺(tái)系統(tǒng)中,如果故障一直無(wú)法修復(fù),還將導(dǎo)致故障擴(kuò)散失控、數(shù)據(jù)大量丟失等更嚴(yán)重的惡性循環(huán)。
1.2研究目標(biāo)
本文針對(duì)現(xiàn)有技術(shù)痛點(diǎn),設(shè)計(jì)并實(shí)
P-流水-高性能微服務(wù)監(jiān)控框架的設(shè)計(jì)與實(shí)現(xiàn)
現(xiàn)了一種面向Java分布式微服務(wù)架構(gòu)的異常監(jiān)控及自動(dòng)處置框架,構(gòu)建“異常感知發(fā)現(xiàn)-告警通知-自動(dòng)處置決策-處置結(jié)果通知”的全流程自動(dòng)化閉環(huán)管理。需要有如下創(chuàng)新性目標(biāo)。
1.2.1非侵入式監(jiān)控體系
非侵入式監(jiān)控體系下,微服務(wù)程序無(wú)須修改即可快速增加指定的監(jiān)控能力,該特性十分有利于對(duì)已有的大量微服務(wù)進(jìn)行快速更新升級(jí)并附加監(jiān)控能力。
1.2.2輕量化高性能架構(gòu)
輕量化高性能架構(gòu)整體性能高,且對(duì)CPU、內(nèi)存、存儲(chǔ)等系統(tǒng)資源消耗低,不對(duì)微服務(wù)業(yè)務(wù)的處理造成影響。
1.2.3可擴(kuò)展監(jiān)控生態(tài)
可擴(kuò)展監(jiān)控生態(tài)下,擴(kuò)展功能強(qiáng),不僅可以添加默認(rèn)的監(jiān)控指標(biāo),同時(shí)還提供擴(kuò)展接口,實(shí)現(xiàn)微服務(wù)業(yè)務(wù)自定義指標(biāo)的監(jiān)控及自動(dòng)處置。
1.2.4支持自動(dòng)處置且穩(wěn)定可靠
異常檢測(cè)發(fā)現(xiàn)與異常告警通知處置分別在不同的進(jìn)程中進(jìn)行處理,既避免了對(duì)微服務(wù)進(jìn)程的干擾,又保障了告警處置程序的穩(wěn)定運(yùn)行,同時(shí)還可以執(zhí)行重啟微服務(wù)這種自動(dòng)處置的命令。
監(jiān)控框架自身也帶監(jiān)控,避免監(jiān)控框架自身出現(xiàn)故障卻沒(méi)有告警通知。
2.非侵入式高性能微服務(wù)監(jiān)控框架的總體設(shè)計(jì)
2.1監(jiān)控框架運(yùn)行流程設(shè)計(jì)
本文研究的監(jiān)控框架的核心包含兩個(gè)部分程序,如圖1所示。
2.1.1微服務(wù)啟動(dòng)器
當(dāng)前微服務(wù)架構(gòu)中,日志系統(tǒng)作為關(guān)鍵基礎(chǔ)設(shè)施承載著異常信息記錄功能,其中slf4j因其良好的抽象特性和多日志實(shí)現(xiàn)兼容性,已成為絕大多數(shù)的Java項(xiàng)目的統(tǒng)一日志接口標(biāo)準(zhǔn)。大多數(shù)的開(kāi)發(fā)規(guī)范都會(huì)明確規(guī)定必須使用s1f4j打印日志。本文提出的監(jiān)控框架核心就基于sIf4j日志框架,包括以下內(nèi)容。
(1)采用字節(jié)碼增強(qiáng)技術(shù)在slf4j的log打印接口進(jìn)行動(dòng)態(tài)字節(jié)碼植入,實(shí)現(xiàn)對(duì)所有異常的捕獲和分析。動(dòng)態(tài)字節(jié)碼植入是Java核心的運(yùn)行時(shí)編程技術(shù)。傳統(tǒng)Java代碼須經(jīng)過(guò)編譯生成.class字節(jié)碼文件,而動(dòng)態(tài)技術(shù)突破了這一限制,允許程序在運(yùn)行時(shí)動(dòng)態(tài)生成新的類(lèi)或修改已有類(lèi)的字節(jié)碼。這種能力在框架開(kāi)發(fā)、性能監(jiān)控、熱修復(fù)等領(lǐng)域具有重要價(jià)值。
具體做法為:使用javassist在org.slf4j.Marker的“trace”“debug”“info”“warn”“error”方法中插入異常判斷代碼。例如,當(dāng)判斷異常類(lèi)型為OutOfMemoryError時(shí),則認(rèn)為系統(tǒng)發(fā)生了內(nèi)存溢出異常。該方案具有監(jiān)控?zé)o侵入性的優(yōu)勢(shì),無(wú)須修改業(yè)務(wù)代碼即可實(shí)現(xiàn)全量異常捕獲,有效規(guī)避人為遺漏風(fēng)險(xiǎn)。
(2)在Java虛擬機(jī)規(guī)范中,類(lèi)加載器(ClassLoader)采用雙親委派模型實(shí)現(xiàn)類(lèi)資源的層級(jí)加載控制[,該機(jī)制導(dǎo)致目標(biāo)類(lèi)一旦完成初始化即形成穩(wěn)定的方法區(qū)結(jié)構(gòu),常規(guī)技術(shù)手段難以對(duì)其進(jìn)行二次修改。因此,如果要在slf4j的log接口進(jìn)行插入動(dòng)態(tài)字節(jié)碼生成的觸發(fā)器程序,就必須要在slf4j的class加載之前完成。因此,框架設(shè)計(jì)一個(gè)利用反射啟動(dòng)微服務(wù),通過(guò)開(kāi)發(fā)獨(dú)立的自定義類(lèi)加載器(CustomClassLoader),用于在微服務(wù)程序啟動(dòng)之前將字節(jié)碼修改好,然后再通過(guò)java的反射機(jī)制[8]并使用自定義類(lèi)加載器,將真正的微服務(wù)啟動(dòng)程序運(yùn)行起來(lái)。
下,上述這種告警模式易引發(fā)“告警風(fēng)暴”問(wèn)題,主要表現(xiàn)為瞬時(shí)爆發(fā)大量的告警,如果不進(jìn)行優(yōu)化處理,將導(dǎo)致告警通知和處置系統(tǒng)崩潰。因此,本框架研究了一種基于時(shí)間窗口的告警聚合算法,出現(xiàn)異常觸發(fā)執(zhí)行織入代碼,其核心設(shè)計(jì)為依據(jù)時(shí)間窗口將相同告警類(lèi)型的告警進(jìn)行合并,并且時(shí)間窗口為階梯式擴(kuò)展的非均勻時(shí)間窗口策略(3、15、30、60、120、240分鐘)。
(4)合并后的告警詳情(包括告警時(shí)間、告警類(lèi)型、告警次數(shù)、告警詳情等)通過(guò)寫(xiě)文件的方式通知給監(jiān)控處置程序,即指定異常時(shí)將異常信息寫(xiě)人指定系統(tǒng)文件。例如:當(dāng)系統(tǒng)發(fā)生OutOfMemoryError異常時(shí),將向指定的文件中寫(xiě)人:{\"serviceName\":\"iot-convergence\",\"timeStr\":\"2025-04-2316:48:38\",\"timeLong\":\"1745398118836\",\"uuid\":\"135614ee-766c-4175-ac53-504705889781\",\"OutOfMemoryError\":\"4-Java heap space\"}。
(3)在大型物聯(lián)網(wǎng)平臺(tái)高并發(fā)異常場(chǎng)景
2.1.2獨(dú)立監(jiān)控處置程序
框架遵循“監(jiān)控與處置解耦”的原則將處置程序設(shè)計(jì)作為獨(dú)立程序運(yùn)行,通過(guò)讀取指定系統(tǒng)文件的異常信息,然后解析異常,并發(fā)送通知,判斷是否重啟服務(wù)(使用systemctl命令)。將監(jiān)控處置程序設(shè)計(jì)為獨(dú)立進(jìn)程,可以簡(jiǎn)化微服務(wù)啟動(dòng)器,避免對(duì)微服務(wù)的java進(jìn)程產(chǎn)生干擾,也可避免微服務(wù)啟動(dòng)器頻繁更新,保障微服務(wù)集群的穩(wěn)定性;當(dāng)發(fā)生一些嚴(yán)重異常的時(shí)候,如OutOfMemoryError,微服務(wù)的自身java進(jìn)程已經(jīng)無(wú)法正常運(yùn)行了,也就無(wú)法保障能進(jìn)行告警處置,使用外部獨(dú)立處置程序就可以避免這個(gè)問(wèn)題,而且還能執(zhí)行重啟微服務(wù)命令。
2.2監(jiān)控指標(biāo)具體設(shè)計(jì)
在上述框架的基礎(chǔ)上,系統(tǒng)默認(rèn)實(shí)現(xiàn)了一些具體的監(jiān)控指標(biāo)。
(1)內(nèi)存溢出OutOfMemoryError。直接監(jiān)控異常類(lèi)型為OutOfMemoryError的異常。在監(jiān)控到該異常時(shí),監(jiān)控處置程序還會(huì)嘗試執(zhí)行jmap-histo命令,記錄Java對(duì)象堆中每個(gè)類(lèi)的類(lèi)名、實(shí)例數(shù)目和內(nèi)存占用[],用于后續(xù)排查異常原因。
(2)消息隊(duì)列kafka異常。通過(guò)給org.apache.kafka.clients.NetworkClient的processDisconnection方法、org.apache.kafka.clients.FetchSessionHandler的handleResponse方法插入觸發(fā)器,從而監(jiān)控kafka客戶(hù)端的程序異常。
(3)微服務(wù)啟動(dòng)失敗。當(dāng)通過(guò)反射調(diào)用來(lái)啟動(dòng)微服務(wù)發(fā)生異常的時(shí)候觸發(fā)。
(4)程序自定義異常Slf4jMonitorError。微服務(wù)直接使用s1f4j打印類(lèi)名為Slf4jMonitorError(包名不限)的異常,即可觸發(fā)自定義告警,Slf4jMonitorError實(shí)現(xiàn)邏輯僅包括兩點(diǎn),即Slf4jMonitorError繼承java.lang.Error,errorMessage的格式為[type=0][msg=0][autoRestart=0][notice=0]。其中,type表示告警類(lèi)型;msg描述告警詳情;autoRestart為true時(shí),框架監(jiān)控到該異常,會(huì)自動(dòng)重啟服務(wù);notice為true時(shí),表示是通知并非告警,消息將會(huì)通過(guò)通知通道發(fā)送,不使用告警通道。
(5)獨(dú)立監(jiān)控處置程序自身異常。正式環(huán)境通常部署在一個(gè)集群服務(wù)器上,每臺(tái)服務(wù)器都會(huì)部署獨(dú)立監(jiān)控處置程序,監(jiān)控框架設(shè)計(jì)一個(gè)定時(shí)心跳驗(yàn)證機(jī)制,當(dāng)心跳驗(yàn)證異常時(shí)發(fā)送告警,即可及時(shí)發(fā)現(xiàn)監(jiān)控處置程序異?;蛘叻?wù)器異常停機(jī)。
(6)獨(dú)立處置程序自身實(shí)現(xiàn)一些其他的異常監(jiān)控。獨(dú)立處置程序作為一個(gè)獨(dú)立運(yùn)行的程序,還可以實(shí)現(xiàn)一些其他的監(jiān)控,如硬盤(pán)空間滿(mǎn)、Cassandra數(shù)據(jù)庫(kù)集群節(jié)點(diǎn)失效等。
3.監(jiān)控框架的應(yīng)用實(shí)踐
在福信富通公司北斗物聯(lián)中樞云平臺(tái)實(shí)際應(yīng)用該框架,因其對(duì)微服務(wù)程序的無(wú)侵入的特性,單個(gè)微服務(wù)適配和測(cè)試的平均耗時(shí)僅1小時(shí);框架引入后無(wú)須新增服務(wù)器配置,且服務(wù)CPU和內(nèi)存消耗與之前相比幾乎沒(méi)有增加;同時(shí),將OOM異常、kakfa隊(duì)列堆積等嚴(yán)重異常的發(fā)現(xiàn)和處置時(shí)間,從數(shù)個(gè)小時(shí)縮短到5分鐘內(nèi);其他的如硬盤(pán)空間滿(mǎn)、Cassandra節(jié)點(diǎn)故障、框架自身監(jiān)控,以及自定義的數(shù)據(jù)處理失敗率等告警的及時(shí)通知,也避免了多次系統(tǒng)故障,系統(tǒng)可用性從 99.9% 提升至 99.99% 。
結(jié)語(yǔ)
本文提出的非侵入式高性能微服務(wù)監(jiān)控框架的設(shè)計(jì)與實(shí)現(xiàn),在易用性、故障自愈、資源效率、運(yùn)維成本等多個(gè)方面均實(shí)現(xiàn)突破性改進(jìn)。應(yīng)用實(shí)踐表明,其可使微服務(wù)集群的綜合穩(wěn)定性提升1-2個(gè)數(shù)量級(jí),為整體系統(tǒng)的可靠性及穩(wěn)定性提供底層技術(shù)支撐。
盡管本文提出的非侵人式高性能微服務(wù)監(jiān)控框架在當(dāng)前應(yīng)用中取得了顯著成效,但仍存在進(jìn)一步優(yōu)化與拓展的空間。未來(lái)的研究方向?qū)⒕劢褂谝韵聝蓚€(gè)方面。一是智能化監(jiān)控與預(yù)測(cè)。通過(guò)人工智能和機(jī)器學(xué)習(xí)技術(shù)分析歷史監(jiān)控?cái)?shù)據(jù),訓(xùn)練預(yù)測(cè)模型,提前識(shí)別潛在故障風(fēng)險(xiǎn),從而進(jìn)一步提升系統(tǒng)的可靠性。二是跨平臺(tái)兼容性增強(qiáng)。當(dāng)前框架主要應(yīng)用于基于Java的微服務(wù)架構(gòu)。未來(lái)將擴(kuò)展框架的兼容性,使其能夠支持多種編程語(yǔ)言和運(yùn)行環(huán)境,如Python、Go等,以滿(mǎn)足更廣泛的物聯(lián)網(wǎng)應(yīng)用場(chǎng)景。
通過(guò)以上研究方向的持續(xù)探索與實(shí)踐,非侵入式高性能微服務(wù)監(jiān)控框架將不斷完善,為物聯(lián)網(wǎng)平臺(tái)的穩(wěn)定運(yùn)行提供更強(qiáng)大的支持。
參考文獻(xiàn):
[1]邵建輝.基于Zabbix的內(nèi)網(wǎng)編輯系統(tǒng)監(jiān)控應(yīng)用研究[J].中國(guó)傳媒科技,2018(7):58-60.
[2]靳喬喬,王靜一,郭怡冰,等.淺析Java與 C++ 的區(qū)別[J].數(shù)碼世界,2018(10):65.
[3]姜明銘.基于ELK棧的網(wǎng)絡(luò)運(yùn)維日志分析系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)[J.信息與電腦,2024,36(23):46-48.
[4]鮮征征,葉嘉祥.一種改進(jìn)的ELK日志采集與分析系統(tǒng)[J].軟件導(dǎo)刊,2019,18(8):105-110.
[5]吳晟.ApacheSkyWalking,開(kāi)源監(jiān)控生態(tài)[].軟件和集成電路,2021(6):62.
[6]遲慧智,孔德智.Java方法增強(qiáng)技術(shù)研究[J].電子產(chǎn)品可靠性與環(huán)境試驗(yàn),2022,40(3):75-80.
[7]王萬(wàn)森,龔文.Java動(dòng)態(tài)類(lèi)加載機(jī)制研究及應(yīng)用[J].計(jì)算機(jī)工程與設(shè)計(jì),2011,32(6):2154-2158.
[8]王昊天,于航,商貝寧Java反射機(jī)制概述[]].電子世界,2020(3):73-74.
[9]陳澤生.應(yīng)對(duì)醫(yī)療系統(tǒng)海量告警的收斂技術(shù)研究與應(yīng)用[J].中國(guó)信息化,2021(11):22-24.
[10]王茂鋼.Java內(nèi)存模型描述及變量運(yùn)用分析[J].現(xiàn)代信息科技,2019,3(4):98-99.
作者簡(jiǎn)介:黃祿森,本科,工程師,ccccalm@qq.com,研究方向:物聯(lián)網(wǎng)平臺(tái)及大數(shù)據(jù)平臺(tái)。