ABP VNext + OpenTelemetry + Jaeger:分布式追踪与调用链可视化 🚀


📚 目录

  • ABP VNext + OpenTelemetry + Jaeger:分布式追踪与调用链可视化 🚀
    • 背景与动机 🌟
    • 环境与依赖 📦
      • 必装 NuGet 包
    • 系统架构概览 🖥️
    • 跑通示例 🚀
      • `Program.cs`
      • `docker-compose.yml` 🐳
    • 自动 + 手动埋点 🔍
      • 自动埋点
      • 自定义业务 Span
    • 异常与状态码标记 ⚠️
    • 日志与 Metrics 关联 📑
    • Jaeger 部署与高可用 🏗️
    • 采样策略与性能优化 🛡️
    • 扩展:OTel Collector & Grafana Tempo 🔗


版本说明:本文基于 OpenTelemetry.Extensions.Hosting >=1.4.0 编写,推荐使用统一的 .AddOpenTelemetry().WithTracing(...).WithMetrics(...) API。

TL;DR

  1. 提供完整 Program.cs + docker-compose.yml 示例 🏃‍♂️
  2. 自动 + 手动埋点:支持 HTTP/gRPC、数据库、外部调用与自定义 Span 🔍
  3. 高性能采样:Parent-Based + TraceIdRatioBasedSampler,动态可配 ⚙️
  4. 生产级部署:Batch 模式、OTel Collector、日志/Metrics 关联、异常标记 🚀

背景与动机 🌟

在分布式微服务架构中,调用链横跨多个进程与网络节点,“谁调用了谁”、“哪些环节慢”成为痛点。
OpenTelemetry(OTel)与 Jaeger 提供了开源、无侵入的端到端分布式追踪解决方案,帮助我们:

  • 自动化采集:入站 HTTP/gRPC、数据库、外部 HTTP 等一键埋点 📡
  • 自定义业务 Span:灵活埋点关键业务逻辑 🛠️
  • 统一可视化:Jaeger UI 或 Grafana Tempo 展示完整调用链 📈

本文基于 ABP VNext 6.x + .NET 6+,演示从零搭建到生产级优化,涵盖自动/手动埋点、采样策略、异常与日志关联等最佳实践。


环境与依赖 📦

  • .NET SDK:6.0+
  • ABP Framework:vNext 6.x
  • OpenTelemetry.Extensions.Hosting:>=1.4.0
  • Jaeger:all-in-one(测试);独立 Agent/Collector/Storage(生产)
  • 可选:OpenTelemetry Collector、Grafana Tempo、Prometheus/Grafana

必装 NuGet 包

dotnet add package OpenTelemetry.Extensions.Hosting
dotnet add package OpenTelemetry.Instrumentation.AspNetCore
dotnet add package OpenTelemetry.Instrumentation.Http
dotnet add package OpenTelemetry.Instrumentation.SqlClient
dotnet add package OpenTelemetry.Instrumentation.GrpcNetClient
dotnet add package OpenTelemetry.Instrumentation.GrpcAspNetCore
dotnet add package OpenTelemetry.Exporter.Jaeger
dotnet add package OpenTelemetry.Exporter.Prometheus.AspNetCore
dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol

系统架构概览 🖥️

HTTP/gRPC
DB
HTTP
Metrics
Logs
Client
ABP Service A
SQL Server
ABP Service B
Jaeger Collector
Jaeger UI
Prometheus
Grafana Dashboard
OTel Collector
日志后端
Grafana Tempo
  • 采集:入站 HTTP/gRPC、EF Core/SqlClient、HttpClient、gRPC 客户端、日志、Metrics
  • 导出:Trace → Jaeger;Metrics → Prometheus;Logs → OTLP → 日志后端;(可选)Trace → Tempo

跑通示例 🚀

启动 Jaeger (docker-compose)
运行微服务 (dotnet run)
访问业务 API
生成 Trace/Metric/Log 数据
在 Jaeger UI 查看调用链
在 Prometheus 查看 Metrics
在日志后端查看日志

Program.cs

using OpenTelemetry;
using OpenTelemetry.Logs;
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using Volo.Abp;var builder = WebApplication.CreateBuilder(args);// 1. ABP 模块注册
builder.Services.AddApplication<MyProjectHttpApiHostModule>();// 2. OpenTelemetry 注册(Tracing + Metrics)
builder.Services.AddOpenTelemetry()// Tracing.WithTracing(tracing => tracing.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("OrderService", serviceVersion: "1.0.0")).AddAspNetCoreInstrumentation().AddHttpClientInstrumentation().AddSqlClientInstrumentation().AddGrpcAspNetCoreInstrumentation().AddGrpcClientInstrumentation().AddSource("MyCompany.MyProduct").AddJaegerExporter(opts =>{opts.AgentHost = builder.Configuration["Jaeger:Host"];opts.AgentPort = int.Parse(builder.Configuration["Jaeger:Port"]!);}, exportProcessorType: ExportProcessorType.Batch).SetSampler(new ParentBasedSampler(new TraceIdRatioBasedSampler(0.1))))// Metrics.WithMetrics(metrics => metrics.AddAspNetCoreInstrumentation().AddHttpClientInstrumentation().AddPrometheusExporter());// 3. 日志关联 TraceContext
builder.Logging.AddOpenTelemetry(logging =>
{logging.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("OrderService"));logging.IncludeFormattedMessage = true;logging.IncludeScopes = true;logging.ParseStateValues = true;logging.AddOtlpExporter(); // 需要 OpenTelemetry.Exporter.OpenTelemetryProtocol
});var app = builder.Build();// 4. Prometheus 默认抓取端点(/metrics),无需额外配置
app.MapPrometheusScrapingEndpoint();// 5. 启动 ABP 应用
app.InitializeApplication();
app.Run();

docker-compose.yml 🐳

version: '3.8'
services:jaeger:image: jaegertracing/all-in-one:1.45ports:- "6831:6831/udp"- "16686:16686"- "14250:14250"

快速启动

  1. docker-compose up -d
  2. dotnet run --project src/MyProject.HttpApi.Host
  3. 访问 API & http://localhost:16686

自动 + 手动埋点 🔍

自动埋点

  • HTTP/gRPC.AddAspNetCoreInstrumentation().AddGrpcAspNetCoreInstrumentation()
  • 外部调用.AddHttpClientInstrumentation().AddGrpcClientInstrumentation()
  • 数据库.AddSqlClientInstrumentation()
ClientABP APISQL Server外部服务HTTP 请求SQL 查询HTTP 调用响应ClientABP APISQL Server外部服务

自定义业务 Span

public class OrderAppService : ApplicationService
{private static readonly ActivitySource Source = new("MyCompany.MyProduct");public async Task ProcessOrderAsync(Guid orderId){using var activity = Source.StartActivity("ProcessOrder");activity?.SetTag("order.id", orderId);try{await _orderManager.HandleOrderAsync(orderId);}catch (Exception ex){activity?.SetStatus(ActivityStatusCode.Error, ex.Message);activity?.RecordException(ex);throw;}}
}

💡 Tip:通过 ABP 拦截器统一埋点:

public class TraceInterceptor : IInterceptor
{private static readonly ActivitySource Source = new("MyCompany.MyProduct");public void Intercept(IInvocation invocation){using var activity = Source.StartActivity(invocation.Method.Name);activity?.SetTag("abp.service", invocation.TargetType.Name);try{invocation.Proceed();}catch (Exception ex){activity?.SetStatus(ActivityStatusCode.Error, ex.Message);activity?.RecordException(ex);throw;}}
}// 注册拦截器
Configure<AbpInterceptorsOptions>(opts =>opts.Interceptors.Add<TraceInterceptor>()
);

异常与状态码标记 ⚠️

  • activity?.SetStatus(ActivityStatusCode.Error, message) 标记失败 Span
  • activity?.RecordException(ex) 记录异常详情

在 Jaeger UI 中直观区分成功/失败调用链。


日志与 Metrics 关联 📑

TraceContext
OTLP
Metrics
ILogger
OpenTelemetryLogProvider
OTelCollector
LogStore
API
Prometheus
Grafana
  1. 日志

    builder.Logging.AddOpenTelemetry(logging =>logging.AddOtlpExporter());
    
  2. Metrics

    • 自动采集请求计数与时延
    • 自定义 Meter 导出 Prometheus

Jaeger 部署与高可用 🏗️

  • 测试:All-in-One 镜像,一键启动

  • 生产

    • 组件拆分:Agent/Collector/Query/UI 分离部署
    • 后端存储:Cassandra / Elasticsearch / Kafka
    • 安全:启用 TLS、鉴权(mTLS、Token),或通过 OTel Collector 做统一接入与流量控制
    • 多副本:水平扩展与高可用

采样策略与性能优化 🛡️

收到请求
父 Span 有采样?
遵从父决策
随机 < 0.1?
采样
丢弃
  • ParentBasedSampler:跨服务一致决策
  • Batch 模式:减少网络与 CPU 开销
  • 动态调整:环境变量 OTEL_TRACES_SAMPLER / OTEL_TRACES_SAMPLER_ARG
  • 环境差异:开发环境 AlwaysOnSampler;生产环境 5–10%

扩展:OTel Collector & Grafana Tempo 🔗

  • Collector:统一接入、Filter、Auth、转发至 Jaeger/Tempo/Prometheus
  • Grafana Tempo:专注 Trace 存储,结合 Prometheus、Loki 构建全栈 Observability

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/88726.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/88726.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/88726.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言中整数编码方式(原码、反码、补码)

在 C 语言中&#xff0c;原码、反码、补码的运算规则与其编码特性密切相关&#xff0c;核心差异体现在符号位是否参与运算、进位如何处理以及减法是否能转化为加法等方面。以下是三者的运算规则及特点分析&#xff08;以 8 位整数为例&#xff0c;符号位为最高位&#xff09;&a…

js二维数组如何变为一维数组

在 JavaScript 中&#xff0c;将二维数组转换为一维数组&#xff08;扁平化&#xff09;有多种方法&#xff0c;可根据数组结构复杂度、性能需求和兼容性选择。以下是最常用的实现方式&#xff1a; 1. 使用 flat() 方法&#xff08;ES2019&#xff09; MDN释义&#xff1a;flat…

Claude code在Windows上的配置流程

前言 昨天在服务器上配置好了 Claude code&#xff0c;发现其编码性能和效率都非常不错。 然而&#xff0c;尝试用它修改带 UI 界面的客户端程序时颇为不便&#xff0c;因为服务器没有图形化界面&#xff0c;无法直接将应用界面直接显示到开发机上&#xff0c;调试起来颇为不…

手把手教你用YOLOv10打造智能垃圾检测系统

无需编程基础&#xff01;手把手教你用YOLOv10打造智能垃圾检测系统 垃圾分类不再难&#xff0c;AI助手秒识别 你是否曾站在分类垃圾桶前犹豫不决&#xff1f;塑料瓶是可回收还是其他垃圾&#xff1f;外卖餐盒到底该丢哪里&#xff1f;随着垃圾分类政策推广&#xff0c;这样的困…

batchnorm类

1. 伪代码&#xff1a;2. python代码&#xff1a;3. 测试&#xff1a;4. 加深理解&#xff1a;以 为例&#xff0c;x3&#xff0c;可见输出的batchnorm后y0.2627.查看模型记录的均值及方差&#xff0c;计算y0.286799&#xff0c;理解是大致这样的计算过程。&#xff08;为什么数…

SpringBoot项目保证接口幂等的五种方法!

1. 幂等概述 1.1 深入理解幂等性 在计算机领域中&#xff0c;幂等&#xff08;Idempotence&#xff09;是指任意一个操作的多次执行总是能获得相同的结果&#xff0c;不会对系统状态产生额外影响。在Java后端开发中&#xff0c;幂等性的实现通常通过确保方法或服务调用的结果…

SQL新手入门详细教程和应用实例

SQL(Structured Query Language)是用于管理和操作关系型数据库的标准语言。它允许你创建、查询、更新和删除数据。本教程将从基础概念开始,逐步引导你上手SQL,并提供详细的应用实例。教程基于标准SQL语法,实际使用时需根据数据库系统(如MySQL、SQLite或PostgreSQL)调整。…

DVWA-LOW级-SQL手工注入漏洞测试(MySQL数据库)+sqlmap自动化注入-小白必看(超详细)

首次使用DVWA的靶场&#xff0c;咋们先从最低级别的LOW开始&#xff0c;因为之前玩过一下墨者学院&#xff0c;对sql注入有一点认识和理解&#xff0c;所以先从sql的盲注开始&#xff1b; 1、测试注入点是否存在sql注入的漏洞&#xff1b; &#xff08;1&#xff09;首先我们…

JAVA线程池详解+学习笔记

1.线程池基础概念线程池是一种资源复用技术&#xff0c;通过预先创建并管理一组线程&#xff0c;减少频繁创建和销毁线程的开销。核心思想与数据库连接池、字符串常量池类似&#xff0c;旨在提升系统性能。核心参数解析ThreadPoolExecutor构造函数包含7个关键参数&#xff1a;c…

数据分析库 Pandas

对于Pandas的简单认识和基本操作的练习一 介绍 Pandas 是一个开源的数据分析和数据处理库&#xff0c;它是基于 Python 编程语言的库。 Pandas 提供了易于使用的数据结构和数据分析工具&#xff0c;特别适用于处理结构化数据&#xff0c;如表格型数据&#xff08;类似于 Excel …

qt 中不要让 lambda 槽函数捕获信号源对象的共享指针

错误示例std::shared_ptr<QSerialPort> serial{new QSerialPort{}};QSerialPort::connect(serial.get(),&QSerialPort::readyRead,[serial](){QByteArray receive_data serial->readAll();std::cout.write(receive_data.data(), receive_data.size());});这会直接…

Solidity 合约的编写-完整开发流程:从编译、测试、部署到交互

&#x1f9f1; Solidity 合约开发全流程&#xff08;Foundry 版&#xff09;✅ 适合对象&#xff1a;已经能写合约但不清楚如何测试、部署、交互的开发者✅ 工具链&#xff1a;Foundry&#xff08;forge, anvil, cast&#xff09;&#x1f4cc; 开发流程总览1️⃣ 初始化项目 2…

设计模式 - 面向对象原则:SOLID最佳实践

文章目录深入理解 SOLID&#xff1a;用对原则&#xff0c;别把简单问题搞复杂SOLID 原则概览1. 单一职责原则&#xff08;SRP&#xff09;2. 开闭原则&#xff08;OCP&#xff09;3. 里氏替换原则&#xff08;LSP&#xff09;4. 接口隔离原则&#xff08;ISP&#xff09;5. 依赖…

Vue 3 中父组件内两个子组件相互传参的几种方法

方法一&#xff1a;通过父组件中转&#xff08;Props Emits&#xff09;<!-- ParentComponent.vue --> <template><ChildA :message-from-b"messageFromB" send-to-b"handleSendToB" /><ChildB :message-from-a"messageFromA&q…

三子棋游戏设计与实现(C 语言版)

一、需求分析目标&#xff1a;实现一个简单的人机对战三子棋&#xff0c;支持以下功能&#xff1a;初始化空棋盘&#xff0c;清晰展示落子状态。玩家通过坐标落子&#xff08;X 代表玩家&#xff09;&#xff0c;电脑随机落子&#xff08;O 代表电脑&#xff09;。实时判断胜负…

GD32 CAN1和TIMER0同时开启问题

背景&#xff1a;今天在一个项目调试的时候发现了一些问题&#xff0c;由此贴记录一下问题解决的过程。使用的芯片是GD32F305VE。使用到了CAN1和TIMER0。在使用这连个外设的时候发送了一些问题。单独使用CAN1。功能正常。单独使用TIMER0。配置为输出模式。功能正常。但是当两个…

剑指offer56_数组中唯一只出现一次的数字

数组中唯一只出现一次的数字在一个数组中除了一个数字只出现一次之外&#xff0c;其他数字都出现了三次。 请找出那个只出现一次的数字。 你可以假设满足条件的数字一定存在。 思考题&#xff1a; 如果要求只使用 O(n) 的时间和额外 O(1) 的空间&#xff0c;该怎么做呢&#xf…

从语音识别到智能助手:Voice Agent 的技术进化与交互变革丨Voice Agent 学习笔记

From Research AI&#xff1a; 最近看到 Andrew Ng 的一句话让我印象深刻&#xff1a;“While some things in AI are overhyped, voice applications seem underhyped right now.”&#xff08;尽管 AI 中有些领域被过度炒作&#xff0c;语音应用却似乎被低估了&#xff09;。…

什么是Jaccard 相似度(Jaccard Similarity)

文章目录✅ 定义&#xff1a;&#x1f4cc; 取值范围&#xff1a;&#x1f50d; 举例说明&#xff1a;&#x1f9e0; 应用场景&#xff1a;⚠️ 局限性&#xff1a;&#x1f4a1; 扩展概念&#xff1a;Jaccard 相似度&#xff08;Jaccard Similarity&#xff09; 是一种用于衡量…

ragflow_多模态文档解析与正文提取策略

多模态文档解析与正文提取策略 RAGflow的文档解析系统位于deepdoc/parser/目录下,实现了对多种文档格式的统一解析处理。该系统采用模块化设计,针对不同文档格式提供专门的解析器,并通过视觉识别技术增强解析能力。本文将深入探讨RAGflow的文档解析系统的设计原理、实现细节…