摘要:然而,問(wèn)題在于大量的日志可能會(huì)導(dǎo)致有用的事件日志被忽略掉,這樣完全達(dá)不到日志記錄的目的。高性能質(zhì)量的日志記錄中也會(huì)詳細(xì)闡述在不影響應(yīng)用性能的前提下能夠?qū)崿F(xiàn)質(zhì)量記錄的相關(guān)技術(shù)。
【編者按】本文作者是 Archanaa Panda ,從 2000 以來(lái)一直在軟件開(kāi)發(fā)(構(gòu)架、設(shè)計(jì)和編程)團(tuán)隊(duì)擔(dān)任 Java / JavaEE 構(gòu)架師,目前立志于做一個(gè)與時(shí)俱進(jìn)的獨(dú)立的顧問(wèn)架構(gòu)師。在本篇文章中,作者通過(guò)多個(gè)方面為生產(chǎn)環(huán)節(jié)的日志提供建議和指導(dǎo),最后還介紹了一個(gè)高性能的智能日志技術(shù),幫助大家構(gòu)建高性能的智能日志框架。
??
當(dāng)應(yīng)用在生產(chǎn)過(guò)程中,日志通常處于開(kāi)發(fā)周期的次要位置,但實(shí)際上高性能的日志可能成為開(kāi)發(fā)團(tuán)隊(duì)的重要生命線。在此我們假設(shè)讀者已熟悉了各種日志框架,如 Log4j 、 SLF4J 等,所以不再詳細(xì)介紹,本文旨在為「真實(shí)」的生產(chǎn)日志提供指南,檢測(cè)其對(duì)應(yīng)用質(zhì)量的影響,同時(shí)還為大家介紹了一個(gè)被遺忘已久的高性能的智能日志技術(shù)。
2.介紹在為應(yīng)用搭建架構(gòu)、設(shè)計(jì)、開(kāi)發(fā)甚至是提升性能的整個(gè)環(huán)節(jié)中,大家都常常忽略日志的重要性。最后當(dāng)應(yīng)用程序一切準(zhǔn)備就緒打算部署的時(shí)候,會(huì)發(fā)生什么呢?
糟糕!應(yīng)用程序已經(jīng)脫離你的開(kāi)發(fā)環(huán)境,它無(wú)法運(yùn)行出你想要的 IDE 平臺(tái),而且沒(méi)有對(duì)應(yīng)的調(diào)試器可用,此時(shí)你才想起來(lái)日志的重要性似乎為時(shí)已晚。然后當(dāng)你費(fèi)勁地想從一大堆日志中嘗試調(diào)試出應(yīng)用哪里出了問(wèn)題,才發(fā)現(xiàn)這個(gè)任務(wù)不僅僅是艱巨,而且極其無(wú)聊、繁瑣,還會(huì)浪費(fèi)大量的時(shí)間。根據(jù)你多年的經(jīng)驗(yàn)和專業(yè)知識(shí)來(lái)看,這樣的做法毫無(wú)疑問(wèn)是大海撈針!再或者你把這個(gè)任務(wù)分配給下屬或運(yùn)維團(tuán)隊(duì),而這樣一份繁瑣無(wú)比費(fèi)力不討好的工作,擱誰(shuí)身上都會(huì)招致抱怨!甚至他們也無(wú)功而返,集體抱怨你的失策,你只有讓專業(yè)架構(gòu)師和設(shè)計(jì)師參與進(jìn)來(lái)。
所以,日志應(yīng)該是生產(chǎn)應(yīng)用的重要生命線,誰(shuí)都不應(yīng)該掉以輕心。當(dāng)然,眾所周知,可以根據(jù)需求開(kāi)啟或關(guān)閉各種日志的記錄級(jí)別,市面上知道有多種日志類別和日志框架,如 Log4j 、 Commons Logging 或是 SLF4J ,我們可以直接將日志發(fā)到不同目的地,如文件、數(shù)據(jù)庫(kù)、 JMS 隊(duì)列等。
但是我們中有多少人會(huì)真正地計(jì)劃日志呢?又有多少人理解日志是如何影響系統(tǒng)質(zhì)量的呢?誰(shuí)又會(huì)不斷地去優(yōu)化日志,時(shí)刻記得一旦應(yīng)用上線,日志會(huì)對(duì)系統(tǒng)和工作生活產(chǎn)生哪些影響?還有多少人已經(jīng)嘗試過(guò)利用日志框架的先進(jìn)功能來(lái)提升日志性能呢?
本文主要想喚醒大家對(duì)應(yīng)用日志的重視,同時(shí)為部署應(yīng)用日志提供基本指導(dǎo)。最后,本文會(huì)介紹一個(gè)被遺忘已久的日志技術(shù),在不影響應(yīng)用性能和質(zhì)量的前提下,幫助大家實(shí)現(xiàn)高質(zhì)量的日志記錄。
3.記錄其他系統(tǒng)質(zhì)量屬性 3.1.1監(jiān)控日志記錄是最常見(jiàn)的質(zhì)量監(jiān)控方式,它可以幫助應(yīng)用開(kāi)發(fā)者探究到問(wèn)題的根源。但這些往往只通過(guò)監(jiān)控來(lái)實(shí)現(xiàn),對(duì)于開(kāi)發(fā)者來(lái)說(shuō),在代碼的各個(gè)地方編寫一個(gè) System.out.println() 或 logger.log() 語(yǔ)句再簡(jiǎn)單不過(guò)。然而,問(wèn)題在于大量的日志可能會(huì)導(dǎo)致有用的事件日志被忽略掉,這樣完全達(dá)不到日志記錄的目的。所以,開(kāi)發(fā)者可能會(huì)尋找其他系統(tǒng)監(jiān)控技術(shù),如使用或開(kāi)發(fā) JMX 控制臺(tái)。這一點(diǎn)會(huì)在后面的 「為待生產(chǎn)的應(yīng)用進(jìn)行日志記錄」章節(jié)中詳細(xì)討論。
3.1.2 性能不管咨詢哪位性能專家或架構(gòu)師,對(duì)于 90% 的應(yīng)用來(lái)說(shuō),過(guò)多的日志記錄都會(huì)對(duì)性能產(chǎn)生非常不利的影響。日志是一種 I/O 密集型活動(dòng),的確會(huì)對(duì)應(yīng)用性能產(chǎn)生不良影響,特別是傳統(tǒng)的日志方式還會(huì)寫入應(yīng)用線程環(huán)境的 FileAppender 中。不僅如此,日志代碼還會(huì)造成大量的堆消耗和垃圾收集,比如:
?if (logger.isDebugEnabled()) ???? ?????logger.debug("name "+person.name+" age "+person.age+" address "+person.address);
除此之外,內(nèi)部調(diào)用日志到 Log4J Appender 的 doappend() 方法,會(huì)與線程安全同步。這也意味著,應(yīng)用線程不僅在同步地進(jìn)行大量的磁盤 I/O 操作,還會(huì)在寫入日志時(shí)互相阻塞!在某電子政務(wù)門戶網(wǎng)站上最嚴(yán)峻的性能情形之一就是,線程轉(zhuǎn)儲(chǔ)顯示在日志記錄寫入到單個(gè)文件 appender 時(shí),應(yīng)用日志也被寫入到這個(gè)的 appender 文件集中!
事實(shí)上,性能專家首先會(huì)確定應(yīng)用的當(dāng)前日志級(jí)別,然后通常只是把日志級(jí)別從 DEBUG 切換 INFO 或 WARNING 模式,來(lái)達(dá)到提升應(yīng)用性能的目的。但是,在完成性能基準(zhǔn)測(cè)試工作或即時(shí)可伸縮問(wèn)題之后,應(yīng)用開(kāi)發(fā)者在尋找應(yīng)用功能性 bug 的根本原因時(shí),又會(huì)將日志級(jí)別改回到 DEBUG 模式。事實(shí)上,這并不是一個(gè)科學(xué)的日志操作。在「為待生產(chǎn)的應(yīng)用進(jìn)行日志記錄」中,我們還會(huì)進(jìn)一步討論日志規(guī)范和衛(wèi)生維護(hù)?!父咝阅苜|(zhì)量的日志記錄」中也會(huì)詳細(xì)闡述在不影響應(yīng)用性能的前提下能夠?qū)崿F(xiàn)質(zhì)量記錄的相關(guān)技術(shù)。
3.1.3安全性(審核和其他敏感信息)審核日志是一類特殊的日志,主要用于應(yīng)用的安全審核和跟蹤用戶操作。以下示例主要介紹了日志在安全性方面的幫助。
但是,如果走向另一個(gè)極端,日志中攜帶的敏感信息,如用戶的帳戶密碼,可能會(huì)暴露系統(tǒng)漏洞。
第三,記錄應(yīng)用程序的事件和流程可能有助于開(kāi)發(fā)者監(jiān)控和調(diào)試,但同時(shí)可能會(huì)無(wú)意地暴露應(yīng)用的內(nèi)部架構(gòu)。
在當(dāng)前的云應(yīng)用環(huán)境中,應(yīng)用可以在公共云上托管,這樣的漏洞會(huì)對(duì)應(yīng)用所有者的知識(shí)產(chǎn)權(quán)構(gòu)成威脅。
3.1.4可擴(kuò)展性和高可用性日志記錄會(huì)和擴(kuò)展性、高可用性之間互相影響。利用「高性能質(zhì)量的日志」技術(shù)來(lái)提高應(yīng)用性能,用更少的硬件提高擴(kuò)展性和可用性,在現(xiàn)有的資源和條件下,你的應(yīng)用完全可以「重拳出擊」。
當(dāng)應(yīng)用被擴(kuò)展成能夠?qū)捎眯赃M(jìn)行主動(dòng)或被動(dòng)配置時(shí),就會(huì)有多個(gè)應(yīng)用實(shí)例,而日志策略就顯得非常重要。應(yīng)用是否能支持,或者開(kāi)發(fā)團(tuán)隊(duì)是愿意收集來(lái)自10個(gè)不同機(jī)器或目錄的日志,還是找一個(gè)位置能集中收集日志呢?此時(shí),集中的分布式日志變得至關(guān)重要。
3.1.5可恢復(fù)性像如 Oracle 這樣的重要數(shù)據(jù)庫(kù),已經(jīng)使用 Redo 日志來(lái)確保事務(wù)恢復(fù)。應(yīng)用也可以參考這種做法,使用一類特殊的日志幫助恢復(fù),以防萬(wàn)一。
3.1.6錯(cuò)誤處理和容錯(cuò)在大多數(shù)應(yīng)用中,日志只是其中一種錯(cuò)誤處理方式,有時(shí)只用來(lái)評(píng)估錯(cuò)誤。在復(fù)發(fā)性錯(cuò)誤,如短信/郵件服務(wù)器或數(shù)據(jù)庫(kù)長(zhǎng)期不可用的情況下,重復(fù)地、頻繁地記錄錯(cuò)誤是百害而無(wú)一利,特別在大量的異常堆棧跟蹤下,只會(huì)大大地增加 I/O 活動(dòng)。在這個(gè)過(guò)程中,當(dāng)你要分析一個(gè)星期前被忽略的老問(wèn)題時(shí),這時(shí)候關(guān)于這個(gè)問(wèn)題的日志早已滾動(dòng)更新,這種方法只會(huì)「火上澆油」。
3.1.7容量在考慮應(yīng)用的容量問(wèn)題時(shí),架構(gòu)師會(huì)參考生產(chǎn)環(huán)節(jié)的日志大小,再估計(jì)所需的磁盤空間、集中文件系統(tǒng)的配置等。
對(duì)于分布式環(huán)境中的集中式日志,也需要估計(jì)分布在網(wǎng)絡(luò)到遠(yuǎn)程機(jī)器的日志對(duì)象的大小。
4.缺少重要日志的案例分析本節(jié)主要介紹作者對(duì)嵌入式應(yīng)用案例的研究經(jīng)驗(yàn),如果在架構(gòu)、設(shè)計(jì)和開(kāi)發(fā)階段忽略了日志記錄的重要性,問(wèn)題一旦發(fā)生,之前所做的一切可能功虧一簣,只得在慘痛的教訓(xùn)面前學(xué)著「吃一塹,長(zhǎng)一智」。
舉一個(gè)大家都熟悉的場(chǎng)景, GPS 設(shè)備就是一個(gè)嵌入式應(yīng)用,裝載在車中可以進(jìn)行位置跟蹤。該設(shè)備不提供任何用戶界面,除了 LEDs 和幾個(gè)按鈕,所以幾乎沒(méi)有人來(lái)管理車輛內(nèi)部的應(yīng)用程序,不像豪華車型那樣會(huì)和服務(wù)器端應(yīng)用進(jìn)行交互。因此,如果設(shè)備應(yīng)用出現(xiàn)了問(wèn)題,應(yīng)用開(kāi)發(fā)者應(yīng)該如何診斷問(wèn)題根源呢?隨著各種卡車被運(yùn)往全國(guó)各地,日志又是何時(shí)寫入車內(nèi)設(shè)備的呢?
應(yīng)用開(kāi)發(fā)者可能會(huì)異想天開(kāi),全國(guó)各地都配備了服務(wù)工程師,能夠取下設(shè)備帶回去進(jìn)一步分析。以上設(shè)想純屬虛構(gòu),實(shí)際上,開(kāi)發(fā)者只會(huì)和服務(wù)工程師登入設(shè)備的操作系統(tǒng)去復(fù)制日志。但面對(duì)繁雜的日志,連續(xù)的加班作戰(zhàn)只會(huì)讓人身心疲憊!
為了更方便地完成這項(xiàng)工作,應(yīng)用開(kāi)發(fā)者在設(shè)備的桌面服務(wù)應(yīng)用中加上「日志下載」按鈕。服務(wù)工程師就可以直接利用筆記本里的服務(wù)應(yīng)用下載相關(guān)的設(shè)備日志。這至少是一個(gè)進(jìn)步,至少不必再讓車停下來(lái)再取走設(shè)備了,也給了本該陪同服務(wù)工程師夜以繼日下載日志的可憐開(kāi)發(fā)者們一絲喘息的空間。顯然,服務(wù)工程師也不至于全世界亂跑了,他們只要盯著應(yīng)用開(kāi)發(fā)團(tuán)隊(duì)注意下載日志即可。
最后,開(kāi)發(fā)團(tuán)隊(duì)不得不提高設(shè)備應(yīng)用的性能,讓它像發(fā)送其他跟蹤數(shù)據(jù)一樣,直接通過(guò)無(wú)線 GPRS 就可以發(fā)送日志到后端服務(wù)器。
需要注意是,在初始的預(yù)估和開(kāi)發(fā)過(guò)程中,所有這些額外工作都沒(méi)有被計(jì)入需求池或預(yù)算中。開(kāi)發(fā)團(tuán)隊(duì)已經(jīng)有一個(gè)典型的由客戶功能需求驅(qū)動(dòng)的思維定勢(shì)。應(yīng)用日志既不是一個(gè)客戶驅(qū)動(dòng)的需求,也并非是突出的非功能屬性。所以新手開(kāi)發(fā)者通常缺乏遠(yuǎn)見(jiàn),也無(wú)力說(shuō)服高層或管理者給他們足夠的時(shí)間預(yù)算來(lái)建立這樣的設(shè)施。當(dāng)這些設(shè)備準(zhǔn)備上市時(shí),他們遇到了這樣的問(wèn)題,經(jīng)理和客戶氣得臉紅脖子粗,而他們不得不挑燈夜戰(zhàn)。真是一個(gè)費(fèi)力不討好的活兒!
5. 為待生產(chǎn)的應(yīng)用進(jìn)行日志記錄and don"ts in this section, which would make an application production ready.
在上一節(jié)「記錄其他系統(tǒng)質(zhì)量屬性」中,我們已經(jīng)遇到了一些在生產(chǎn)環(huán)境中不得不面臨的問(wèn)題。接下來(lái)在本節(jié)中,我們?cè)倭_列出哪些該做和哪些不該做,為應(yīng)用的待生產(chǎn)狀態(tài)做準(zhǔn)備。
-?日志規(guī)范和代碼審查
日志規(guī)范極其重要,因?yàn)檫@一步將為本文討論的其他最佳實(shí)踐鋪平道路。事實(shí)上,許多生產(chǎn)系統(tǒng)還會(huì)有那些無(wú)聊的日志,如 「 Hi 」 、 「 Came over here 」、「 Done 」、「 xxxyyyyzzzz 」。這些日志通常會(huì)在應(yīng)用調(diào)試階段或開(kāi)發(fā)階段的單元測(cè)試中產(chǎn)生。
但生產(chǎn)階段還有人仍然采用這樣的無(wú)聊日志,其給出的理由是它們只會(huì)在調(diào)試時(shí)產(chǎn)生,而且便于關(guān)閉。但是,在實(shí)踐中開(kāi)發(fā)者很少這樣做,關(guān)閉的同時(shí)也關(guān)掉了一些有價(jià)值的日志。為了更好地控制日志,需要開(kāi)發(fā)者非常精細(xì)地配置日志框架,但在生產(chǎn)中卻常常忽略這一點(diǎn)
同時(shí),代碼審查必須提高效率。當(dāng)高級(jí)開(kāi)發(fā)者或團(tuán)隊(duì)領(lǐng)導(dǎo)審查日志時(shí),必須確保刪除掉無(wú)用的日志,即使要面對(duì)一些挑釁的言論,比如有人說(shuō)「我已經(jīng)在測(cè)試時(shí)刪過(guò)日志了」,「不就是個(gè)日志么!它又不是引發(fā)問(wèn)題的原因」。但這是一個(gè)很好的規(guī)則,日志并不是開(kāi)發(fā)過(guò)程中用來(lái)調(diào)試問(wèn)題的方式,負(fù)責(zé)調(diào)試的是我們 IDE 的調(diào)試器!
-?當(dāng)你對(duì)應(yīng)用進(jìn)行模塊化時(shí),也需要關(guān)注集中式日志
應(yīng)用日志寫入應(yīng)用服務(wù)器的 SystemOut 或 SystemError 文件顯示不是最高效的辦法,但在生產(chǎn)環(huán)境中仍然常見(jiàn),或如前所述,電子政務(wù)門戶的線程互相阻塞,共同爭(zhēng)奪一個(gè) FileAppender 或者一個(gè)文件 I/O 。
最起碼,開(kāi)發(fā)者應(yīng)該將有基于軟件包或完全限定類為已有的記錄器命名約定,并可能將不同的日志分類記錄到不同的 Appender 位置。
在生產(chǎn)過(guò)程中,應(yīng)該牢記日志級(jí)別應(yīng)該是 WARNING 或根據(jù)日志信息設(shè)為 INFO 級(jí)別。
一個(gè)有效的方法是在中央配置或常量類中,列舉出所有可能的日志,并只允許開(kāi)發(fā)者使用這些日志。我們將在「設(shè)計(jì)高性能的智能日志」章節(jié)中進(jìn)行討論。
-?在集群環(huán)境和分布式環(huán)境中記錄日志
幾乎所有的服務(wù)器端應(yīng)用都必須采用集群和分布式環(huán)境,因?yàn)檫@兩種技術(shù)可以提供可擴(kuò)展性和可用性。在集群環(huán)境中,日志應(yīng)該反映出組件、模塊、子系統(tǒng)以及其過(guò)程實(shí)例。
在分布式和集群的環(huán)境采用集中的日志服務(wù)器,可以避免從多個(gè)目錄和機(jī)器上收集日志的繁瑣。同時(shí),對(duì)于移動(dòng) I/O 到一個(gè)多帶帶的機(jī)器上也更加方便,而應(yīng)用性能可以不再受日志 I/O 的影響。
-?在厚分布式客戶端或嵌入式應(yīng)用中進(jìn)行日志記錄
在「缺少重要日志的案例分析」章節(jié)中的趣聞中也提道,在厚客戶端或嵌入式應(yīng)用的日志幾乎不會(huì)發(fā)送給到開(kāi)發(fā)團(tuán)隊(duì),也無(wú)從幫助他們進(jìn)行問(wèn)題分析。遠(yuǎn)程傳輸日志的機(jī)制需要再深思熟慮,再適當(dāng)?shù)亓腥腠?xiàng)目計(jì)劃進(jìn)行開(kāi)發(fā)。
-?使用映射診斷環(huán)境和嵌套診斷環(huán)境
Log4j 的映射診斷環(huán)境( MDC )和嵌套診斷環(huán)境( NDC )使用 ThreadLocal 儲(chǔ)存環(huán)境特定信息。它們可以存儲(chǔ)如用戶名、事務(wù) ID 這樣的信息,來(lái)識(shí)別特定用戶或事務(wù)所做的全部操作。這就不需要為了日志記錄,在類和方法中傳遞特定環(huán)境信息。利用 PatternLayout 的 %X 或 X { key } ,存儲(chǔ)的值將在日志中呈現(xiàn)。
-?規(guī)劃日志的生命周期和維護(hù)
這包括規(guī)劃日志滾動(dòng)更新之前的日志文件大小和最大數(shù)量。為什么需要規(guī)劃呢?因?yàn)槿罩疚募34蟮接梦谋揪庉嬈鞫即虿婚_(kāi)!正如腳本會(huì)定期對(duì)數(shù)據(jù)庫(kù)進(jìn)行備份一樣,也應(yīng)該有腳本來(lái)備份和歸檔日志。當(dāng)超出磁盤空間限制時(shí),壓縮日志文件也是不錯(cuò)的想法,這樣遠(yuǎn)程傳輸起來(lái)會(huì)更加容易。
-?抵制實(shí)時(shí)記錄源位置信息的誘惑
獲取位置信息常常以昂貴的性能損失為代價(jià),因?yàn)槿罩究蚣茉噲D確定當(dāng)前的線程堆棧,從而獲得該方法、文件名和行數(shù)。確切地說(shuō),日志信息本身就可以通過(guò)提供服務(wù)器、子系統(tǒng)、模塊、組件、線程等信息找出日志的來(lái)源。
-?避免重復(fù)使用長(zhǎng)堆棧跟蹤來(lái)記錄錯(cuò)誤
如果可能的話,日志中應(yīng)該有足夠的信息顯示錯(cuò)誤發(fā)生的位置,并盡可能避免巨大的堆棧跟蹤。當(dāng)然,這不是一個(gè)像 NullPointerException 那樣的特例。但它可以為一些容易識(shí)別的特定應(yīng)用錯(cuò)誤進(jìn)行記錄。此外,當(dāng)經(jīng)常性問(wèn)題長(zhǎng)期發(fā)生時(shí),如與 Email 、短信或數(shù)據(jù)庫(kù)服務(wù)器的連接問(wèn)題,日志記錄也會(huì)每隔5分鐘地記錄該問(wèn)題,而不是每隔幾秒就用巨大的堆棧跟蹤填充日志。
-?不要盲目使用 AOP 注入記錄,尤其在生產(chǎn)過(guò)程中
對(duì)于新手來(lái)說(shuō),最基本的 AOP 教材案例就是日志。因?yàn)槿罩颈旧砭褪且粋€(gè)橫切關(guān)注點(diǎn),新手可以在進(jìn)入方法之前或退出方法之后注入日志。在應(yīng)用于生產(chǎn)有價(jià)值的應(yīng)用之前,應(yīng)該嚴(yán)肅地考慮這個(gè)示例或觀點(diǎn)。對(duì)于以上已經(jīng)建立的示例,日志記錄可不是一件小事,它值得像大多數(shù)其他非功能性需求( NFRs )一樣進(jìn)行詳細(xì)布局規(guī)劃。
-?別把日志當(dāng)作其他監(jiān)控手段的替代品
最滑稽地使用日志記錄的典型案例之一就是「性能日志」,如下所示:
19 Sept 2010 10:20:30 PERF INFO Thread-25 OrderInsertAction.java Time taken in processing OrderInsertAction: 50ms 19 Sept 2010 10:20:33 PERF INFO Thread-8 OrderInsertDao.java Time taken in insert 30ms
筆者就曾犯過(guò)這樣的問(wèn)題,卻沒(méi)意識(shí)到它增加 I/O 對(duì)性能產(chǎn)生的嚴(yán)重危害。
更明智的做法是捕獲 「 TimeStatistic 」 的總時(shí)間,并用計(jì)數(shù)器算出用 GUI 屏幕顯示同樣內(nèi)容的平均時(shí)間、最長(zhǎng)時(shí)間、最短時(shí)間。
6.設(shè)計(jì)高性能的智能日志在這一節(jié)中主要討論的策略是將集中式日志包裝成記錄器,日志采用整數(shù)編碼而不是字符串。這項(xiàng)技術(shù)已經(jīng)由作者在導(dǎo)師的建議下成功地實(shí)現(xiàn)。
目前在網(wǎng)上有許多文章都介紹如何用 JMS 隊(duì)列和主題或 sockets 來(lái)構(gòu)建集中式日志記錄。集中式日志記錄能夠通過(guò)移動(dòng) I/O 活動(dòng)到不同的機(jī)器上進(jìn)一步提高性能,雖然會(huì)對(duì)程序節(jié)點(diǎn)有輕微的開(kāi)銷。
但是,這里的關(guān)鍵是結(jié)合代碼來(lái)記錄集中式日志,而非冗長(zhǎng)的字符串。現(xiàn)有框架 Log4J 或者 Commons Logging 鼓勵(lì)使用字符串來(lái)記錄信息,這樣的作法會(huì)對(duì)內(nèi)存、磁盤和網(wǎng)絡(luò)資源造成一定影響,而這些工作完全可以通過(guò)一段簡(jiǎn)單的代碼搞定。
一個(gè)多帶帶的文件可以列出錯(cuò)誤代碼和可識(shí)別字符串之間的映射。
如以下日志記錄:
[090822 16:02:48] TX WARNING (Tx-2-thread-1: 1163 transmitData): Server has not responded with an ACK, so trying again.
與下面的日志進(jìn)行對(duì)比
1300604499194,4,192168001002,20600,1001,2,500000
以上日志顯示了長(zhǎng)時(shí)間戳、日志級(jí)別、生成日志的機(jī)器IP地址、處理的整數(shù)值、處理模塊、應(yīng)用的實(shí)例ID和一個(gè)完整的錯(cuò)誤代碼,代碼翻譯過(guò)來(lái)也會(huì)傳達(dá)相同的含義。這種對(duì)象非常便于在網(wǎng)絡(luò)中以二進(jìn)制格式進(jìn)行傳輸。如果有上下文信息能進(jìn)一步限定日志中的信息,一個(gè) Object[] 數(shù)組也可以被傳遞,而主錯(cuò)誤代碼將轉(zhuǎn)化成為帶有 printf() 格式占位符的字符串。
使用短碼表示錯(cuò)誤的做法,幾乎在所有的主流產(chǎn)品中都很常見(jiàn),如 Oracle 、 WebSphere 、 Microsoft 。例如,在微軟的 Office 應(yīng)用出現(xiàn)錯(cuò)誤時(shí),所反饋的錯(cuò)誤對(duì)話框就是一個(gè)難以讀懂的整數(shù)代碼,然后會(huì)發(fā)送給微軟用于診斷。
在查看錯(cuò)誤時(shí),可以將各種錯(cuò)誤代碼翻譯成完整的字符串進(jìn)一步解讀。
這樣做的好處有如下幾點(diǎn):
能節(jié)省磁盤空間,從而延長(zhǎng)日志的保質(zhì)期和縮減文件大小
應(yīng)用內(nèi)部設(shè)計(jì)和執(zhí)行的一些安全措施不會(huì)被日志暴露。但在脫機(jī)查看時(shí),日志可以通過(guò)使用翻譯機(jī)來(lái)翻譯全文。
避免構(gòu)造或傳輸長(zhǎng)字符串,進(jìn)一步減少內(nèi)存使用。
網(wǎng)絡(luò)傳輸中日志是非常輕量的,所以在調(diào)試日志時(shí)也盡可能保持最小開(kāi)銷。
防止日志隨機(jī)構(gòu)造
通過(guò)自定制工具更高效地搜索特定錯(cuò)誤
此外,通過(guò)防止直接使用 Log4J 或其他類似的框架可以執(zhí)行日志記錄,或者在你最喜歡的日志框架上或自定制日志上編寫一個(gè)定制格式,比如:
public class LogClientFacade { public void log(int logLevel, int instanceId, int subsystemId, int componentId, int errorCode); public void logWithContext(int logLevel, int instanceId, int subsystemId, int componentId, int errorCode, Object[] contextInfo); public void logWithEx(int logLevel, int instanceId, int subsystemId, int componentId, int errorCode, Throwable ex); ... }
這樣的日志接口能確保開(kāi)發(fā)者注意到在分布式環(huán)境下診斷日志的基本信息,比如子系統(tǒng)、部件或其他,不必在在實(shí)時(shí)操作中記錄源代碼的行號(hào)和文件名。
上圖顯示了一種解決方案的建議設(shè)計(jì)。其目的是通過(guò)在隊(duì)列和異步處理中收集信息,或在接收器線程中進(jìn)行轉(zhuǎn)移,盡量確保日志的處理過(guò)程不存在阻塞。這種方式在網(wǎng)絡(luò)傳輸過(guò)程中,以二進(jìn)制序列化格式進(jìn)行信息傳輸具有諸多優(yōu)勢(shì),特別是完整的解決方案是同步地使用同一語(yǔ)言時(shí)。
當(dāng)他們倒進(jìn)服務(wù)器查看離線日志時(shí),應(yīng)該有一個(gè)簡(jiǎn)單的圖形用戶界面來(lái)觀看日志。然后用一個(gè)翻譯機(jī)將日志轉(zhuǎn)換為文本格式,而日志本身也會(huì)以二進(jìn)制格式寫入磁盤。需要注意的是,這種方法能和云環(huán)境很好地關(guān)聯(lián),從而確保部署的知識(shí)產(chǎn)權(quán)的保密性。
6.1A 注意實(shí)施擴(kuò)展現(xiàn)有框架也是一種好方法,如 Log4J 、 Commons Logging 、 SLF4J 。但是,這樣做的話,為了遵循框架內(nèi)部API的通用性,可能會(huì)犧牲一部分效率。例如, Log4J 會(huì)序列化日志消息,而堆棧跟蹤會(huì)作為字符串在 SocketAppender 和 JMSAppender 中進(jìn)行網(wǎng)絡(luò)傳遞。該框架相當(dāng)易于擴(kuò)展,而且能覆蓋所選擇框架的特定部分,如通過(guò)添加或擴(kuò)展新的 Appenders ,擴(kuò)展內(nèi)部的數(shù)據(jù)傳輸對(duì)象,如 LoggingEvent ,并進(jìn)行自定義序列化。再者,如果需要最大的靈活性,你可以僅用較短的時(shí)間來(lái)創(chuàng)建一個(gè)簡(jiǎn)單的自定義日志框架。
另一個(gè)有趣的決定是在應(yīng)用運(yùn)行在服務(wù)器時(shí)是否使用 JMS ,或者通過(guò)使用一個(gè)獨(dú)立隊(duì)列,如 WebSphereMQ 、HornetQ 或 ActiveMQ 。如果選擇 JMS ,以下是作者的幾點(diǎn)建議:
使用寬松質(zhì)量屬性來(lái)避免增加事務(wù)、持續(xù)性并允許隊(duì)列重復(fù)。記住,嚴(yán)格可靠性會(huì)降低性能,對(duì)日志而言這是不必要的。
在一個(gè) JVM 中,要么是在日志服務(wù)器或在客戶子系統(tǒng),最好是使用輕量的 java.util.concurrent 隊(duì)列或 in-VM 隊(duì)列實(shí)現(xiàn),從而避免系列化開(kāi)銷。
建議使用消息代理或運(yùn)輸橋梁,而不是用一個(gè)集中式隊(duì)列,并做相同的遠(yuǎn)程調(diào)用。
本人的個(gè)人偏好是使用簡(jiǎn)單的 socket。
7.總結(jié)在這篇文章中,我們已經(jīng)討論了最佳實(shí)踐和日志記錄中所發(fā)現(xiàn)的弊端。我們還提出了一種結(jié)合集中式日志和代碼的技術(shù),從而取代字符串實(shí)現(xiàn)高性能的智能日志實(shí)踐。
作者將構(gòu)思高性能智能日志的設(shè)計(jì)歸功于她的導(dǎo)師 Akash Gupt 先生,是 InterGlobe 科技公司的解決方案架構(gòu)師( http://in.linkedin.com/pub/akash-gupta/3/79/2b3 ),在他的指導(dǎo)下,作者成功地實(shí)施并觀察到這種技術(shù)的巨大性能優(yōu)勢(shì)。
8References
8.引用Pro Apache Log4J by Samudra Gupta
Log4J Source code
(編譯自:https://dzone.com/articles/high-performance-and-smarter)
OneAPM 為您提供端到端的 Java 應(yīng)用性能解決方案,我們支持所有常見(jiàn)的 Java 框架及應(yīng)用服務(wù)器,助您快速發(fā)現(xiàn)系統(tǒng)瓶頸,定位異常根本原因。分鐘級(jí)部署,即刻體驗(yàn),Java 監(jiān)控從來(lái)沒(méi)有如此簡(jiǎn)單。想閱讀更多技術(shù)文章,請(qǐng)?jiān)L問(wèn) OneAPM 官方技術(shù)博客。
本文轉(zhuǎn)自 OneAPM 官方博客
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/11731.html
摘要:接下來(lái)我們以余額寶為例,重點(diǎn)剖析天弘基金在日志數(shù)據(jù)分析領(lǐng)域是如何突破的此前,天弘基金一直使用開(kāi)源的日志方案,研發(fā)和運(yùn)維人員通過(guò)對(duì)日志數(shù)據(jù)進(jìn)行處理,使用日志文件進(jìn)行查詢檢索。 雙十一剛剛結(jié)束,其實(shí)最緊張的不是商鋪理貨,也不是網(wǎng)友緊盯大促商品準(zhǔn)備秒殺,而是網(wǎng)購(gòu)幕后的運(yùn)維人員,他們最擔(dān)心:什么網(wǎng)絡(luò)中斷、應(yīng)用卡頓、響應(yīng)速度慢,服務(wù)器宕機(jī)……雙十一作為電商 IT 部門的頭等大事,大促前,運(yùn)維人員就需要...
摘要:但隨著大數(shù)據(jù)及人工智能的快速發(fā)展,傳統(tǒng)的運(yùn)維方式及解決方案已不能滿足需求。從海量日志中獲取慢屬于大數(shù)據(jù)分析范疇。 摘要: AIOps英文全稱是Algorithmic IT Operations,是基于算法的IT運(yùn)維。AIOps是運(yùn)維領(lǐng)域上的熱點(diǎn),然而在滿足業(yè)務(wù)SLA的前提下,如何提升平臺(tái)效率和穩(wěn)定性及降低資源成本成為AIOps面臨的問(wèn)題和挑戰(zhàn)。 背景 隨著搜索業(yè)務(wù)的快速發(fā)展,搜索系統(tǒng)...
摘要:用戶態(tài)功能得到加強(qiáng)。與之對(duì)應(yīng)的是另一種操作系統(tǒng)體系架構(gòu)微內(nèi)核,在微內(nèi)核架構(gòu)下,即使是操作系統(tǒng)內(nèi)核功能,比如文件系統(tǒng)網(wǎng)絡(luò)協(xié)議棧設(shè)備驅(qū)動(dòng)程序等,也是以進(jìn)程形式實(shí)現(xiàn),每個(gè)功能是一個(gè)獨(dú)立的進(jìn)程,占用獨(dú)立的地址空間。 經(jīng)過(guò)HelloX開(kāi)發(fā)團(tuán)隊(duì)近一年的努力,在HelloX V1.86版本基礎(chǔ)上,增加許多...
閱讀 1352·2023-04-25 15:21
閱讀 2684·2021-11-24 10:23
閱讀 3409·2021-10-11 10:59
閱讀 3255·2021-09-03 10:28
閱讀 1739·2019-08-26 13:45
閱讀 2329·2019-08-26 12:11
閱讀 929·2019-08-26 12:00
閱讀 1718·2019-08-26 10:44