成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

分布式調(diào)用跟蹤實戰(zhàn)

jlanglang / 2293人閱讀

摘要:為了追蹤一個請求完整的流轉(zhuǎn)過程,我可以給請求分配一個唯一的,當(dāng)請求調(diào)用其他服務(wù)時,我們傳遞這個。這是一個簡單的實現(xiàn)分布式調(diào)用追蹤的實踐,以上。

背景

分布式環(huán)境下,跨服務(wù)之間的調(diào)用錯綜復(fù)雜,如果突然爆出一個錯誤,雖然有日志記錄,但到底是哪個服務(wù)出了問題呢?是移動端傳的參數(shù)有錯誤,還是系統(tǒng)X或者系統(tǒng)Y提供的接口導(dǎo)致?在這種情況下,錯誤排查起來就非常費勁。

為了追蹤一個請求完整的流轉(zhuǎn)過程,我可以給請求分配一個唯一的traceId,當(dāng)請求調(diào)用其他服務(wù)時,我們傳遞這個traceId。在輸出日志時,將這個traceId打印到日志文件中,這樣,從日志文件中,根據(jù)traceId就可以分析一個請求完整的調(diào)用過程,若更進(jìn)一步,還可以做性能分析。

TraceID在Http服務(wù)中的實現(xiàn)

在一個服務(wù)的內(nèi)部,我們不希望在調(diào)用每個方法時,都帶上traceId這個參數(shù)(這樣實在太蠢了- . -)。

在Java中,我們一般將traceId放到ThreadLocal中,這樣在打印日志時,日志框架從ThreadLocal取出traceId,和其他需要打印的信息一起打印出來。這樣對框架的使用者來說,traceId就是透明的,并不需要去關(guān)注它。

我們來看代碼實現(xiàn):

/**
 * 建立日志MDC上下文屬性的攔截器
 */
public class WebLogMdcHandlerInterceptor extends HandlerInterceptorAdapter {

    /**
     * traceId一般由前端的負(fù)載生成,比如Nignx
     */
    private boolean generateTraceId = false;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String ctxTraceId = null;
        String ctxOpId = null;

        // 判斷Http header中是否有traceId字段,如果沒有,則通過隨機(jī)數(shù)生成
        if (StringUtils.isNotBlank(request.getHeader(Conventions.TRACE_ID_HEADER))) {
            ctxTraceId = request.getHeader(Conventions.TRACE_ID_HEADER);
        } else if (generateTraceId) {
            ctxTraceId = getTraceId();
        }

        ctxOpId = UUID.randomUUID().toString();
        MDC.put(Conventions.CTX_TRACE_ID_MDC, ctxTraceId + "," + ctxOpId);

        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        MDC.clear();
    }

    // 通過隨機(jī)數(shù)生成traceId,也可以通過其他方式實現(xiàn),只要保證唯一即可
    private static String getTraceId() {
        Random random = new Random();
        String rs1 = String.valueOf(random.nextInt(10000));
        String rs2 = String.valueOf(random.nextInt(10000));
        return rs1 + rs2;
    }

    public void setGenerateTraceId(boolean generateTraceId) {
        this.generateTraceId = generateTraceId;
    }
}

實現(xiàn)其實比較簡單,使用MDC(Mapped Diagnostic Contexts)來實現(xiàn),logbacklog4j支持MDC,MDC的底層實現(xiàn)其實很容易理解,就是通過ThreadLocal來維護(hù)key-value,源碼如下:

public final class LogbackMDCAdapter implements MDCAdapter {

    final InheritableThreadLocal> copyOnInheritThreadLocal = new InheritableThreadLocal>();
    ...
    ...
}

WebLogMdcHandlerInterceptor繼承了HandlerInterceptorAdapterHandlerInterceptorAdapter是一個攔截器適配器,我們實現(xiàn)了它其中的2個方法:

preHandle: 實現(xiàn)處理器的預(yù)處理

afterCompletion: 整個請求處理完畢回調(diào)方法,可以進(jìn)行一些資源清理

我們在afterCompletion方法中對MDC進(jìn)行了clear操作,底層調(diào)用了ThreadLocalremove方法,清除當(dāng)前線程中的線程局部變量。其作用有兩個,一是防止ThreadLocal導(dǎo)致的內(nèi)存溢出,二是Tomcat容器線程復(fù)用時,新請求會依舊使用原來的MDC中的traceId,會導(dǎo)致traceId的"串碼"現(xiàn)象。

我們再來講一下preHandle方法中的ctxOpId,即我們向MDC中不僅僅寫入http header中的traceId,還通過UUID生成了一個ctxOpId。

如上圖,A服務(wù)的某個方法連續(xù)調(diào)用了B服務(wù)的某個接口3次(可能是重試機(jī)制導(dǎo)致,也有可能確實是業(yè)務(wù)邏輯),如何區(qū)分這3次調(diào)用呢?只通過traceId無法區(qū)分,因為這三次的traceId都相同,所以每次調(diào)用時UUID生成ctxOpId,來區(qū)分這三次調(diào)用。

然后在logback.xml文件中配置pattern,如下:

%d %-5level [%X{ctxTraceId}][%thread] %logger{5} - %msg%n

具體打印日志時,會根據(jù)pattern格式打印,各字段的含義可自行百度。

最后,當(dāng)我們在調(diào)用其他Http服務(wù)時,先獲取當(dāng)前線程的ThreadLocal上下文,將traceId寫入http clientheader中,從而達(dá)到跨服務(wù)傳遞traceId。

這是一個簡單的實現(xiàn)分布式調(diào)用追蹤的實踐,以上。

原文鏈接

https://segmentfault.com/a/11...

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

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/70501.html

相關(guān)文章

  • Java調(diào)用跟蹤關(guān)鍵技術(shù)(一)總體介紹

    摘要:微服務(wù)中調(diào)用棧的獲取,使用的開發(fā)者會很自然想到用來攔截,但是攔截同一個類的多個方法之間的調(diào)用很不方便,有侵入性,因此并不適合。調(diào)用棧的跟蹤也提供了這個能力,可以獲得當(dāng)前方法的調(diào)用棧信息。 一、調(diào)用鏈跟蹤的作用 調(diào)用鏈跟蹤包括 1.前端到后端的調(diào)用鏈 2.單個服務(wù)內(nèi)部方法之間的調(diào)用鏈 3.微服務(wù)之間的調(diào)用鏈 4.應(yīng)用服務(wù)和數(shù)據(jù)庫之間的調(diào)用鏈 5.應(yīng)用服務(wù)和第三方服務(wù)中...

    gaara 評論0 收藏0
  • Java調(diào)用跟蹤關(guān)鍵技術(shù)(三)線程變量

    摘要:除了以上級別的成員變量共享,在調(diào)用鏈跟蹤時要能識別不同分層下的多個類實例的調(diào)用是同一個請求,而這個請求的調(diào)用都在一個獨立線程內(nèi)完成,此時就要用到線程級變量共享。 一、Java類成員作用域 JAVA類成員作用域參考下圖: showImg(https://segmentfault.com/img/bVbvWlh?w=1695&h=925); Java虛擬機(jī)級作用域,通過在類成員變量前加...

    ThreeWords 評論0 收藏0
  • Web全棧應(yīng)用之旅-啟程篇

    摘要:但能拷貝圖粘貼后不失真通常是收費富文本編輯器才具備的能力。是否支持編程語言高亮,例如按,語言高亮是否支持?jǐn)?shù)學(xué)公式等等因此選擇了兩款富文本編輯器,支持截屏粘貼,當(dāng)做跟蹤系統(tǒng)時這個功能特別有用。 一、Web應(yīng)用技術(shù)棧 在開發(fā)Web應(yīng)用時,通常會使用到以下技術(shù)棧: showImg(https://segmentfault.com/img/bVbwceG);對應(yīng)這些技術(shù)棧都已有相應(yīng)的開源產(chǎn)品...

    longmon 評論0 收藏0
  • Flink實戰(zhàn)(八) - Streaming Connectors 編程

    摘要:默認(rèn)情況下,當(dāng)數(shù)據(jù)元到達(dá)時,分段接收器將按當(dāng)前系統(tǒng)時間拆分,并使用日期時間模式命名存儲區(qū)。如果需要,可以使用數(shù)據(jù)元或元組的屬性來確定目錄。這將調(diào)用傳入的數(shù)據(jù)元并將它們寫入部分文件,由換行符分隔。消費者的消費者被稱為或等。 1 概覽 1.1 預(yù)定義的源和接收器 Flink內(nèi)置了一些基本數(shù)據(jù)源和接收器,并且始終可用。該預(yù)定義的數(shù)據(jù)源包括文件,目錄和插socket,并從集合和迭代器攝取數(shù)據(jù)...

    beita 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<