一天一个开源项目

开源项目第195期:OpenTelemetry Demo(Astronomy Shop)— 官方出品的分布式系统可观测性实战教材,12种语言 + 17个微服务 + 13个故障开关,50+ 云厂商用它做集成演示

OpenTelemetry 官方出品的分布式电商演示系统 Astronomy Shop,以接近真实的微服务架构展示 Traces/Metrics/Logs 三大信号的完整实现。17个服务覆盖 .NET/Go/Java/Kotlin/Python/Rust/Ruby/PHP/C++/TypeScript/JavaScript/Elixir 12种语言,13个可开关的故障场景(内存泄漏、CPU 飙升、服务不可达、Kafka 堆积),Grafana + Jaeger + Prometheus 全套可视化。Datadog、Elastic、AWS、GCP、New Relic、Dynatrace 等 50+ 家厂商基于此项目构建集成演示。Docker 或 Helm 一键部署。3.3k Stars,Apache-2.0。

·约 11 分钟阅读·Observability

引言

"可观测性不是工具,是能力。要学会用 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 种语言

服务列表

服务语言主要职责
FrontendTypeScriptWeb UI,调用多个后端服务
Frontend ProxyC++ (Envoy)请求路由、故障注入
AdJava广告推荐,触发 gRPC 调用
Cart.NET购物车,连接 Valkey 缓存
CheckoutGo结账流程,协调多服务
CurrencyC++汇率转换,高 QPS 服务
EmailRuby发送确认邮件
Fraud DetectionKotlin欺诈检测,Kafka 消费者
PaymentJavaScript支付处理
Product CatalogGo商品列表,gRPC 接口
QuotePHP运费报价,HTTP 接口
RecommendationPython商品推荐,调用 Product Catalog
ShippingRust配送处理,调用 Quote
Accounting.NET订单记账,Kafka 消费者
Load GeneratorPython/Locust模拟真实用户流量
FlagdGoFeature Flag 服务
Flagd UIElixirFeature 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,再分发到各可视化后端:

各服务(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 界面开关,不需要重启服务。

故障开关完整列表

开关名称影响服务制造的问题
adServiceFailureAd1/10 概率 GetAds 请求报错
adServiceManualGcAd手动触发垃圾回收
adServiceHighCpuAd模拟高 CPU 负载
cartServiceFailureCartEmptyCart 调用报错
emailMemoryLeakEmail内存泄漏
productCatalogFailureProduct Catalog特定商品 ID 请求失败
recommendationServiceCacheFailureRecommendation缓存指数增长,内存泄漏(每次 1.4 倍,50% 请求触发)
paymentServiceFailurePaymentcharge 调用报错
paymentServiceUnreachableCheckout支付服务不可达
loadgeneratorFloodHomepageLoad Generator主页请求洪泛
kafkaQueueProblemsKafka队列过载 + 消费延迟,触发堆积峰值
imageSlowLoadFrontendEnvoy 故障注入延迟图片加载
failedReadinessProbeCart就绪探针失败(仅 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 部署

# 克隆仓库
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:8080Astronomy Shop(电商前端)
http://localhost:8080/featureFeature Flag 管理界面
http://localhost:3000Grafana(统一可视化)
http://localhost:16686Jaeger(链路追踪)
http://localhost:9090Prometheus(指标)

Kubernetes / Helm 部署

# 添加 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 手动插桩示例(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 手动插桩示例(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 与技能的市场,每一个都经过真实企业工作流验证,去掉浮夸,留下真正有用的。

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