深入 Hadoop 12 - YARN Timeline Service v2
上一篇讲了 YARN HA 和 Federation。本篇讲 YARN Timeline Service v2——YARN 提供的通用应用历史与指标系统,是第二阶段的最后一篇。
Timeline Service 常被介绍成"YARN 的作业历史记录"。这个描述对应了功能但漏了 v2 与 v1 的架构差异。准确的说法是:Timeline Service v2 是 Hadoop 3.0 引入的下一代架构,与 v1 的"集中式 Timeline Server"不同,v2 把写入侧改造成"每个 AM / NM 内嵌 TimelineCollector",把读侧改造成"无状态 Reader + 可扩展 HBase 后端",让 Timeline 系统可以横向扩展支撑万节点集群。
本篇只抓一个问题:Timeline Service v2 解决了 v1 的什么瓶颈、Per-App Collector 和 TimelineReader 各自怎么工作、为什么 v2 的后端必须用 HBase 而不是直接用 HDFS。
v1 的设计缺陷
Timeline Service v1(Hadoop 2.4 引入)的设计是"集中式 Timeline Server":
1 | |
这个设计在小集群(几百节点)工作良好,但在大集群暴露了三个结构性问题:
第一,写入瓶颈。集群里所有 AM 和 NM 都把事件发到单一 Timeline Server,Timeline Server 进程的网卡和 CPU 成为瓶颈。5000 节点集群上每秒可能有几十万事件(每个 task 几十个事件 × 数千并发 task),单 Timeline Server 处理不过来。
第二,写入与计算耦合。Timeline Server 是一个独立 JVM 进程,但它要部署在哪里?部署在专用节点(资源浪费)?部署在某个 NM 节点上(与计算争资源)?这个部署难题在 v1 时代没有好的解。
第三,数据模型不区分。v1 把"通用应用元数据"(作业 ID、提交用户、队列、状态)和"框架特定数据"(MapReduce counter、Spark stage 信息、Tez DAG)混在一起,没有清晰的 schema 区分。这让 Reader 查询时很难按维度过滤,性能也差。
v2 的架构改造
Timeline Service v2(Hadoop 3.0 引入)针对 v1 的三个问题做了架构改造:
1 | |
这种"分布式写入 + 无状态读取 + LSM-Tree 后端"的组合让 Timeline v2 可以扩展到万节点集群。每秒几十万事件被分散到所有 AM / NM 的 Collector,批量写 HBase,吞吐线性扩展。
为什么后端必须用 HBase 而不是 HDFS?因为 Timeline 数据的访问模式是"按 app-id / entity-type / time-range 查询",不是顺序扫描。HDFS 适合大文件顺序读,按 key 查询需要 NameNode 元数据 + DataNode 随机读,性能差。HBase 的 LSM-Tree + RegionServer 天然支持按 rowkey 高效查询,是 Timeline 系统的正确后端选择。
Per-App TimelineCollector
v2 的核心创新是 Per-App TimelineCollector。每个 AM 启动时在自己的 JVM 里内嵌一个 Collector 实例,AM 内部产生的事件(task 启动、task 完成、counter 更新)通过本地方法调用发给 Collector,不经过网络。
1 | |
Collector 在本地内存里维护一个环形 buffer 或 list,攒够一定数量事件或达到时间窗口后批量写到 HBase。这种"本地攒批 + 批量写"模式让网络 RPC 减少 100 倍以上——单个事件可能几百字节,攒成 1000 个事件的批量后一次 RPC 写 1 MB。
Per-App Collector 还带来一个隐性收益——写入隔离。一个作业产生大量事件不会拖慢其他作业的写入,因为每个作业有自己的 Collector 和本地 buffer。v1 时代所有作业挤一个 Timeline Server,一个"日志狂"作业可以拖慢整个集群的 Timeline 写入。
NM 上的 TimelineCollector 处理 container 级事件——container 启动、container 完成、container 资源使用指标。这些事件由 NM 自己产生,攒批后写 HBase。
数据模型:Flow / Run / App / Entity
v2 的 schema 设计是 Timeline v2 与 v1 的另一个关键差异。v2 引入了"Flow → FlowRun → App → Entity"四级聚合:
1 | |
这种层级让 Timeline 数据可以按维度查询:
1 | |
v1 时代这种跨 app 查询几乎不可能——v1 只有 app 和 entity 两级,没有 flow / run 的概念。v2 的四级聚合让"作业编排视角"成为一等公民——用户可以从"这次 ETL 流怎么样"开始查询,而不是从"某个作业的某个 task"开始。
HBase 的 rowkey 设计按 flow / run / app / entity 复合,让按 flow 维度的查询高效(同一 flow 的数据在 HBase 上连续存放,scan 性能好)。
Reader 与 REST API
TimelineReader 是 v2 的读取侧组件,提供 REST API 给 UI 和客户端:
1 | |
这套 REST API 支持 flow / run / app / entity 四个层级的查询,支持按时间范围、按 entity type、按 attribute 过滤。
Reader 是无状态服务——它只是 HBase 的查询代理。可以部署多个 Reader 实例做负载均衡,任何一个 Reader 挂掉客户端切换到另一个。这种无状态特性让 Reader 可以放在任意节点(包括专用的 Timeline Service 节点或者 NM 节点上同部署)。
Hadoop 自带的 YARN Timeline Web UI(在 ResourceManager Web UI 的 “Timeline service” 标签下)通过 Reader REST API 渲染作业历史、task 详情、counter 等。第三方 UI(Apache Zeppelin、Ranger Audit UI)也可以用同一套 REST API。
与计算框架的集成
Timeline v2 的价值依赖计算框架主动上报事件。Hadoop 3.x 默认集成了三个框架:
MapReduce(MRv2):MRAppMaster 内置 TimelineClient,把 task 启动、task 完成、counter 等事件自动发给 Per-App Collector。用户不需要修改作业代码。
Tez:Tez DAG AppMaster 同样内置 TimelineClient,把 DAG 节点执行事件发给 Collector。Tez UI 通过 Reader REST API 渲染 DAG 视图。
Spark:Spark AppMaster 配置 spark.hadoop.yarn.timeline-service.enabled=true 后会把 stage / task 事件发给 Collector。Spark History Server 可以读 Timeline 数据。
Flink:Flink JobManager 通过 TimelineClient 把 job / task 事件发给 Collector。Flink Web UI 可以集成 Timeline 数据。
其他自定义 AM 框架需要实现 TimelineClient 接口主动上报事件。这是 v2 的额外开发成本——计算框架需要主动集成。不集成的话 Timeline v2 仍然能记录 NM 层面的 container 事件(container 启动 / 完成、资源使用指标),但 AM 层面的事件(task 进度、counter)就缺失。
实验:观察 Timeline Service
部署 Timeline v2 的集群,配置 yarn.timeline-service.enabled=true 和 yarn.timeline-service.version=v2。提交一个 MapReduce 作业,用 REST API 查询作业事件:
1 | |
输出 JSON 格式的事件列表,每个事件包含 entity type、timestamp、attributes 等。
HBase 后端可以直接查询数据:
1 | |
可以看到 Timeline 数据按 rowkey(cluster + flow + run + app 复合)存放在 HBase,scan 顺序就是按 flow 维度查询的结果。
YARN Web UI 上的 “Timeline service” 标签页(默认 http://resourcemanager:8088/timeline)展示作业历史。如果配置正确,每个作业点进去可以看到 task 详情、counter、日志链接等。
模式提炼
Timeline Service v2 体现的设计模式:
1 | |
这个模式不只是 Timeline。Kafka 的 producer/consumer 也用类似的"本地攒批 + 批量网络"模式。Spark Event Log 同样是"AM 内部记录 + 持久化到 HDFS"的写入模式(差异在 Spark 用顺序追加文件,Timeline 用 HBase LSM-Tree)。Prometheus 的 Pushgateway 在某些场景类似——分布式客户端推指标到 Pushgateway,Prometheus 拉取。
数据模型的多级聚合(Flow → Run → App → Entity)对应"业务流水线 → 一次执行 → 一次任务 → 内部对象"。这种层级在很多监控系统中出现——OpenTelemetry 的 Trace / Span / Event 三级、ELK 的 Index / Document / Field、Prometheus 的 Metric / Label / Sample 都是类似抽象。
工程迁移表
| Timeline v2 概念 | Spark Event Log | Flink JobManager | Kafka Connect | Prometheus |
|---|---|---|---|---|
| Per-App Collector | Driver 内 Event Log writer | JobManager 内 metric registry | Worker 内 Convert 记录 | pushgateway |
| Reader REST | Spark History Server | Flink REST API | Connect REST | PromQL API |
| HBase 后端 | HDFS 顺序文件 | 内存 + RocksDB | Kafka topic | TSDB(自定义) |
| Flow 聚合 | - | - | - | Federation |
| 多级聚合 | - | Job → Task → SubTask | Connector → Task | Metric → Label |
注意 Spark Event Log 这一列。Spark 默认把事件写到 HDFS 上的一个顺序文件(.inprogress 后缀,作业完成后改名)。这种"一个文件追加写"的模式比 Timeline v2 简单,但只能 Spark 自己读。Timeline v2 把数据放到 HBase 让多框架(MR / Tez / Spark / Flink)共享存储和查询接口。
常见误解
误解一:“Timeline v2 只是 v1 的优化版本”。v2 与 v1 是完全不同的架构——v1 是集中式 Timeline Server,v2 是分布式 Per-App Collector + 无状态 Reader。架构差异巨大,迁移不是简单升级。Hadoop 3.0 早期 v2 还有 bug,到 3.1-3.2 才稳定,生产部署要谨慎。
误解二:“Timeline 数据必须实时查询”。Timeline 的写入是异步攒批,事件从产生到可查询有秒级延迟。如果需要实时监控(毫秒级),Timeline 不适合,应该用 Prometheus / OpenTelemetry 等专门的实时指标系统。
误解三:“Timeline v2 取代了日志聚合”。Timeline 记录的是结构化事件(task 启动、counter),日志聚合(YARN Log Aggregation)记录的是 stdout/stderr 文本日志。两个系统职责不同,互不替代。作业调试既要看 Timeline 的事件,也要看聚合日志的 stderr。
误解四:“HBase 后端是 Timeline v2 的可选配置”。Timeline v2 强制使用 HBase,不能换成其他后端。如果集群没有 HBase,Timeline v2 无法启用。这是为什么小集群经常不开 Timeline v2——HBase 部署成本太高,不如直接用日志聚合。
误解五:“Timeline 数据应该长期保留”。Timeline 数据是作业历史,理论上对调试和审计有价值。但 HBase 存储成本高,长期保留所有事件会让 HBase 集群膨胀。生产环境通常设置 TTL(默认 7 天,关键事件更长),让旧数据自动过期。
练习
-
在启用 Timeline v2 的集群上提交一个 MapReduce 作业,用
curl http://timeline-reader:8198/ws/v2/timeline/apps/{appId}/entities/YARN_APPLICATION查询作业事件。观察 entity 的 attributes 和 timestamps。 -
在 HBase shell 里
scan 'timelineservice.app_flow_table', {LIMIT => 5},观察 Timeline 数据的 rowkey 结构(cluster + flow + run + app 复合)。 -
在
apache/hadoop源码里找到TimelineCollector.java、TimelineReaderServer.java、HBaseTimelineWriterImpl.java、HBaseTimelineReaderImpl.java(hadoop-yarn-server-common-timeline / hadoop-yarn-server-timeline-plugin 模块),观察 v2 架构的核心实现。 -
思考题:如果让 Timeline v2 后端换成 HBase 之外的存储(例如 ClickHouse 或 TimescaleDB),需要改写哪些组件?这种替换在什么场景有价值?
系列导航
| 序号 | 主题 | 状态 |
|---|---|---|
| 00-06 | HDFS 存储层(00 导读 / 01-06 HDFS 各主题) | 第一阶段(已完成) |
| 07 | YARN 架构:ResourceManager、NodeManager、ApplicationMaster 的三方契约 | |
| 08 | 资源模型:Resource、Container 与 NodeLabel | |
| 09 | 调度器对比:FIFO、Capacity、Fair 的设计取舍 | |
| 10 | 应用程序生命周期:提交、调度、启动、运行、完成 | |
| 11 | YARN HA 与 Federation | 上一篇 |
| 12 | YARN Timeline Service v2:通用的应用历史与指标 | 本篇(YARN 篇完结) |
| 13-15 | MapReduce 计算模型(编程模型 / Shuffle / MRv2 on YARN) | 第三阶段,下一篇开始 |
参考资料
- Vinod Kumar Vavilapalli et al. Apache Hadoop YARN: Yet Another Resource Negotiator. SOCC 2013. 描述了 Timeline v1 的早期设计。
- Li Lu, Wei Yan. YARN-4236: Timeline Service v2 Architecture.(Apache JIRA,v2 的核心设计文档)
- Apache Hadoop 官方文档:Timeline Service v2. https://hadoop.apache.org/docs/current/hadoop-yarn/hadoop-yarn-site/TimelineServiceV2.html
- Apache Hadoop 官方文档:Timeline Server REST API. https://hadoop.apache.org/docs/current/hadoop-yarn/hadoop-yarn-site/TimelineServer.html
- Apache Hadoop 源码:
TimelineCollector.java、TimelineReaderServer.java、HBaseTimelineWriterImpl.java. https://github.com/apache/hadoop - Sergey V. et al. Apache HBase: The Definitive Guide. O’Reilly, 2015.(HBase LSM-Tree 与 rowkey 设计,理解 Timeline v2 后端的基础)
