CodeGym /课程 /C# SELF /分布式追踪与遥测

分布式追踪与遥测

C# SELF
第 64 级, 课程 4
可用

1. 引言

在现代的面向服务架构 (SOA)、微服务和云方案里,一个用户请求可能会在返回结果前“飞过”几十个不同的服务。每个节点都写自己的日志,但怎么知道某个位置的错误或延迟真的是和这个特定请求有关?

分布式追踪 就像物流里的包裹追踪系统:你能看到包裹经过了哪些站点、在哪儿滞留了、哪里出了问题。在编程世界里——它让你能追踪一个请求在所有服务中的“旅行”,知道每段耗时多少、哪里发生了错误或延迟。

为什么需要追踪?

  • 定位错误:出问题时你能马上看到在哪个服务、哪个阶段、甚至是哪个具体方法被调用。
  • 发现“瓶颈”:追踪会显示哪部分服务“慢”,在哪个阶段消耗最多时间。
  • 用户场景分析:可以理解客户真实如何使用你的服务,该把优化投入到哪儿。

它怎么工作?

每个请求会拿到一个唯一的追踪标识(TraceId),这个标识会随着请求在整个服务栈中“旅行”:从前端到后端,从 API 到数据库再回来。每个阶段会创建 span(spans),记录操作的耗时和额外事件。最终你会得到一个操作树(或图),带有每个节点的持续时间和它们之间的关联。

分布式追踪的关键实体与术语

术语 描述
追踪(Trace) 一个请求穿过多个服务的逻辑路径。由唯一的 TraceId 标识。
span(Span) 追踪内的一个操作或子操作。每个 span 有自己的唯一标识。
TraceId 整个追踪(整个请求)的唯一标识。
SpanId 当前 span(操作)的唯一标识。
Parent SpanId 父 span 的 Id(如果该 span 是另一个操作的一部分)。
Attributes span 的一组用户元数据:方法名、参数、状态等。
Events/Logs 与 span 相关的重要事件(比如错误、完成)。
Context Propagation 在服务和线程间传递追踪信息的机制。

2. OpenTelemetry: 用于可观测性的开放标准

关于 OpenTelemetry 简要说明

OpenTelemetry — 一个开放标准和工具集,用来从各种应用收集遥测(追踪、指标、日志)。它由 Cloud Native Computing Foundation (CNCF) 支持,已经成为云和分布式应用领域的事实标准。

OpenTelemetry(简称 OTel)可以:

  • 自动收集并发送追踪、指标和日志;
  • 支持主流编程语言,包括 C#, Java, Python 等;
  • 将数据传回可观测性系统——Jaeger, Zipkin, Azure Monitor, Grafana 等;
  • 通过插件扩展并按任何技术栈进行配置。

为什么选择 OpenTelemetry?

  • 厂商无关:OTel 是标准,而不是某个公司的产品。
  • 兼容性:支持主流追踪格式,易于和 APM 系统集成。
  • 自动化:很多工作(比如 HTTP 请求追踪)可以自动完成,配置很少。
  • 可扩展性:OTel 既适合小系统,也能应对非常大的系统。

OpenTelemetry 架构:简单说明

为了不绕晕我们,来可视化一个典型的 OTel 追踪数据流。

flowchart LR
    subgraph 应用
        A[OpenTelemetry SDK]
    end
    A -->|追踪、指标、日志| B[OpenTelemetry Collector]
    B -->|导出到| C[Jaeger/Zipkin/Grafana/Azure/Application Insights 等]
  1. OpenTelemetry SDK:直接嵌入到你的应用里(例如通过 .NET 的 NuGet 包)。
  2. OTel Collector:一个独立的汇聚服务(通常以 Docker 容器部署),接收所有应用的 trace 数据并把它们导出到指定位置。
  3. 可视化前端:你查看漂亮图表、树状视图、过滤和分析追踪的地方。

3. 在 C#/.NET 上快速开始追踪

我们来给教学示例应用添加基本的分布式追踪。主要步骤很简单。

安装 NuGet 包

dotnet add package OpenTelemetry
dotnet add package OpenTelemetry.Exporter.Console

OpenTelemetry — SDK 的基础实现;
OpenTelemetry.Exporter.Console — 将追踪导出到控制台(可以替换为 Jaeger、Zipkin 等)。

最小追踪配置

在文件 Program.cs(针对控制台应用):

using OpenTelemetry;
using OpenTelemetry.Trace;

class Program
{
    static void Main(string[] args)
    {
        // 配置追踪
        using var tracerProvider = Sdk.CreateTracerProviderBuilder()
            .AddSource("DemoApp") // 指定源名称
            .AddConsoleExporter() // 将追踪导出到控制台
            .Build();

        var source = new System.Diagnostics.ActivitySource("DemoApp");

        // 开始一个新的追踪(根 span)
        using (var activity = source.StartActivity("主操作"))
        {
            DoWork();
        }
    }

    static void DoWork()
    {
        // 一些应用逻辑...
        System.Threading.Thread.Sleep(300);
    }
}

这里发生了什么?

  • 创建了追踪提供者,注册了源("DemoApp")并添加了控制台导出器 AddConsoleExporter()。
  • 通过 ActivitySource 在程序入口启动了一个新的 activity(span)。
  • 在内部执行我们想要追踪的实际工作。

结果:

Activity.Id:          0b69e3e97ca5f14d
Activity.Operation:   主操作
Duration: 00:00:00.3001082
...

HTTP 和数据库的自动追踪

OpenTelemetry 支持 instrumentation —— 对流行库的自动追踪。比如,通过 HttpClient 的调用和针对数据库的查询(ADO.NET)可以在不改你业务代码的情况下被采集。

using var tracerProvider = Sdk.CreateTracerProviderBuilder()
    .AddHttpClientInstrumentation() // HTTP 请求
    .AddSqlClientInstrumentation()  // SQL 请求(如果你在用)
    .AddConsoleExporter()
    .Build();

现在你通过 HttpClient 的所有调用和对 SQL 的操作会自动出现在追踪里。

4. 追踪的可视化

输出到控制台只是第一步。要真正发挥价值,最好用带可视化的前端。

Jaeger

Jaeger 是最流行的开源追踪可视化系统之一。

  1. 部署 Jaeger(比如用 Docker)。
  2. 把 AddConsoleExporter() 换成:
    .AddJaegerExporter(options =>
    {
        options.AgentHost = "localhost";
        options.AgentPort = 6831;
    })
    
  3. 现在所有追踪都会显示在 Jaeger UI 中——可以按 TraceId 过滤,查看详细的时间线。

完整指南:OpenTelemetry Jaeger Exporter 用于 .NET

5. 有用的细节

方法比较

不使用 OTel 时你得手动把 TraceId 写到日志里,希望别忘了往下传,然后在分析事故时受罪。用 OTel 后整条链自动串起来,一键可视化。

方法 工作量 可靠性 可扩展性 兼容性
手动记录 TraceId 高 低 需要持续维护 仅限你的应用
OpenTelemetry 最小化(部署后) 可靠 广泛(任意语言、技术栈) 与大多数 APM 和日志系统兼容

架构示例

[网页客户端] --> [API 服务] --> [授权服务] --> [数据库服务]

当用户点击按钮,请求会通过这些服务。借助 OTel 你可以把那根线(TraceId)从每个服务串起来,自动把各段逻辑合并成一条追踪。

  • 在每个服务里 OTel SDK 会自动从 HTTP header 识别 TraceId 并继续链路。
  • 结果是你可以打开一个追踪——看哪些地方耗了毫秒,发生了什么,哪里出错了。

在真实项目和面试中的应用

  • 微服务系统和分布式应用(金融科技、市场平台、SaaS 等)。
  • DevOps/SRE:快速定位问题。
  • 提升 SLA 和服务响应能力。
  • 性能分析与优化。
  • 面试中展示成熟的工程实践。

6. 常见错误和实现注意点

忘了传递 TraceContext。 如果服务间不传 TraceId(比如忘记把必要的 HTTP header 透传),追踪会被断开——看起来像孤立的“点”,可观测性的好处就没了。

未被 instrument 的代码。 如果某个库或框架不支持自动 instrument,那些操作会从追踪里缺失(不过你可以通过 ActivitySource 和 StartActivity() 手动创建 span)。

数据过多。 为每个请求采集追踪在大流量下代价很高。通常只对部分请求开启追踪(sample rate),或基于触发条件采集(错误、慢请求等)。

性能影响。 正确使用异步导出时 OTel 对性能的影响很小,但在极大流量下仍需关注开销并调整采样率。

2
任务
C# SELF, 第 64 级, 课程 4
已锁定
使用 OpenTelemetry 实现最小化追踪
使用 OpenTelemetry 实现最小化追踪
1
调查/小测验
日志记录第 64 级,课程 4
不可用
日志记录
Logging、监控和追踪
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION