开源项目第195期:OpenTelemetry Demo(Astronomy Shop)— 官方出品的分布式系统可观测性实战教材

引言

"可观测性不是工具,是能力。要学会用 Traces/Metrics/Logs 诊断分布式系统,光读文档不够,得有一个真实的系统可以折腾。"

这是第 195 篇 。今天的项目是 OpenTelemetry Demo(Astronomy Shop) ------ OpenTelemetry 官方出品的分布式电商演示系统,核心定位是:一个可以主动制造故障、然后用可观测性数据找出根因的实战学习环境。

不是 Hello World,不是玩具项目。17 个微服务,12 种编程语言,Kafka 消息队列,PostgreSQL 数据库,gRPC + HTTP 混合通信,加上 Grafana + Jaeger + Prometheus 全套可视化。

3,300 Stars,7,000+ Forks。Apache-2.0 许可。Datadog、AWS、Google Cloud、New Relic、Dynatrace 等超过 50 家云厂商 Fork 它用来做自己的集成演示。

你会学到什么

  • OpenTelemetry Demo 的三大用途和定位
  • 17 个服务的架构全景和技术选型逻辑
  • Traces/Metrics/Logs 三大信号在不同语言里的实现方式
  • 13 个故障开关:如何主动制造问题来练习根因分析
  • 完整可视化栈:Grafana + Jaeger + Prometheus 的数据流
  • 为什么 50+ 家厂商选它作为集成演示基础

前提知识

  • 了解微服务架构的基本概念
  • 知道 Traces(链路追踪)、Metrics(指标)、Logs(日志)是什么
  • Docker 基础操作

背景:可观测性学习的困境

学习可观测性有一个根本问题:没有真实系统就没有真实数据,没有真实数据就学不了真实的诊断方法。

拿单服务应用练习链路追踪,学到的是"如何给一个 HTTP 处理器打 span"。但实际生产环境的问题是:请求从前端出发,经过 API 网关,调用三个微服务,其中一个调用了 Kafka,异步消费者在 30 秒后处理,触发了数据库写入失败------你在哪里看到错误?错误是哪个服务的责任?根因在第几跳?

这类问题必须在真正的分布式系统里才能理解。

OpenTelemetry Demo 的解法是:造一个足够真实的系统,然后给它配上 13 个可控的故障开关,让你按需制造问题,再用可观测性数据找出来。


项目的三大定位

OpenTelemetry Demo 同时服务于三类人,这一点从它的架构设计上就能看出来。

1. 学习者:可观测性实战教材

对于想学 OpenTelemetry 的工程师,项目提供了一个现成的分布式系统,涵盖:

  • 12 种语言的真实 SDK 用法(自动插桩 vs 手动插桩的差异)
  • gRPC 和 HTTP 两种协议的 span 传播
  • 跨服务的上下文传播(context propagation)
  • Kafka 消息队列的异步 trace 关联

打开 Jaeger,能看到一条请求从浏览器出发,流过 Frontend → Checkout → Payment → Email 的完整链路。每一跳用了多少时间,哪里出了错,一目了然。

2. 厂商和工具开发者:集成演示基础

Datadog、Elastic、AWS OpenSearch、Grafana Labs、New Relic、Dynatrace、Splunk、Google Cloud......超过 50 家公司 Fork 了这个仓库,接上自己的后端,用来演示"OTel 数据导入我们平台的效果"。

这意味着:你在这个项目里学会的 OTel 知识,在这 50 家厂商的产品里都可以直接用。OTel 的可观测性信号是中立标准,不锁定在任何一家厂商。

3. OTel 贡献者:API/SDK 测试床

新版本的 OTel SDK 发布前,需要在真实的多语言环境里验证兼容性和性能。这个项目同时运行 12 种语言的 SDK,是天然的集成测试环境。


架构全景:17 个服务,12 种语言

服务列表

服务 语言 主要职责
Frontend TypeScript Web UI,调用多个后端服务
Frontend Proxy C++ (Envoy) 请求路由、故障注入
Ad Java 广告推荐,触发 gRPC 调用
Cart .NET 购物车,连接 Valkey 缓存
Checkout Go 结账流程,协调多服务
Currency C++ 汇率转换,高 QPS 服务
Email Ruby 发送确认邮件
Fraud Detection Kotlin 欺诈检测,Kafka 消费者
Payment JavaScript 支付处理
Product Catalog Go 商品列表,gRPC 接口
Quote PHP 运费报价,HTTP 接口
Recommendation Python 商品推荐,调用 Product Catalog
Shipping Rust 配送处理,调用 Quote
Accounting .NET 订单记账,Kafka 消费者
Load Generator Python/Locust 模拟真实用户流量
Flagd Go Feature Flag 服务
Flagd UI Elixir Feature Flag 管理界面

基础设施组件

  • 缓存: Valkey(Redis 兼容)
  • 数据库: PostgreSQL
  • 消息队列: Kafka(Java)
  • OTel Collector: 统一收集所有遥测数据

通信协议

  • 服务间:主要用 gRPC,少数用 HTTP
  • 遥测数据:OTLP/gRPC(端口 4317)和 OTLP/HTTP(端口 4318)
  • 异步:Kafka TCP 连接

技术选型的逻辑

语言选择不是随机的,每种语言对应 OTel SDK 的一个实现:

  • C++ (Currency):高 QPS 场景,验证 C++ SDK 性能开销
  • Rust (Shipping):新兴后端语言,演示 Rust SDK 用法
  • PHP (Quote):传统 Web 技术,演示 PHP SDK 集成
  • Elixir (Flagd UI):函数式语言,演示 BEAM 平台的 OTel 支持

遥测数据流:从服务到 Grafana

所有服务的遥测数据汇入同一个 OTel Collector,再分发到各可视化后端:

bash 复制代码
各服务(12种语言)
    ↓ OTLP/gRPC 或 OTLP/HTTP
OTel Collector
    ├──→ Prometheus(指标存储)       → localhost:9090
    ├──→ Jaeger(链路追踪存储)        → localhost:16686
    └──→ OpenSearch(日志存储)        → localhost:9200
         ↑ ↑ ↑
        Grafana(统一可视化)           → localhost:3000

Collector 还通过 OpAMP 扩展把自身的健康状态、版本、有效配置上报给 OpAMP 服务器,这是 OTel 的远程配置管理能力演示。


13 个故障开关:主动制造问题

这是 OpenTelemetry Demo 区别于普通演示项目最关键的设计。

所有故障开关由 Flagd (OpenFeature 标准的 Feature Flag 服务)管理,在 http://localhost:8080/feature 界面开关,不需要重启服务。

故障开关完整列表

开关名称 影响服务 制造的问题
adServiceFailure Ad 1/10 概率 GetAds 请求报错
adServiceManualGc Ad 手动触发垃圾回收
adServiceHighCpu Ad 模拟高 CPU 负载
cartServiceFailure Cart EmptyCart 调用报错
emailMemoryLeak Email 内存泄漏
productCatalogFailure Product Catalog 特定商品 ID 请求失败
recommendationServiceCacheFailure Recommendation 缓存指数增长,内存泄漏(每次 1.4 倍,50% 请求触发)
paymentServiceFailure Payment charge 调用报错
paymentServiceUnreachable Checkout 支付服务不可达
loadgeneratorFloodHomepage Load Generator 主页请求洪泛
kafkaQueueProblems Kafka 队列过载 + 消费延迟,触发堆积峰值
imageSlowLoad Frontend Envoy 故障注入延迟图片加载
failedReadinessProbe Cart 就绪探针失败(仅 Kubernetes 场景)

故障练习路径

练习 1:内存泄漏诊断

开启 recommendationServiceCacheFailure

  • 在 Grafana 看到 Recommendation 服务内存指标呈指数增长
  • 在 Jaeger 看到部分推荐请求的 span 标注缓存操作异常
  • 练习:从指标异常 → 定位服务 → 追溯 trace → 确认根因

练习 2:支付链路级联故障

开启 paymentServiceUnreachable

  • Checkout 服务开始收到支付失败错误
  • 在 Jaeger 里看到 Checkout trace 中 Payment 服务的子 span 显示超时
  • 练习:从用户报告"无法付款" → Checkout trace → Payment span → 定位服务不可达

练习 3:Kafka 堆积分析

开启 kafkaQueueProblems

  • Kafka 消费者(Accounting、Fraud Detection)开始积压
  • Prometheus 里 Kafka 消费延迟指标持续上升
  • 练习:从订单处理延迟 → Kafka 指标 → 消费者 lag → 定位队列问题

练习 4:前端延迟分析

开启 imageSlowLoad(Envoy 故障注入):

  • Frontend 的图片加载时间突然延长
  • 在 Jaeger 的 Frontend trace 里看到图片请求的 span 耗时异常
  • 练习:浏览器 Web Vitals 劣化 → Frontend trace → 定位具体请求

快速上手

Docker Compose 部署

bash 复制代码
# 克隆仓库
git clone https://github.com/open-telemetry/opentelemetry-demo.git
cd opentelemetry-demo

# 启动全部服务(首次拉取镜像需要几分钟)
docker compose up --no-build

# 等待服务就绪(有些服务启动较慢,等 1-2 分钟)
docker compose ps

服务就绪后的访问地址:

地址 服务
http://localhost:8080 Astronomy Shop(电商前端)
http://localhost:8080/feature Feature Flag 管理界面
http://localhost:3000 Grafana(统一可视化)
http://localhost:16686 Jaeger(链路追踪)
http://localhost:9090 Prometheus(指标)

Kubernetes / Helm 部署

bash 复制代码
# 添加 OTel Demo Helm 仓库
helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-charts
helm repo update

# 安装到 otel-demo 命名空间
helm install my-otel-demo open-telemetry/opentelemetry-demo \
  --namespace otel-demo \
  --create-namespace

Helm Chart 已上架 Artifact Hub,可以按需覆盖各服务的配置。


插桩方式对比:自动 vs 手动

OTel 提供两种插桩路径,项目里同时有示例:

自动插桩(Zero-code)

代码零修改,通过 agent/SDK 初始化自动捕获框架层的遥测数据:

  • Java (Ad Service) :JVM Agent,启动参数加 -javaagent:opentelemetry-javaagent.jar
  • Python (Recommendation)opentelemetry-instrument python app.py
  • .NET (Cart, Accounting)OTEL_DOTNET_AUTO_* 环境变量

适合:需要快速上线可观测性、不想修改已有代码。

手动插桩

在业务代码里直接用 SDK 创建 span、添加属性、记录事件:

go 复制代码
// Go 手动插桩示例(Checkout Service)
tracer := otel.Tracer("checkout")
ctx, span := tracer.Start(ctx, "placeOrder")
defer span.End()

span.SetAttributes(
    attribute.String("order.id", orderID),
    attribute.Int("order.items", len(items)),
)

// 处理业务逻辑...

if err != nil {
    span.RecordError(err)
    span.SetStatus(codes.Error, err.Error())
}
rust 复制代码
// Rust 手动插桩示例(Shipping Service)
let tracer = global::tracer("shipping");
let mut span = tracer.start("shipOrder");
span.set_attribute(KeyValue::new("shipping.method", method));

适合:需要对业务逻辑有精细控制,需要自定义属性和事件。


为什么 50+ 家厂商选它

选一个统一的演示基础而不是自己造轮子,有几个实际好处:

  1. 受众熟悉:工程师在学习 OTel 时可能已经看过这个项目,再看厂商演示时有共同背景
  2. 公正对比:所有厂商基于同一数据源,客户可以用同样的工作负载比较不同平台的效果
  3. 维护成本:官方团队维护基础服务架构,厂商只需维护"OTel Collector → 自家后端"的对接部分
  4. 跟上版本:随着 OTel 新版本发布,官方项目同步更新,厂商 Fork 可以 rebase

项目地址与资源


总结

OpenTelemetry Demo 解决了可观测性学习里最核心的障碍:缺少一个可以安全折腾的真实系统

12 种语言的服务让你看到 OTel SDK 在不同技术栈里的实际用法,不用猜文档里的抽象描述对应到代码是什么样子。13 个故障开关让你在受控环境里练习根因分析,从指标异常到链路追踪到日志,走完完整的诊断流程。

更大的价值是它建立了一个行业共识:Datadog 的 Traces 界面展示的是它,Grafana Cloud 演示的是它,AWS X-Ray 集成演示的是它。当你在这个项目里学会如何从 Kafka 延迟指标追溯到消费者堆积,这套思路在任何一家厂商的平台上都适用------OTel 的信号格式是中立的,不锁定。

3,300 Stars 加上 7,000+ Forks 是一个反常的比例:Fork 数是 Star 数的两倍。背后的原因是那 50+ 家厂商------每家都 Fork 了一份自己维护,说明这个项目对行业来说是基础设施级别的参考,不只是学习材料。


探索 PrimeSkills ------ 精选 AI Agent 与技能的市场,每一个都经过真实企业工作流验证,去掉浮夸,留下真正有用的。

欢迎访问我的个人主页,发现更多有价值的见解和有趣的产品。

相关推荐
冬奇Lab1 小时前
Code Agent 解剖(08):一个任务太复杂,怎么拆给子 agent 做?
人工智能·开源
海兰1 小时前
【原理】OpenClaw Agent 运行时回顾一文清
人工智能·agent
民乐团扒谱机1 小时前
【微实验】物理启发神经网络(PINN):当AI学会遵守物理定律(附matlab代码))
人工智能·神经网络·matlab
极客互动API1 小时前
企业微信 iPad 协议消息接口开发:文本 / 图片 / 群发消息的统一封装
人工智能·ios·微信·机器人·企业微信·ipad
达子6662 小时前
AI训练师图解_6.1_6.2_五大行业应用_NLP
人工智能·自然语言处理
新知图书2 小时前
11.4 基于扣子编程的实现过程(AI 数据质检工作流)
人工智能·agent·ai agent·智能体
YHL2 小时前
🚀 端侧 AI DEEPSEEK-R1-WEBGPU 项目实战(二):封装进度条组件,看懂 React 事件与组件树
人工智能
zlinear数据采集卡2 小时前
数据采集卡从入门到精通(38):上位机开发实战——Python/QT/LabVIEW的技术选型与分层架构
python·单片机·嵌入式硬件·qt·fpga开发·开源·labview
皮皮狗工坊2 小时前
贡院计划第一弹:DeepSeek Harness考生翻墙抄了答案,还企图隐藏罪证
人工智能