遥测驱动开发

Lobsters Hottest 工具

摘要

Smart Rent 的 Noah 为 Elixir 提出「遥测驱动开发」:先用 OpenTelemetry 埋点,再上线,用 84.8 万台 Nerves 网关的真实数据取代拍脑袋。

<p>仓库:<a href="https://github.com/Nezteb/telemetry-driven-development" rel="ugc">https://github.com/Nezteb/telemetry-driven-development</a></p> <p><a href="https://lobste.rs/s/bonwlu/telemetry_driven_development">评论</a></p>
查看原文 导出为 Word 导出为 PDF
查看缓存全文

缓存时间: 2026/04/22 19:04

TL;DR:用数据取代猜测——先加遥测再上线,这样你就能随时知道 Elixir 系统在生产中到底在干什么。 ## 遥测驱动开发 > “系统的目的就是它实际做的事。” Noah(GitHub/Slack NZTeb)在一次 Elixir 聚会上提出“遥测驱动开发”(TDD)。传统 TDD 是“先写测试,看它失败,再让它通过”;新的 TDD 则是“让系统告诉你它在干什么,再决定算不算完成”。下文浓缩了他的分享、现场演示,以及他在 Smart Rent 运维 84.8 万台 Nerves 网关的经验。 ## 为什么传统 TDD 已不够 单元测试只能证明代码在开发者笔记本上能跑,而生产环境是分布式、并发、资源饥饿的修罗场。350 万台 IoT 设备(门锁、恒温器、漏水传感器)同时冲击平台——每秒 231 个新 TLS 连接、3600 条 MQTT 消息、7000 行 DB 写入——靠猜只会 outages。遥测成了唯一可靠的反馈闭环。 ## “遥测”到底指什么 借自 1950 年代硬件,遥测字面意思是“远程测量”。想象水管上的压力表:你看不见水,但能读刻度。在软件里我们导出三类信号: 1. **追踪(Traces)**——请求级别的因果图 2. **指标(Metrics)**——随时间预聚合的数值 3. **日志(Logs)**——带上下文的离散事件 OpenTelemetry(OTel)把三者打包成厂商无关的规范。Elixir 现状: - **追踪**——已稳定 - **指标与日志**——beta;可通过 `:telemetry` + `:telemetry_metrics` 桥接使用 ## 你会遇到的库 | 包 | 用途 | |---------|---------| | `opentelemetry_api` | Span/指标/日志 API | | `opentelemetry` | SDK 实现 | | `opentelemetry_exporter` | GRPC/HTTP 导出到 OTel Collector | | `opentelemetry_telemetry` | 把 `:telemetry` 事件桥接成 OTel span | | `telemetry` | BEAM 原生分发库(1.0 发布于 2021-07-03) | ## 一条命令启动本地可观测栈 克隆仓库,运行: ```bash docker compose up ``` Grafana 在 `http://localhost:3000` 启动,自带: - **Loki**——日志 - **Tempo**——追踪 - **Mimir**——指标 缩写 LGTM 是故意玩梗——“looks good to me”,每个 PR 梦寐以求的评论。 ## 演示项目走读 最小 Phoenix 应用 + GenServer 工作进程: 1. 每 10 秒调度一次,调用 `cpu_work()` 和 `io_work()` 2. 每个函数用 `OpenTelemetry.Tracer.with_span/3` 开启 OTel span 3. 属性(`cpu_ms`、`bytes_read`)挂到 span 上 4. Collector 接收,Tempo 存储,Grafana 展示瀑布图 改代码、热重载、刷新 Grafana——反馈 < 5 秒,零云成本。 ## 针对遥测写测试 在 `MIX_ENV=test` 挂处理器: ```elixir :telemetry.attach( "test-handler", [:my_app, :work, :stop], fn _event, measurements, _meta, pid -> send(pid, {:telemetry, measurements}) end, self() ) ``` 然后断言: ```elixir assert_receive {:telemetry, %{cpu_ms: ms}} when ms > 0 ``` 再也不用 flaky 的 sleep 或 `assert_process` 黑科技;事件本身就是同步原语。 ## 环境专属管道 | 环境 | 策略 | |-------------|----------| | dev | 导出到 stdout-spans,采样率 100 % | | test | 进程内挂处理器,不走网络 | | staging | 发到 staging collector,采样率 10 % | | prod | 发到区域 collector,采样率 1 %,基于头部的概率采样 | runtime.exs 读取 `OTEL_EXPORTER_ENDPOINT` 和 `OTEL_TRACES_SAMPLER_ARG`,同一容器镜像到处运行。 ## 持续集成技巧 CI 任务: ```bash docker compose -f ci.docker-compose.yml up --exit-code-from test ``` 栈启动,测试在完整可观测环境下跑,栈自行销毁。产物:JUnit XML *和* 追踪 JSON,方便事后验尸。 ## 证明值得投入的生产数字 Smart Rent 车队: - 84.8 万个 Erlang 节点(Nerves 网关) - 350 万叶子设备(每网关 4 个) - P99 端到端延迟 350 ms - 每秒 7000 行 DB 变更 没有 trace ID,运维会被非结构化日志淹没;有了它,支持工单变成“贴一下 trace ID,我们立刻给你看具体网关、固件版本、执行计划”。 ## Elixir + OTel 当前坑点 1. 指标与日志 API 仍在变动;可能有小破环 2. 高吞吐服务需仔细调采样,否则内存爆炸 3. BEAM 调度器与 reduction→CPU 映射尚无标准语义约定 4. 跨节点传播需在 MQTT/Phoenix Channel 里手动解析 `traceparent` 社区活跃;关注 erlang-otel,日志域 PR 预计下版合并。 ## 自家项目起飞清单 1. 所有应用加 `:opentelemetry_api`(只加 API,库不带 SDK) 2. 业务函数包 `with_span` 或 `:telemetry.execute` 3. 本地用 docker-compose LGTM 栈导出 4. 至少写一条测试断言遥测 payload 5. 部署到 staging,打开 Grafana,问:**“我能看到一个请求的完整故事吗?”** 6. 迭代到仪表盘比 shell 先给出答案为止 ## 经验法则收尾 画不出图,就甭吐槽。先交付可观测性;指标、追踪、日志都说 OK,功能才算完。

相似文章

Elixir 应用优化之旅

Lobsters Hottest

一位开发者分享了优化 Elixir 应用的经验与教训,重点介绍了针对 Postgres 连接池工具 Ultravisor 的性能改进。文章涵盖了使用火焰图、调用追踪等性能分析技术,以及 eFlambè 和 tprof 等工具。

首次实现本地真实编程工作

Reddit r/LocalLLaMA

开发者借助 Qwen3.6-35B 4-bit MLX 模型与 pi.dev 工具,在当前硬件上实现了高效的本地智能体编程,顺利完成了实际项目工单。

Gemma-4微调与部署中的挑战与磨难 [P]

Reddit r/MachineLearning

一个机器学习团队记录了在微调并部署Gemma-4过程中遇到的实际挑战,包括与PEFT、SFTTrainer、DeepSpeed ZeRO-3的不兼容,以及缺乏运行时LoRA服务支持,并提供了每个问题的解决方法。

你这周在做什么?

Lobsters Hottest

一位开发者分享了可嵌入类型化语言 Ekto 的最新进展,该语言受 Lua、Koka 和 Erlang 启发,并讨论了为 Casper VM 实现引用计数、内存管理及有界续体时面临的挑战。