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