引言
"可观测性不是工具,是能力。要学会用 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 服务 |
| 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,再分发到各可视化后端:
各服务(12种语言)
↓ OTLP/gRPC 或 OTLP/HTTP
OTel Collector
├──→ Prometheus(指标存储) → localhost:9090
├──→ Jaeger(链路追踪存储) → localhost:16686
└──→ OpenSearch(日志存储) → localhost:9200
↑ ↑ ↑
Grafana(统一可视化) → localhost:3000Collector 还通过 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 | 内存泄漏 | |
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 部署
# 克隆仓库
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 部署
# 添加 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-namespaceHelm 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+ 家厂商选它
选一个统一的演示基础而不是自己造轮子,有几个实际好处:
- 受众熟悉:工程师在学习 OTel 时可能已经看过这个项目,再看厂商演示时有共同背景
- 公正对比:所有厂商基于同一数据源,客户可以用同样的工作负载比较不同平台的效果
- 维护成本:官方团队维护基础服务架构,厂商只需维护"OTel Collector → 自家后端"的对接部分
- 跟上版本:随着 OTel 新版本发布,官方项目同步更新,厂商 Fork 可以 rebase
项目地址与资源
- GitHub: open-telemetry/opentelemetry-demo
- 官方文档: opentelemetry.io/docs/demo
- Helm Chart: Artifact Hub - opentelemetry-demo
- OTel 官网: opentelemetry.io
总结
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 与技能的市场,每一个都经过真实企业工作流验证,去掉浮夸,留下真正有用的。
欢迎访问我的个人主页,发现更多有价值的见解和有趣的产品。