1. 程式人生 > >日誌級別動態調整--小工具解決大問題

日誌級別動態調整--小工具解決大問題

背景

隨著外賣業務的快速發展,業務複雜度不斷增加,線上系統環境有任何細小波動,對整個外賣業務都可能產生巨大的影響,甚至形成災難性的雪崩效應,造成巨大的經濟損失,因而每一次客訴、系統抖動等都是對我們技術人員的重大考驗:我們必須立即響應,快速解決問題。但是,如何提高排查問題的效率呢?最有效的方式是通過分析系統日誌。如果系統日誌全面,會給我們排查解決線上問題帶來絕大幫助,但是要想保證系統日誌全面,就必須打印出所有的系統或業務日誌,這樣就會帶來另一個問題:日誌量的暴漲,過多的日誌除了能夠幫助我們解決問題外,同時會直接造成系統性能下降,極端情況下,甚至導致系統宕機。在這種背景下,為了兼顧效能和快速響應線上問題,我們設計開發了日誌級別動態調整元件。通過使用該元件,可以在需要解決線上問題時,實時調整線上日誌輸出級別,獲取全面的debug日誌,幫助工程師提高定位問題的效率。

場景介紹

場景一:

業務依賴複雜,某一時刻,依賴的下游服務故障,導致請求大量超時,尤其是對於外賣這種集中性特別明顯的業務,平均每秒QPS在8000以上,1分鐘的故障就會集中產生大量的錯誤日誌,導致磁碟IO急劇提高,耗費大量cpu,進而導致整個服務癱瘓。如果該業務不能立即降級,怎麼辦? 

修改日誌級別,發版上線,流程長,操作麻煩暫且不談,同時存在引入其它故障的高風險。如果系統恰好使用的log4j版本,在面對極短時間內打印出的海量錯誤日誌,會快速耗盡buffer區記憶體,從而拖慢主執行緒,造成服務效能整體下降,甚至還未來得及修復問題,海量日誌已經拖垮服務,造成服務宕機了,損失慘重。

場景二:

大量的訂單、結算等客訴問題反饋過來,一線工程師大量精力埋沒於排查問題中,而排查定位問題的最終手段仍然是依賴線上日誌,由於鏈路較長,任一日誌的缺失,都給問題的排查帶來極大的障礙,面對運營的催促,怎麼辦?

工程師為了以後排查問題的方便,在任一可能出現異常的地方,打印出關鍵日誌。然後發版上線,好不容易解決了本次問題,還沒來得及收穫喜悅,就又面臨著一個新問題,請看場景三。

場景三:

由於線上業務系統預設日誌列印級別是INFO級別,為了排查問題方便,除錯型日誌都以該級別打印出,給系統帶來了額外的負擔,高峰期大量除錯日誌拖慢系統性能,增大出故障的風險,怎麼辦?

一方面要快速響應業務,另一方面要兼顧系統性能,是否可以兩方面都兼顧?我們的動態調整日誌級別工具正是為了解決這種痛點。

該元件能夠解決什麼問題?

1、日誌降級。相容log4j、log4j2和logback主流日誌框架,如果遇到場景一,可以通過我們的日誌工具,快速調整日誌輸出級別,降低系統日誌的輸出,從而達到日誌降級的效果,同時能夠給RD爭取充裕的排查問題時間。

2、規範日誌級別濫用,幫助工程師快速定位解決線上問題。使用日誌級別動態調整元件,可以實時動態調整線上服務的日誌列印級別,除錯型日誌可以使用低級別打印出,減輕線上服務的負載壓力,遇到排查問題時,可以臨時將日誌級別調低,快速得到精準化的日誌資訊,排查解決問題。

系統基礎架構

日誌級別動態調整元件定位為中介軟體,在設計之初重點考慮了以下幾點:
1、低侵入性

  • 接入服務僅需要引入jar包和xml配置檔案即可,不存在額外編碼工作,業務耦合低,接入成本小。

2、安全可靠

  • 更改接入服務的日誌輸出級別,只能通過我們授權的後臺系統操作,所有的操作記錄有跡可查。
  • 引入許可權認證,確保工程師只能操作自己負責的服務或系統,同時會把操作內容實時周知給系統的所有相關責任人,避免誤傷。

3、視覺化操作

  • 操作者可以通過我們提供的管理頁面,定向修改一個或一批服務節點。
  • 提供視覺化的操控開關,可以隨時關閉或開啟服務。

具體實現

核心呼叫元件

本元件採用工廠模式實現,保障其高可擴充套件性。目前已實現日誌級別動態調整和方法呼叫處理單元,下面主要介紹日誌級別動態調整處理單元的實現。

目前咱們外賣業務系統基本統一採用的slf4j日誌框架,在應用初始化時,slf4j會繫結具體的日誌框架,如log4j、logback或log4j2等。具體原始碼如下(slf4j-api-1.7.7):

private final static void bind() {try {Set<URL> staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);// the next line does the bindingStaticLoggerBinder.getSingleton();INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;reportActualBinding(staticLoggerBinderPathSet);fixSubstitutedLoggers();catch (NoClassDefFoundError ncde) {String msg = ncde.getMessage();if (messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) {INITIALIZATION_STATE = NOP_FALLBACK_INITIALIZATION;Util.report("Failed to load class \"org.slf4j.impl.StaticLoggerBinder\".");Util.report("Defaulting to no-operation (NOP) logger implementation");Util.report("See " + NO_STATICLOGGERBINDER_URL" for further details.");else {failedBinding(ncde);throw ncde;}catch (java.lang.NoSuchMethodError nsme) {String msg = nsme.getMessage();if (msg != null && msg.indexOf("org.slf4j.impl.StaticLoggerBinder.getSingleton()") != -1) {INITIALIZATION_STATE = FAILED_INITIALIZATION;Util.report("slf4j-api 1.6.x (or later) is incompatible with this binding.");Util.report("Your binding is version 1.5.5 or earlier.");Util.report("Upgrade your binding to version 1.6.x.");}throw nsme;catch (Exception e) {failedBinding(e);throw new IllegalStateException("Unexpected initialization failure", e);}}

findPossibleStaticLoggerBinderPathSet方法用來查詢當前classpath下所有的org.slf4j.impl.StaticLoggerBinder類。每一個slf4j橋接包中都有一個StaticLoggerBinder類,該類實現了LoggerFactoryBinder介面。具體繫結到哪一個日誌框架則取決於類載入順序。

接下來,咱們分三部分,來說說ChangeLogLevelProcessUnit類:

1.初始化:確定所使用的日誌框架,獲取配置檔案中所有的logger記憶體例項,並將它們的引用快取到map容器中。

String type = StaticLoggerBinder.getSingleton().getLoggerFactoryClassStr();if (LogConstant.LOG4J_LOGGER_FACTORY.equals(type)) {logFrameworkType = LogFrameworkType.LOG4J;Enumeration enumeration = org.apache.log4j.LogManager.getCurrentLoggers();while (enumeration.hasMoreElements()) {org.apache.log4j.Logger logger = (org.apache.log4j.Logger) enumeration.nextElement();if (logger.getLevel() != null) {loggerMap.put(logger.getName(), logger);}}org.apache.log4j.Logger rootLogger = org.apache.log4j.LogManager.getRootLogger();loggerMap.put(rootLogger.getName(), rootLogger);else if (LogConstant.LOGBACK_LOGGER_FACTORY.equals(type)) {logFrameworkType = LogFrameworkType.LOGBACK;ch.qos.logback.classic.LoggerContext loggerContext = (ch.qos.logback.classic.LoggerContext) LoggerFactory.getILoggerFactory();for (ch.qos.logback.classic.Logger logger : loggerContext.getLoggerList()) {if (logger.getLevel() != null) {loggerMap.put(logger.getName(), logger);}}ch.qos.logback.classic.Logger rootLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);loggerMap.put(rootLogger.getName(), rootLogger);else 

相關推薦

日誌級別動態調整--工具解決問題

背景隨著外賣業務的快速發展,業務複雜度不斷增加,線上系統環境有任何細小波動,對整個外賣業務都可能產生巨大的影響,甚至形成災難性的雪崩效應,造成巨大的經濟損失,因而每一次客訴、系統抖動等都是對我們技術人員的重大考驗:我們必須立即響應,快速解決問題。但是,如何提高排查問題的效率呢

log4j日誌列印級別動態調整

1,為什麼日誌列印級別要動態調整?   隨著專案越來越大,訪問量也越來越高,遇到問題時想要排查,可是日誌一開啟卻刷的太快太快,不好排查問題,有的時候甚至因為短時間列印日誌太多,嚴重影響了效能,這個時候日誌的列印級別的動態調整就相當有必要了,在不重啟專案的情況,不改動程式碼的情況下,通過Apollo動態配置就可

BAT解決麻煩_某卡教室控制軟件

發現 lose clas 教室 nes mod ron style ask 1 @echo off 2 mode con cols=13 lines=1 3 if "%1" == "h" goto begin 4 mshta vbscript:createobject

內連線、左外連線、右外連線、全外連線、交叉連線(CROSS JOIN)-----知識解決資料攻略

       早就聽說了內連線與外連線,以前檢視中使用過、這次自考也學習了,只是簡單理解,現在深入探究學習(由於上篇部落格的出現)與實踐: 概念 關鍵字: 左右連線 資料表的連線有: 1、內連線(

數學解決問題

前言 最近閱讀了Google黑板報的“數學之美”系列文章,加上最近工作和學習中接觸了不少的演算法最終都是由簡單的數學公式或者定理解決了問題。我突發奇想地希望將我所知道的數學巧妙運用解決問題的例項記錄下來。因此這篇部落格誕生了,也希望我能夠逐步地完善,並且寫出一個系列的文章。

Java Log4j2 動態調整log級別工具

import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import o

log4j動態日誌級別調整

pri roo erro linking obj not ted oop int 1. 針對root logger的設置 log4j.rootLogger=INFO, CONSOLELogger.getRootLogger().setLevel(org.apache.log

UVA1658 Admiral 拆點法解決結點容量(路徑不能有公共點,容量為1的時候) 最費用最

ear ace == void for include () size max /** 題目:UVA1658 Admiral 鏈接:https://vjudge.net/problem/UVA-1658 題意:lrj入門經典P375 求從s到t的兩條不相交(除了s和t

一個動態導航欄(好看的,用C3)(不依賴js,點擊圖切換的背景圖)

width ima line auto fashion put spl body sha <!DOCTYPE HTML><htmllang="en-US"> <head> <meta charset="UTF-8

有學問的刷漆工具

alt 選擇 很快 com 效果 哪些 之一 由於 而且   在進行裝修過程中占有相當重要的一部分——刷漆,因為墻面粉刷的結果會直接影響著整個家裝的質量。要做到完美粉刷墻面當然少不了我們刷漆小工具,這些工具都有哪些呢?讓我們一起來看看吧。   工具之一——需用滾筒刷墻面  

Linux 使用LVM動態調整磁盤大/擴容

註意事項 容量 新的 cit -- 添加 .cn lvm磁盤管理 增加 1、只有lvm磁盤分區支持動態擴容,不影響舊數據2、擴容特別註意事項,新的分區要格式化後才能使用lvm擴容,否則加進去分區總容量增加了,可用容量卻沒有增加,無法識別參考文獻:LVM磁盤管理之擴展與縮小L

解決wordpress文章歸檔和分類目錄工具標題重復問題

php 出了 需要 列表 select 保存 選擇 工具 rsquo 最近更新了wordpress,發現更新後小工具中的文章歸檔和分類目錄出現了標題重復,經檢查,是部分主題下,主題的代碼已經輸出了標題,而wordpress的代碼又再次輸出了一次。於是我們需要刪除wordpr

Linux基礎管理——文本處理(命令組合解決問題)

文本處理命令 grep 正則表達式 擴展正則表達式 前言: 在服務器中對日誌進行處理是十分常見的工作,所以運維對於各種文本工具來查看、分析、統計,是必備的基本工。那麽學習正則表達式、grep、egrep、和tr、sort、uniq等常見的文件處理命令就十分有必要了。1、工具分類 文

VMware虛擬機Mac OS X無法調整擴展硬盤大解決方案(轉)

一個 vmware 100g vmware虛擬機 顯示 class 0.10 針對 虛擬機 使用VMware虛擬機搭建的MacOSX,在10.10以上可能會出現無法擴充磁盤大小的問題。 因為很多朋友在初次安裝MacOSX的時候都默認選擇40G的磁盤大小,結果用了沒兩天之後

SpringBoot系列十一:SpringBoot整合Restful架構(使用 RestTemplate 模版實現 Rest 服務調用、Swagger 集成、動態修改日誌級別

attribute tar ring 動態修改 包含 分布式 restfu pen 負載 1、概念:SpringBoot整合Restful架構 2、背景 Spring 與 Restful 整合才是微架構的核心,雖然在整個 SpringBoot(SpringCloud)之中提

Logback中使用TurboFilter實現日誌級別等內容的動態修改

可能看到這個標題,讀者會問:要修改日誌的級別,不是直接修改log.xxx就好了嗎?為何要搞那麼複雜呢?所以,先說一下場景,為什麼要通過TurboFilter去動態的修改日誌級別。我們在使用Java開發各種專案的時候必然的會引入很多框架,這些框架通過堆疊的方式完成所要提供的業務服務(一個服務請求在進入後會在這些

iView Table元件寬度只變不變解決方案

示例: <Table class="my-table"></Table> 開啟開發者工具其實你可以發現iView給table標籤的寬度加上了一個明確的寬度值,而且在父元素變小的時候這個值並沒有相應地變小,所以才會導致的iView Table元件只

Java應用日誌級別異常處理最佳實踐

編者按:做了很多年IT工作,突然又對日誌級別有些迷茫,哈哈,為什麼要有又字。是的,人們都在實踐中不停的學習並增進自己。寫了好久的字,盯住看3分鐘,然後你會想,哦?寫錯了吧 ^_^ 日誌:我們應該做的更好了 我在說什麼?現在有大量的Java日誌框架和庫,大多數開發人員每天都

Spring Boot動態修改日誌級別

一 點睛 1 loggers端點 該端點將為我們提供動態修改Spring Boot應用日誌級別的強大功能。該功能的使用非常簡單,它依然延續了Spring Boot自動化配置的實現,所以只需要在引入了spring-boot-starter-actuator依賴的條件下就會自

通過jmx動態修改logback的日誌級別

應用上線後常常會面對這樣一種困境,即,如果把日誌級別開得太高,那麼當系統出現問題時不好查,如果把日誌級別定得太低,那麼硬碟很可能很快就被撐爆了。 這時候我們常常選擇先將日誌級別定高點,當出現問題時,再調低。大部分時候人們習慣的做法是修改logback.xm