手寫鏈路追蹤

1. 什么是鏈路追蹤

鏈路追蹤是指在分布式系統中,將一次請求的處理過程進行記錄并聚合展示的一種方法。目的是將一次分布式請求的調用情況集中在一處展示,如各個服務節點上的耗時、請求具體到達哪臺機器上、每個服務節點的請求狀態等。這樣就可以輕松了解一個請求在系統中的完整生命周期,包括經過的服務、調用的操作以及每個操作的延遲等。通過鏈路追蹤,可以更好地理解系統的性能瓶頸、找出問題的根源以及優化系統的性能。
如下圖就是一個簡單的微服務中的調用過程,如果我們沒有鏈路追蹤,且每個服務都是一個多節點集群,想要搞清楚一個請求是怎么走的就非常困難。
鏈路追蹤

2. 鏈路追蹤的重要性

在分布式系統中,由于服務節點眾多且相互之間存在復雜的依賴關系,所以一旦出現故障,排查起來往往非常困難。而鏈路追蹤可以有效地幫助解決這個問題。具體是以下幾個方面:

快速定位問題:當應用程序出現故障時,開發人員可以通過鏈路追蹤來快速定位到故障的原因。通過查看元數據,可以確定故障發生的位置以及導致故障的請求數據,加速故障的排查過程。

優化程序性能:鏈路追蹤可以幫助開發人員分析應用程序的性能瓶頸。通過觀察數據在各個節點之間的流動情況,可以確定哪些節點的性能較差,并針對這些節點進行優化。

分析安全問題:通過觀察數據在系統中的流動情況,可以發現潛在的安全漏洞和攻擊路徑,例如DDoS攻擊、中間人攻擊、SQL注入攻擊等。有助于提高系統的安全性,并減少潛在的安全風險。

3. 鏈路追蹤的實現

鏈路追蹤的實現方式很多,你可以通過不同工具去實現。
如果你的微服務用的是Spring Cloud, 其實spring cloud已經有很完美的解決方案。
Spring Cloud 鏈路追蹤通常使用 Spring Cloud Sleuth 來實現。Spring Cloud Sleuth 集成了 Zipkin 和 Brave 來提供鏈路追蹤功能。
但是也有很多微服務沒有用Spring Cloud,如果我們只需要簡單的鏈路追蹤,也可以自己手寫一份實現。
手寫也不復雜,但是需要實現的人考慮周全,把鏈路追蹤寫好一點。本篇及后續篇章主要介紹手寫的不同實現方式。
鏈路追蹤的核心是日志追蹤,下面我們嘗試用代碼來實現日志追蹤。

3.1 實現一個API接口

模擬一個登錄接口API。 API包含如下實現

  • API接口參數包括request body;
  • 能接收可能包含trace id的header;
  • 讀取當前線程名(用于線程結束前還原線程名);
  • 如果請求頭中沒有包含trace id, 自動生成一個;
  • 在請求開始的時候替換當前線程名,直到維持到請求結束前,用于修改日志文件的線程名,用它來做日志信息追蹤;
  • 用一個for loop模擬登錄過程的日志
package com.sandwich.logtracing.controller;import com.sandwich.logtracing.entity.ApiResponse;
import com.sandwich.logtracing.util.RandomStrUtils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;/*** @Author 公眾號: IT三明治* @Date 2025/8/29* @Description: login demo controller*/
@Slf4j
@RestController
@RequestMapping("/test")
public class LoginController {@PostMapping("/login")public ApiResponse<String> login(@RequestBody LoginRequest loginRequest,@RequestHeader(value = "x-request-correlation-id", required = false) String traceId) {String currentThreadName = Thread.currentThread().getName();//if the request header don't have a trace id,then generate a random oneif (StringUtils.isBlank(traceId)) {traceId = RandomStrUtils.generateRandomString(15);}//replace current thread name with a trace idThread.currentThread().setName(traceId);log.info("previous thread name:{}", currentThreadName);for (int i=1; i<= 10; i++) {log.info("processing login for user {}, login step {} done", loginRequest.getUsername(), i);}log.info("user {} login success", loginRequest.getUsername());//restore thread name before api request endThread.currentThread().setName(currentThreadName);return ApiResponse.success("Sandwich login success", traceId);}@Datapublic static class LoginRequest {private String username;private String password;}
}

3.2 定義一個response entity

這個entity跟其他response不同之處在于它除了能支持一個泛型的data,還可以支持trace id返回

package com.sandwich.logtracing.entity;import lombok.Data;
import lombok.experimental.Accessors;/*** @Author 公眾號: IT三明治* @Date 2025/8/29* @Description: api response entity*/
@Data
@Accessors(chain = true)
public class ApiResponse<T> {private int responseCode;private String message;private T data;private String traceId;public static  <T> ApiResponse<T> success(T data, String traceId) {return new ApiResponse<T>().setResponseCode(ResponseCode.SUCCESS.getCode()).setMessage(ResponseCode.SUCCESS.getMessage()).setData(data).setTraceId(traceId);}public static ApiResponse<String> success() {return new ApiResponse<String>().setResponseCode(ResponseCode.SUCCESS.getCode()).setMessage(ResponseCode.SUCCESS.getMessage());}public static  <T> ApiResponse<T> success(T data) {return new ApiResponse<T>().setResponseCode(ResponseCode.SUCCESS.getCode()).setMessage(ResponseCode.SUCCESS.getMessage()).setData(data);}}

準備一個枚舉保存response code和對應的message, 這個demo我只用一個success的

package com.sandwich.logtracing.constant;import lombok.Getter;/*** @Author 公眾號: IT三明治* @Date 2025/8/29* @Description:*/
@Getter
public enum ResponseCode {SUCCESS(200, "success"),FAIL(500, "internal error"),NOT_FOUND(404, "not found"),UNAUTHORIZED(401, "unauthorized"),FORBIDDEN(403, "forbidden"),NOT_ACCEPTABLE(406, "not acceptable"),REQUEST_TIMEOUT(408, "request timeout"),CONFLICT(409, "conflict"),UNSUPPORTED_MEDIA_TYPE(415, "unsupported media type"),TOO_MANY_REQUESTS(429, "too many requests");private final int code;private final String message;ResponseCode(int code, String message) {this.code = code;this.message = message;}
}

3.3 用shell寫一個api請求(login.shell)

為了更好地展示api的所有信息,我選擇用shell完成api請求,shell需要完成的功能如下:

  • 自動生成trace id
  • 自動組裝api request,包括請求數據類型,header, payload
  • 用python格式化返回的json結構體
#!/bin/bash# Define the API endpoint
API_URL="http://localhost:8080/test/login"function generate_random_string() {# 使用openssl生成隨機字符串(如果已安裝)if command -v openssl &> /dev/null; thenopenssl rand -base64 20 | tr -dc 'a-zA-Z0-9' | fold -w 15 | head -n 1else# 使用系統方法生成local chars="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"local result=""result=$(printf "%s" "${chars:$((RANDOM % ${#chars})):1}"{1..15} | tr -d '\n')echo "$result"fi
}function normalLogin() {# 生成15位隨機字符串作為traceIdtraceId=$(generate_random_string)response=$(curl -X POST $API_URL \-H "Content-Type: application/json" \-H "x-request-correlation-id: $traceId" \-d '{"username": "Sandwich", "password": "test"}')echo "Response from login API:"echo "$response" | python -m json.tool
}normalLogin

4. 測試驗證

  • 啟動項目
  • 執行請求
Administrator@USER-20230930SH MINGW64 /d/git/java/log-tracing/shell (master)
$ ./login.sh% Total    % Received % Xferd  Average Speed   Time    Time     Time  CurrentDload  Upload   Total   Spent    Left  Speed
100   144    0   100  100    44    493    217 --:--:-- --:--:-- --:--:--   712
Response from login API:
{"responseCode": 200,"message": "success","data": "Sandwich login success","traceId": "wwDJbM12XdX562A"
}
  • 用trace id追蹤日志信息

5. 總結

這就是一個最小的鏈路追蹤過程,非常簡單,我連日志管理文件都沒有配置,只用了springboot 默認的日志系統。

無疑它是非常不完善的,請關注我,下期我再逐步優化它。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/94943.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/94943.shtml
英文地址,請注明出處:http://en.pswp.cn/web/94943.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

從零開始的python學習——常量與變量

? ? ? ? ? づ?ど &#x1f389; 歡迎點贊支持&#x1f389; 個人主頁&#xff1a;勵志不掉頭發的內向程序員&#xff1b; 專欄主頁&#xff1a;python學習專欄&#xff1b; 文章目錄 前言 一、常量和表達式 二、變量類型 2.1、什么是變量 2.2、變量語法 &#xff08;1&a…

基于51單片機環境監測設計 光照 PM2.5粉塵 溫濕度 2.4G無線通信

1 系統功能介紹 本設計是一套 基于51單片機的環境監測系統&#xff0c;能夠實時采集環境光照、PM2.5、溫濕度等參數&#xff0c;并通過 2.4G無線模塊 NRF24L01 實現數據傳輸。系統具備本地顯示與報警功能&#xff0c;可通過按鍵設置各類閾值和時間&#xff0c;方便用戶進行環境…

【Flask】測試平臺開發,產品管理實現添加功能-第五篇

概述在前面的幾篇開發文章中&#xff0c;我們只是讓數據在界面上進行了展示&#xff0c;但是沒有添加按鈕的功能&#xff0c;接下來我們需要開發一個添加的按鈕&#xff0c;用戶產品功能的創建和添加抽公共數據鏈接方法添加接口掌握post實現和請求數據處理前端掌握Button\Dilog…

循環高級(2)

6.練習3 打印九九乘法表7.練習3 制表符詳解對齊不了原因&#xff1a;name補到8zhangsan本身就是8&#xff0c;補完就變成16解決辦法&#xff1a;1.去掉zhangsan\t,這樣前后都是82.name后面加2個\t加一個\t&#xff0c;name\t就是占8個&#xff0c;再加一個\t&#xff0c;就變成…

盒馬生鮮 小程序 逆向分析

聲明 本文章中所有內容僅供學習交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包內容、敏感網址、數據接口等均已做脫敏處理&#xff0c;嚴禁用于商業用途和非法用途&#xff0c;否則由此產生的一切后果均與作者無關&#xff01; 逆向分析 部分python代碼 params {&…

【Linux系統】線程控制

1. POSIX線程庫 (pthreads)POSIX線程&#xff08;通常稱為pthreads&#xff09;是IEEE制定的操作系統線程API標準。Linux系統通過glibc庫實現了這個標準&#xff0c;提供了創建和管理線程的一系列函數。核心特性命名約定&#xff1a;絕大多數函數都以 pthread_ 開頭&#xff0c…

【Spring Cloud Alibaba】前置知識

【Spring Cloud Alibaba】前置知識1. 微服務介紹1.1 系統架構的演變1.1.1 單體應用架構1.1.2 垂直應用架構1.1.3 分布式架構1.1.3.1 SOA架構1.1.4 微服務架構1. 微服務介紹 1.1 系統架構的演變 隨著互聯網的發展&#xff0c;網站應用的規模也在不斷的擴大&#xff0c;進而導致…

2025互聯網大廠Java面試1000道題目及參考答案

Java學到什么程度可以面試工作&#xff1f; 要達到能夠面試Java開發工作的水平&#xff0c;需要掌握以下幾個方面的知識和技能&#xff1a; 1. 基礎扎實&#xff1a;熟悉Java語法、面向對象編程概念、異常處理、I/O流等基礎知識。這是所有Java開發者必備的基礎&#xff0c;也…

記錄:HSD部署(未完成)

建數據庫 相關文檔&#xff1a;Confluence準備&#xff1a;CA文件和備份用的aws key。 CA文件&#xff1a;在namespace添加trust-injectionenabled的標簽&#xff0c;會自動生成。 aws key&#xff1a;生成cnpg-backup-creds的secret。安裝&#xff1a; 從git倉庫獲取values模…

【AI】提示詞與自然語言處理:從NLP視角看提示詞的作用機制

提示詞與自然語言處理&#xff1a;從 NLP 視角看提示詞的作用機制在人工智能快速發展的今天&#xff0c;大模型成為了人們關注的焦點。而要讓大模型更好地理解人類意圖、完成各種任務&#xff0c;提示詞扮演著關鍵角色。從自然語言處理&#xff08;NLP&#xff09;的角度來看&a…

2025.8.29機械臂實戰項目

好久沒給大家更新了&#xff0c;上周末大學大四開學&#xff0c;所以停更了幾天&#xff0c;回來后在做項目&#xff0c;接下來的幾篇文章&#xff0c;給大家帶來幾個項目&#xff0c;第一個介紹的是機械臂操作&#xff0c;說是機械臂操作&#xff0c;簡單來說&#xff0c;就是…

【機器學習基礎】機器學習的要素:任務T、性能度量P和經驗E

第一章 機器學習的本質與理論框架 機器學習作為人工智能領域的核心支柱,其理論基礎可以追溯到20世紀中葉的統計學習理論。Tom Mitchell在其1997年的經典著作《Machine Learning》中給出了一個至今仍被廣泛引用的學習定義:"對于某類任務T和性能度量P,一個計算機程序被認…

wav音頻轉C語言樣點數組

WAV to C Header Converter 將WAV音頻文件轉換為C語言頭文件的Python腳本&#xff0c;支持將音頻數據嵌入到C/C項目中。 功能特性 音頻格式支持 PCM格式&#xff1a;支持8位、16位、24位、32位PCM音頻IEEE Float格式&#xff1a;支持32位浮點音頻多聲道&#xff1a;支持單聲道、…

01.《基礎入門:了解網絡的基本概念》

網絡基礎 文章目錄網絡基礎網絡通信核心原理網絡通信定義信息傳遞過程關鍵術語解釋網絡的分類網絡參考模型OSI 參考模型各層核心工作分層核心原則TCP/IP 參考模型&#xff08;4 層 / 5 層&#xff0c;實際應用模型&#xff09;TCP/IP 與 OSI 模型的對應關系傳輸層核心協議&…

基于vue駕校管理系統的設計與實現5hl93(程序+源碼+數據庫+調試部署+開發環境)帶論文文檔1萬字以上,文末可獲取,系統界面在最后面。

系統程序文件列表&#xff1a;項目功能&#xff1a;學員,教練,教練信息,預約信息,場地信息,時間安排,車輛信息,預約練車,時間段,駕校場地信息,駕校車輛信息,預約報名開題報告內容&#xff1a;一、選題背景與意義背景隨著汽車保有量持續增長&#xff0c;駕校行業規模不斷擴大&am…

灰度思維:解鎖世界原有本色的密碼

摘要本文深入探討灰度思維的概念內涵及其在處理他人評價中的應用價值。研究指出&#xff0c;灰度思維作為一種超越非黑即白的思維方式&#xff0c;能夠幫助個體以更客觀、全面的態度接受他人評價的片面性&#xff0c;從而促進個人成長和人際關系和諧。文章分析了他人評價片面性…

動態規劃--Day03--打家劫舍--198. 打家劫舍,213. 打家劫舍 II,2320. 統計放置房子的方式數

動態規劃–Day03–打家劫舍–198. 打家劫舍&#xff0c;213. 打家劫舍 II&#xff0c;2320. 統計放置房子的方式數 今天要訓練的題目類型是&#xff1a;【打家劫舍】&#xff0c;題單來自靈艾山茶府。 掌握動態規劃&#xff08;DP&#xff09;是沒有捷徑的&#xff0c;咱們唯一…

Nuxt.js@4 中管理 HTML <head> 標簽

可以在 nuxt.config.ts 中配置全局的 HTML 標簽&#xff0c;也可以在指定 index.vue 頁面中配置指定的 HTML 標簽。 在 nuxt.config.ts 中配置 HTML 標簽 export default defineNuxtConfig({compatibilityDate: 2025-07-15,devtools: { enabled: true },app: {head: {charse…

UCIE Specification詳解(十)

文章目錄4.5.3.7 PHYRETRAIN&#xff08;物理層重訓練&#xff09;4.5.3.7.1 Adapter initiated PHY retrain4.5.3.7.2 PHY initiated PHY retrain4.5.3.7.3 Remote Die requested PHY retrain4.5.3.8 TRAIN ERROR4.5.3.9 L1/L24.6 Runtime Recalibration4.7 Multi-module Link…

電商數據的獲取方式:API、爬蟲、第三方服務及更多

在競爭激烈的電商領域&#xff0c;數據是驅動業務增長的關鍵。準確、及時地獲取電商數據&#xff0c;并進行深入分析&#xff0c;能夠幫助企業洞察市場趨勢、優化運營策略、提升用戶體驗。本文將全面介紹電商數據的獲取方式&#xff0c;涵蓋API接口、網絡爬蟲技術、第三方數據服…