Go從入門到精通(25) - 一個簡單web項目-實現鏈路跟蹤

Go從入門到精通(25)

一個簡單web項目-實現鏈路跟蹤


文章目錄

  • Go從入門到精通(25)
  • 前言
  • 為什么需要分布式鏈路跟蹤?
  • go實現鏈路跟蹤
    • 搭建zipkin 服務
    • 安裝依賴
    • 添加tracing包,OpenTelemetry 和Zipkin
    • 在 Gin 中集成 OpenTelemetry 中間件
    • log包添加獲取traceId方法
    • 日志打印加入traceId
    • sql 操作加入鏈路跟蹤
    • 客戶端請求傳遞追蹤上下文
    • 關鍵點總結


前言

分布式鏈路跟蹤技術(Distributed Tracing)是分布式系統(尤其是微服務架構)中用于追蹤請求全鏈路流轉的核心技術。它通過記錄請求在多個服務間的傳播路徑、執行耗時、狀態等信息,幫助開發者定位跨服務調用的性能瓶頸、故障點和依賴關系,是保障分布式系統可觀測性(Observability)的三大支柱之一(另外兩個是日志和指標)。


為什么需要分布式鏈路跟蹤?

在單體應用中,一個請求的處理流程在單一進程內完成,通過日志即可定位問題;但在分布式系統(如微服務)中,一個用戶請求可能經歷以下流程:

客戶端 → API網關 → 認證服務 → 訂單服務 → 庫存服務 → 數據庫 → 緩存

這種場景下,傳統調試方式面臨三大挑戰:

  • 鏈路斷裂:無法確定請求經過了哪些服務、調用順序如何;
  • 責任模糊:某個請求超時 / 失敗時,無法判斷是哪個服務導致(如訂單服務本身慢,還是依賴的庫存服務響應延遲);
  • 性能盲區:無法量化各服務的耗時占比(如 90% 的耗時在數據庫,還是在網絡傳輸)。
    分布式鏈路跟蹤技術通過全鏈路數據采集與可視化,解決了這些問題。

go實現鏈路跟蹤

這里以 OpenTelemetry+Zipkin為例實現鏈路跟蹤

搭建zipkin 服務

一般公司會統一搭建zipkin服務,自行搭建參考官網

安裝依賴

go get “go.opentelemetry.io/contrib/propagators/b3”
go get “go.opentelemetry.io/otel”
go get “go.opentelemetry.io/otel/exporters/zipkin”
go get “go.opentelemetry.io/otel/propagation”
go get “go.opentelemetry.io/otel/sdk/resource”
go get “go.opentelemetry.io/otel/sdk/trace”
go get go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin

添加tracing包,OpenTelemetry 和Zipkin

//tracing/tracing.go
package tracingimport ("go-web-demo/logger""go.opentelemetry.io/contrib/propagators/b3""go.opentelemetry.io/otel""go.opentelemetry.io/otel/exporters/zipkin""go.opentelemetry.io/otel/propagation""go.opentelemetry.io/otel/sdk/resource""go.opentelemetry.io/otel/sdk/trace"semconv "go.opentelemetry.io/otel/semconv/v1.30.0"oteltrace "go.opentelemetry.io/otel/trace""go.uber.org/zap""os"
)var (tracer oteltrace.Tracer
)func InitTracer() error {// 初始化鏈路跟蹤zipkinEndpoint := os.Getenv("ZIPKIN_ENDPOINT")if zipkinEndpoint == "" {logger.Sugar.Warn("ZIPKIN_ENDPOINT 未設置,鏈路跟蹤將被禁用")return nil}zipkinExporter, err := zipkin.New(zipkinEndpoint)if err != nil {zap.L().Error("Failed to create Zipkin exporter", zap.Error(err))return err}tp := trace.NewTracerProvider(trace.WithSampler(trace.AlwaysSample()),trace.WithBatcher(zipkinExporter),trace.WithResource(resource.NewWithAttributes(semconv.SchemaURL, semconv.ServiceName("go-web-demo"))),)otel.SetTracerProvider(tp)// 創建專門的W3C propagatorw3cPropagator := propagation.TraceContext{}// 創建B3 propagator,同時支持單頭和多頭格式b3Propagator := b3.New(b3.WithInjectEncoding(b3.B3MultipleHeader | b3.B3SingleHeader),)otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(w3cPropagator, b3Propagator, propagation.TraceContext{}, propagation.Baggage{}))tracer = otel.Tracer("go-web-demo")logger.Sugar.Infow("Zipkin 鏈路跟蹤初始化成功,服務名: %s,端點: %s", "go-web-demo", zipkinEndpoint)return nil
}
  • zipkinEndpoint 來源于你搭建的服務地址
  • trace.WithSampler(trace.AlwaysSample()) 這里使用100%采樣,如果生成環境可以做適當的調整,比如0.1
sampler := sdktrace.TraceIDRatioBased(0.1) // 采樣率10%

在 Gin 中集成 OpenTelemetry 中間件

import "go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin"// 創建默認引擎,包含日志和恢復中間件router := gin.Default()// 添加Zipkin中間件router.Use(otelgin.Middleware("go-web-demo")) //其他之前的邏輯。。

log包添加獲取traceId方法

func WithTraceCtx(ctx context.Context) *zap.Logger {span := trace.SpanFromContext(ctx)if !span.SpanContext().IsValid() {return Logger}traceID := span.SpanContext().TraceID().String()spanID := span.SpanContext().SpanID().String()return Logger.With(zap.String("traceId", traceID),zap.String("spanId", spanID),)
}

日志打印加入traceId

func HealthHandler(c *gin.Context) {ctx := c.Request.Context()logger.WithTraceCtx(ctx).Info("health check")c.JSON(http.StatusOK, gin.H{"message": "success"})
}

日志打印效果

{"service": "user-api", "traceId": "579ec5e6c0a21967e628266103499008", "spanId": "9053af570d799499"}

當然我們也可以在zipkin服務器查看,把我們日志的traceId輸入并且搜索就可以得到類型下圖的效果。大家也可以多搭建一個服務調用效果更佳
在這里插入圖片描述

sql 操作加入鏈路跟蹤

//repository/database_connection.go
package repositoryimport	gormTracing "gorm.io/plugin/opentelemetry/tracing"
func InitGormDB() error {//。。。 之前的的數據庫連接邏輯//添加鏈路跟蹤err = DB.Use(gormTracing.NewPlugin(//這里使用實際的數據類型,比如mysqlgormTracing.WithDBSystem(dbDriver),gormTracing.WithoutServerAddress(),))
}

客戶端請求傳遞追蹤上下文

// 調用其他服務并傳遞追蹤上下文
func callAnotherService(ctx context.Context, url string) (*http.Response, error) {// 從上下文中獲取當前spanspan := trace.SpanFromContext(ctx)// 創建HTTP請求req, err := http.NewRequestWithContext(ctx, "GET", url, nil)if err != nil {span.RecordError(err)span.SetStatus(codes.Error, err.Error())return nil, err}// 使用OpenTelemetry傳播器將上下文注入到請求頭otel.GetTextMapPropagator().Inject(ctx,propagation.HeaderCarrier(req.Header),)// 發送請求client := &http.Client{}resp, err := client.Do(req)if err != nil {span.RecordError(err)span.SetStatus(codes.Error, err.Error())return nil, err}// 記錄響應狀態span.SetAttributes(attribute.Int("http.status_code", resp.StatusCode))if resp.StatusCode >= 400 {span.SetStatus(codes.Error, resp.Status)}return resp, nil
}

關鍵點總結

  • 使用 OpenTelemetry 標準:
    通過 go.opentelemetry.io/otel 實現與 Zipkin 的集成,遵循 CNCF 標準。
  • 中間件集成:
    使用 go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin 自動處理 Gin 請求的追蹤。

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

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

相關文章

2025年最新秋招java后端面試八股文+場景題

一、Java核心八股文(2025年最新版)1. Java基礎HashMap vs ConcurrentHashMapHashMap:非線程安全,JDK1.8后采用數組鏈表/紅黑樹,擴容時可能死循環(JDK1.7)。ConcurrentHashMap:JDK1.8…

esp32 sd卡

ref: platform io & arduino Boards — PlatformIO latest documentation https://github.com/espressif/arduino-esp32/blob/master/libraries/SD_MMC/README.md SD 卡實驗 | 極客俠GeeksMan GitHub - fabianoriccardi/ESPLogger: An Arduino library pro…

Java學習--------消息隊列的重復消費、消失與順序性的深度解析?

在 Java 分布式系統開發中,消息隊列的應用已十分普遍。但隨著業務規模擴大,消息的重復消費、意外消失、順序錯亂等問題逐漸成為系統穩定性的隱患。本文將從 Java 開發者的視角,深入分析這三大問題的產生原因、業務后果,并結合具體…

【Oracle】centos7離線靜默安裝oracle11g(p13390677_112040)

博文地址:https://blog.csdn.net/gitblog_06670/article/details/142569814 倉庫地址:https://gitcode.com/Open-source-documentation-tutorial/31eb1/?utm_sourcedocument_gitcode&indexbottom&typecard 參考安裝地址: 收費版&…

智能設備暢想

### 智能設備暢想 突然想到了一個好主意 因為最近在查無人機的相關資料(很早之前就想搞個無人機玩玩但始終沒有買) 在了解自組裝方面的內容時,和AI溝通了下 正好之前組裝的 小智AI 基本上已經完善了,也正在考慮其在其他方向拓展的…

SpringAI——ChatModel

我的前面一篇文章(SpringAI——ChatClient配置與使用)中講了ChatClient,它是一個構建于 ChatModel 之上的高層封裝,它提供了更豐富的對話交互能力。可以這么說ChatModel相當于發動機,ChatClient相當于一臺含有發動機、…

Zabbix監控K8S的PV信息詳細教程!

文將介紹如何使用Zabbix自定義鍵值腳本方式監控K8S的PV卷狀態等信息。 在Kubernetes (K8S) 中,PersistentVolume (PV) 是集群中的一個抽象層,它代表了底層存儲資源,例如網絡存儲系統(如NFS、Ceph、GlusterFS等)或本地存…

wx小程序原生開發使用高德地圖api

第一步:注冊高德地圖api的key第二步:下載amap-wx.js 放到項目的某個目錄第三步:配置app.json(必須,因為需要定位功能,)"requiredPrivateInfos": ["getLocation"],"per…

如何通過mac的前24bit,模糊確認是那一臺什么樣的設備

MAC Address Lookup - MAC/OUI/IAB/IEEE Vendor Manufacturer Search Wireshark ? Go Deep 上面這兩個網址提供了,正對mac 的前24位,查找對應的網絡設備廠商信息,可以讓我們在運維過程中模糊的判斷大約是什么型號的設備 使用macvendorloo…

【爬蟲】04 - 高級數據存儲

爬蟲04 - 高級數據存儲 文章目錄爬蟲04 - 高級數據存儲一:加密數據的存儲二:JSON Schema校驗三:云原生NoSQL(了解)四:Redis Edge近端計算(了解)五:二進制存儲1:Pickle2:Parquet一:加…

UDP和TCP的主要區別是什么?

在網絡通信中,TCP(傳輸控制協議)和UDP(用戶數據報協議)是兩種核心的傳輸層協議。它們各自的特點和應用場景截然不同,理解兩者的區別對于選擇合適的通信方式至關重要。本文將通過幾個關鍵點,用簡…

Softhub軟件下載站實戰開發(十八):軟件分類展示

Softhub軟件下載站實戰開發(十八):軟件分類展示 🖥? 在之前文章中,我們實現了后臺管理相關部分,本篇文章開始我們來實現用戶端頁面,由于內網使用,不需要sso優化等特性,我…

linux--------------------BlockQueue的生產者消費模型

1.基礎BlockingQueue的生產者消費模型 1.1 BlockQueue 在多線程編程中阻塞隊列是一種常用于實現生產者和消費者模型的數據結構,它與普通的隊列區別在于,當隊列為空時,從隊列獲取元素的操作將被阻塞,直到隊列中放入了新的數據。當…

堆排序算法詳解:原理、實現與C語言代碼

堆排序(Heap Sort)是一種高效的排序算法,利用二叉堆數據結構實現。其核心思想是將待排序序列構造成一個大頂堆(或小頂堆),通過反復調整堆結構完成排序。下面從原理到實現進行詳細解析。一、核心概念&#x…

SSM框架——注入類型

引用類型的注入:Setter方法簡單類型的注入:定義簡單實例和方法在配置文件中對bean進行配置,使用porperty屬性 值用value(ref是用來獲取bean的)構造器方法:構造器方法中需要寫name,這樣程序就會耦…

信息學奧賽一本通 1552:【例 1】點的距離

【題目鏈接】 ybt 1552:【例 1】點的距離 【題目考點】 1. 最近公共祖先(LCA):倍增求LCA 知識點講解見:洛谷 P3379 【模板】最近公共祖先(LCA) 【解題思路】 首先用鄰接表保存輸入的無權圖…

1Panel中的OpenResty使用alias

問題 在服務器上使用了1Panel的OpenResty來管理網站服務,當作是一個Nginx用,想做一個alias來直接管理某個文件夾的文件,于是直接在其中一個網站中使用了alias配置。 location /upload {alias /root/upload;autoindex on;charset utf-8;charse…

小明記賬簿煥新記:從單色到多彩的主題進化之路

【從冷靜藍到多彩世界,這一次我們重新定義記賬美學】 曾經,打開“小明記賬簿”是一片沉穩的藍色海洋,它像一位理性的財務管家,默默守護著你的每一筆收支。但總有人悄悄問:“能不能多一些顏色?”今天&#x…

Apache IoTDB(1):時序數據庫介紹與單機版安裝部署指南

目錄一、Apache IoTDB 是什么?1.1 產品介紹1.2 產品體系1.3 產品架構二、IoTDB 環境配置2.1 Linux系統需準備環境2.2 Windows系統需準備環境2.3 網絡配置2.3.1 關閉防火墻2.3.2 查看端口是否占用2.3.3 避雷經驗三、IoTDB 單機版系統部署安裝指南3.1 產品下載3.2 注意…

Python 圖片爬取入門:從手動下載到自動批量獲取

前言 想批量下載網頁圖片卻嫌手動保存太麻煩?本文用 Python 帶你實現自動爬取,從分析網站到代碼運行,步驟清晰,新手也能快速上手,輕松搞定圖片批量獲取。 1.安裝模塊 在開始爬取圖片前,我們需要準備好工具…