亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

日志排查問題困難?分布式日志鏈路跟蹤來幫你

EasonTyler / 2568人閱讀

摘要:當(dāng)前線程的子線程會繼承其父線程中的的內(nèi)容。若希望在線程池與主線程間傳遞,需配合和使用。

一、背景

開發(fā)排查系統(tǒng)問題用得最多的手段就是查看系統(tǒng)日志,在分布式環(huán)境中一般使用ELK來統(tǒng)一收集日志,但是在并發(fā)大時使用日志定位問題還是比較麻煩,由于大量的其他用戶/其他線程的日志也一起輸出穿行其中導(dǎo)致很難篩選出指定請求的全部相關(guān)日志,以及下游線程/服務(wù)對應(yīng)的日志。

?

二、解決思路

每個請求都使用一個唯一標(biāo)識來追蹤全部的鏈路顯示在日志中,并且不修改原有的打印方式(代碼無入侵)

使用Logback的MDC機(jī)制日志模板中加入traceId標(biāo)識,取值方式為%X{traceId}

MDC(Mapped Diagnostic Context,映射調(diào)試上下文)是 log4j 和 logback 提供的一種方便在多線程條件下記錄日志的功能。MDC 可以看成是一個與當(dāng)前線程綁定的Map,可以往其中添加鍵值對。MDC 中包含的內(nèi)容可以被同一線程中執(zhí)行的代碼所訪問。當(dāng)前線程的子線程會繼承其父線程中的 MDC 的內(nèi)容。當(dāng)需要記錄日志時,只需要從 MDC 中獲取所需的信息即可。MDC 的內(nèi)容則由程序在適當(dāng)?shù)臅r候保存進(jìn)去。對于一個 Web 應(yīng)用來說,通常是在請求被處理的最開始保存這些數(shù)據(jù)。

?

三、方案實(shí)現(xiàn)

由于MDC內(nèi)部使用的是ThreadLocal所以只有本線程才有效,子線程和下游的服務(wù)MDC里的值會丟失;所以方案主要的難點(diǎn)是解決值的傳遞問題,主要包括以幾下部分:

API網(wǎng)關(guān)中的MDC數(shù)據(jù)如何傳遞給下游服務(wù)

服務(wù)如何接收數(shù)據(jù),并且調(diào)用其他遠(yuǎn)程服務(wù)時如何繼續(xù)傳遞

異步的情況下(線程池)如何傳給子線程

3.1. 修改日志模板

logback配置文件模板格式添加標(biāo)識%X{traceId}

?

3.2. 網(wǎng)關(guān)添加過濾器

生成traceId并通過header傳遞給下游服務(wù)

@Component
public class TraceFilter extends ZuulFilter {
    @Autowired
    private TraceProperties traceProperties;

    @Override
    public String filterType() {
        return FilterConstants.PRE_TYPE;
    }

    @Override
    public int filterOrder() {
        return FORM_BODY_WRAPPER_FILTER_ORDER - 1;
    }

    @Override
    public boolean shouldFilter() {
        //根據(jù)配置控制是否開啟過濾器
        return traceProperties.getEnable();
    }

    @Override
    public Object run() {
        //鏈路追蹤id
        String traceId = IdUtil.fastSimpleUUID();
        MDC.put(CommonConstant.LOG_TRACE_ID, traceId);
        RequestContext ctx = RequestContext.getCurrentContext();
        ctx.addZuulRequestHeader(CommonConstant.TRACE_ID_HEADER, traceId);
        return null;
    }
}

?

3.3. 下游服務(wù)增加spring攔截器

接收并保存traceId的值
攔截器

public class TraceInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String traceId = request.getHeader(CommonConstant.TRACE_ID_HEADER);
        if (StrUtil.isNotEmpty(traceId)) {
            MDC.put(CommonConstant.LOG_TRACE_ID, traceId);
        }
        return true;
    }
}

注冊攔截器

public class DefaultWebMvcConfig extends WebMvcConfigurationSupport {
  @Override
  protected void addInterceptors(InterceptorRegistry registry) {
    //日志鏈路追蹤攔截器
    registry.addInterceptor(new TraceInterceptor()).addPathPatterns("/**");

    super.addInterceptors(registry);
  }
}

?

3.4. 下游服務(wù)增加feign攔截器

繼續(xù)把當(dāng)前服務(wù)的traceId值傳遞給下游服務(wù)

public class FeignInterceptorConfig {
    @Bean
    public RequestInterceptor requestInterceptor() {
        RequestInterceptor requestInterceptor = template -> {
            //傳遞日志traceId
            String traceId = MDC.get(CommonConstant.LOG_TRACE_ID);
            if (StrUtil.isNotEmpty(traceId)) {
                template.header(CommonConstant.TRACE_ID_HEADER, traceId);
            }
        };
        return requestInterceptor;
    }
}

?

3.5. 解決父子線程傳遞問題

主要針對業(yè)務(wù)會使用線程池(異步、并行處理),并且spring自己也有@Async注解來使用線程池,要解決這個問題需要以下兩個步驟

3.5.1. 重寫logback的LogbackMDCAdapter

由于logback的MDC實(shí)現(xiàn)內(nèi)部使用的是ThreadLocal不能傳遞子線程,所以需要重寫替換為阿里的TransmittableThreadLocal

TransmittableThreadLocal 是Alibaba開源的、用于解決 “在使用線程池等會緩存線程的組件情況下傳遞ThreadLocal” 問題的 InheritableThreadLocal 擴(kuò)展。若希望 TransmittableThreadLocal 在線程池與主線程間傳遞,需配合 TtlRunnableTtlCallable 使用。

TtlMDCAdapter類

package org.slf4j;

import com.alibaba.ttl.TransmittableThreadLocal;
import org.slf4j.spi.MDCAdapter;

public class TtlMDCAdapter implements MDCAdapter {
    /**
     * 此處是關(guān)鍵
     */
    private final ThreadLocal> copyOnInheritThreadLocal = new TransmittableThreadLocal<>();

    private static TtlMDCAdapter mtcMDCAdapter;

    static {
        mtcMDCAdapter = new TtlMDCAdapter();
        MDC.mdcAdapter = mtcMDCAdapter;
    }

    public static MDCAdapter getInstance() {
        return mtcMDCAdapter;
    }
其他代碼與ch.qos.logback.classic.util.LogbackMDCAdapter一樣,只需改為調(diào)用copyOnInheritThreadLocal變量

?
TtlMDCAdapterInitializer類用于程序啟動時加載自己的mdcAdapter實(shí)現(xiàn)

public class TtlMDCAdapterInitializer implements ApplicationContextInitializer {
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        //加載TtlMDCAdapter實(shí)例
        TtlMDCAdapter.getInstance();
    }
}

?

3.5.2. 擴(kuò)展線程池實(shí)現(xiàn)

增加TtlRunnableTtlCallable擴(kuò)展實(shí)現(xiàn)TTL

public class CustomThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {
    @Override
    public void execute(Runnable runnable) {
        Runnable ttlRunnable = TtlRunnable.get(runnable);
        super.execute(ttlRunnable);
    }

    @Override
    public  Future submit(Callable task) {
        Callable ttlCallable = TtlCallable.get(task);
        return super.submit(ttlCallable);
    }

    @Override
    public Future submit(Runnable task) {
        Runnable ttlRunnable = TtlRunnable.get(task);
        return super.submit(ttlRunnable);
    }

    @Override
    public ListenableFuture submitListenable(Runnable task) {
        Runnable ttlRunnable = TtlRunnable.get(task);
        return super.submitListenable(ttlRunnable);
    }

    @Override
    public  ListenableFuture submitListenable(Callable task) {
        Callable ttlCallable = TtlCallable.get(task);
        return super.submitListenable(ttlCallable);
    }
}

?

四、場景測試 4.1. 測試代碼如下


?

4.2. api網(wǎng)關(guān)打印的日志

網(wǎng)關(guān)生成traceId值為13d9800c8c7944c78a06ce28c36de670

?

4.3. 請求跳轉(zhuǎn)到文件服務(wù)時打印的日志

顯示的traceId與網(wǎng)關(guān)相同,這里特意模擬發(fā)生異常的場景

?

4.4. ELK聚合日志通過traceId查詢整條鏈路日志

當(dāng)系統(tǒng)出現(xiàn)異常時,可直接通過該異常日志的traceId?的值,在日志中心中詢該請求的所有日志信息

?

五、源碼下載

附上我的開源微服務(wù)框架(包含本文中的代碼),歡迎 star 關(guān)注

https://gitee.com/zlt2000/mic...

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/76187.html

相關(guān)文章

  • 2017雙11技術(shù)揭秘—雙十一海量數(shù)據(jù)下EagleEye的使命和挑戰(zhàn)

    摘要:今年的無論是常態(tài)全鏈路壓測或者是雙十一當(dāng)天,面臨的主要問題是如何保障自身系統(tǒng)在海量數(shù)據(jù)沖擊下的穩(wěn)定性,以及如何更快的展現(xiàn)各個系統(tǒng)的狀態(tài)及更好的幫助開發(fā)同學(xué)發(fā)現(xiàn)及定位問題。在整個雙十一備戰(zhàn)過程中,遇到并解決了很多疑難雜癥。 摘要: EagleEye作為阿里集團(tuán)老牌的鏈路跟蹤系統(tǒng),其自身業(yè)務(wù)雖不在交易鏈路上,但卻監(jiān)控著全集團(tuán)的鏈路狀態(tài),特別是在中間件的遠(yuǎn)程調(diào)用上,覆蓋了集團(tuán)絕大部分的場景,...

    ssshooter 評論0 收藏0
  • 余額寶11.11:基于日志數(shù)據(jù)分析的高效運(yùn)維

    摘要:接下來我們以余額寶為例,重點(diǎn)剖析天弘基金在日志數(shù)據(jù)分析領(lǐng)域是如何突破的此前,天弘基金一直使用開源的日志方案,研發(fā)和運(yùn)維人員通過對日志數(shù)據(jù)進(jìn)行處理,使用日志文件進(jìn)行查詢檢索。 雙十一剛剛結(jié)束,其實(shí)最緊張的不是商鋪理貨,也不是網(wǎng)友緊盯大促商品準(zhǔn)備秒殺,而是網(wǎng)購幕后的運(yùn)維人員,他們最擔(dān)心:什么網(wǎng)絡(luò)中斷、應(yīng)用卡頓、響應(yīng)速度慢,服務(wù)器宕機(jī)……雙十一作為電商 IT 部門的頭等大事,大促前,運(yùn)維人員就需要...

    wenshi11019 評論0 收藏0
  • 筆記|軟件調(diào)試的技巧

    摘要:在軟件世界里,觀察意味著設(shè)置斷點(diǎn)添加調(diào)試語句監(jiān)視程序值以及檢查內(nèi)存在醫(yī)學(xué)領(lǐng)域,需要測試血樣和進(jìn)行光透視。福爾摩斯,最后一案如果你不修復(fù),它不會自動消失。修復(fù)解決問題的能力,是軟件工程師的核心競爭力之一。 這篇文章是《調(diào)試九法:軟硬件錯誤的排查之道》的閱讀筆記。這本書的主旨,是介紹如何修復(fù)bug:找出bug發(fā)生的原因、并給出修復(fù)方案。 調(diào)試bug的九個規(guī)則列舉如下,建議將這個清單打印出來...

    DirtyMind 評論0 收藏0
  • 阿里云 APM 解決方案地圖

    摘要:阿里云上領(lǐng)域各個產(chǎn)品最終目標(biāo)是為了對以上各個組件進(jìn)行有效監(jiān)控。阿里云的解決方案地圖基于今天的云上的應(yīng)用架構(gòu),阿里云的解決方案地圖如下所示。其他阿里云服務(wù)包括緩存,等。阿里云解決方案地圖以下表格對阿里云解決方案進(jìn)行總結(jié)。 摘要: PM是近5年來伴隨著云技術(shù)、微服務(wù)架構(gòu)發(fā)展起來的一個新興監(jiān)控領(lǐng)域。在國內(nèi)外,無論是云廠商(如AWS, Azure,等)還是獨(dú)立的公司(Dynatrace, Ap...

    tainzhi 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<