深入 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 侧应用级 collector 加 NodeManager 内嵌 collector;读侧改造成独立 TimelineReader + 可扩展 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 比 v1 更容易扩展。事件被分散到 application-level collector 和 NM collector,再批量写 HBase;读取侧通过 TimelineReader 的 REST API 查 HBase。
为什么 3.4.1 的官方路径选择 HBase 而不是 HDFS?因为 Timeline 数据的访问模式是"按 app-id / entity-type / time-range 查询",不是顺序扫描。HDFS 适合大文件顺序读,按 key 查询需要 NameNode 元数据 + DataNode 随机读,性能差。HBase 的 LSM-Tree + RegionServer 天然支持按 rowkey 高效查询,是 Timeline 系统的官方后端选择。
Per-App TimelineCollector
v2 的核心创新是 application-level TimelineCollector。Hadoop 3.4.1 文档把它描述为与对应 AM 共置、在本版本中作为 NodeManager auxiliary service 运行的 collector。AM 内部产生的事件(task 启动、task 完成、counter 更新)先交给该应用的 collector,再由 collector 写入后端。
1 | |
Collector 会按配置周期 flush 到 HBase,yarn.timeline-service.writer.flush-interval-seconds 在 Hadoop 3.4.1 的默认值是 60 秒。这里不要写成固定的环形 buffer,也不要写成"减少 100 倍"这类未验证性能数字;可确认的机制是分布式 collector 承担写入入口,后端由 HBase 存储。
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 的读取侧组件,默认 HTTP 地址是 ${yarn.timeline-service.hostname}:8188,HTTPS 地址是 ${yarn.timeline-service.hostname}:8190。3.4.1 的 REST 根路径固定在 /ws/v2/timeline/:
1 | |
这套 REST API 支持 flow / run / app / entity 四个层级的查询。省略 cluster 的 endpoint 会使用 yarn.resourcemanager.cluster-id,而 flow/run 相关 endpoint 在 3.4.1 文档里包含 users/{user name} 这一层路径。
Reader 是独立的查询服务,它把 REST 查询转成对 HBase 后端的读取。3.4.1 文档写明 reader 是单实例;如果要做多实例负载均衡,需要按具体部署能力单独验证,不能把它写成默认架构。
Hadoop 自带的 YARN UI 可以通过 TimelineReader REST API 查询应用、attempt、container 和框架 entity。第三方 UI 是否读取 Timeline v2 数据取决于各自集成,不能从 TimelineReader 的存在反推出已经支持。
与计算框架的集成
Timeline v2 的价值依赖计算框架主动上报事件。Hadoop 3.4.1 文档明确说 Distributed Shell 和 MapReduce 可以写入 per-framework 数据,其他框架要以各自官方集成为准:
Distributed Shell:作为 YARN 示例应用,可以写入 Timeline Service v2。
MapReduce(MRv2):启用 mapreduce.job.emit-timeline-data=true 后,MapReduce 框架数据可以通过 MRAppMaster 写入 Timeline Service v2。
其他 AM 框架需要使用 Timeline v2 client 主动上报 entity、event 和 metric。AM 使用 AMRMClient 时可以注册 Timeline v2 client;否则需要从 AllocateResponse 里的 collector info 取得 collector 地址。框架不集成时,Timeline v2 仍可保留 YARN 通用生命周期事件和系统指标,但框架内部的 task、stage、counter 细节不会自动出现。
实验:观察 Timeline Service
实验状态:UNVERIFIED_RUNTIME。下面是按 Hadoop 3.4.1 文档整理的验证步骤和查询路径,本轮没有连接真实 YARN + HBase 集群执行。
部署 Timeline v2 的集群,配置 yarn.timeline-service.enabled=true 和 yarn.timeline-service.version=2.0f。如果同时启用 1.5 和 v2,则配置 yarn.timeline-service.versions=1.5f,2.0f;未配置 versions 时,它回落到 yarn.timeline-service.version。TimelineReader 默认 HTTP 端口是 8188。提交一个启用 mapreduce.job.emit-timeline-data=true 的 MapReduce 作业后,用 REST API 查询作业事件:
1 | |
输出 JSON 格式的事件列表,每个事件包含 entity type、timestamp、attributes 等。
HBase 后端可以直接查询数据:
1 | |
可以看到 Timeline 数据按 rowkey 存放在 HBase。表名前缀默认是 prod.,具体表名来自 Hadoop 3.4.1 的 Timeline Service v2 schema,而不是 timelineservice.* 这类通配命名。
Reader 根路径 http://timeline-reader-host:8188/ws/v2/timeline/ 会返回服务与版本信息。RM Web UI 是否跳到 Timeline 页面取决于部署的 UI 版本和集成方式,排障时先验证 Reader REST,再看 UI。
模式提炼
Timeline Service v2 体现的设计模式:
1 | |
这个模式不只是 Timeline。Kafka producer 也用类似的本地攒批与批量网络写入。Spark Event Log 是 driver 记录事件并持久化到文件系统的模式,差异在 Spark 用顺序追加文件,Timeline 用 HBase LSM-Tree。Prometheus Pushgateway 适合短生命周期 batch job 暂存指标,不能替代通用分布式时序库。
数据模型的多级聚合(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 |
|---|---|---|---|---|
| Application-level Collector | Driver 内 Event Log writer | JobManager 内 metric registry | Worker 内状态上报 | 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 默认把事件写到文件系统上的顺序日志,History Server 再读取这些日志。Timeline v2 把数据放到 HBase,提供统一的 YARN entity 查询接口;具体计算框架是否把自己的内部事件写进去,要看框架自身集成。
常见误解
误解一:“Timeline v2 只是 v1 的优化版本”。v2 与 v1 是完全不同的架构——v1 是集中式 Timeline Server,v2 是分布式 application-level collector + 独立 TimelineReader。架构差异巨大,迁移不是简单升级。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 的可选配置”。Hadoop 3.4.1 的 Timeline v2 文档把 HBase 写成主后端,默认 writer/reader 都是 HBase storage 实现;同页部署步骤也要求准备 HBase、启用 coprocessor、创建 schema。如果集群没有 HBase,按官方路径就无法完整启用 v2。
误解五:“Timeline 数据应该长期保留”。Timeline 数据是作业历史,理论上对调试和审计有价值。但 HBase 存储成本高,长期保留所有事件会让 HBase 集群膨胀。v1 的 Timeline Server 文档有 7 天 TTL 默认值;v2 的保留策略要按 HBase schema、表 TTL 和集群策略配置,不能直接把 v1 TTL 当成 v2 行为。
练习
-
在启用 Timeline v2 的集群上提交一个开启
mapreduce.job.emit-timeline-data=true的 MapReduce 作业,用curl http://timeline-reader:8188/ws/v2/timeline/apps/{appId}/entities/YARN_APPLICATION查询作业事件。观察 entity 的 attributes 和 timestamps。 -
在 HBase shell 里列出
prod.*表并抽样扫描应用到 flow 的映射表,观察 Timeline 数据的 rowkey 结构。 -
在
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),需要改写哪些组件?这种替换在什么场景有价值?
系列导航
参考资料
- Vinod Kumar Vavilapalli et al. Apache Hadoop YARN: Yet Another Resource Negotiator. SOCC 2013. 描述了 Timeline v1 的早期设计。
- Apache Hadoop JIRA. YARN-2928: YARN Timeline Service v.2: alpha 1.(Timeline Service v2 早期实现与设计跟踪)
- Apache Hadoop 官方文档:Timeline Service v2. https://hadoop.apache.org/docs/r3.4.1/hadoop-yarn/hadoop-yarn-site/TimelineServiceV2.html
- Apache Hadoop 3.4.1
yarn-default.xml:Timeline v2 默认值。https://apache.googlesource.com/hadoop/+/refs/tags/rel/release-3.4.1/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/resources/yarn-default.xml - Apache Hadoop 官方文档:Timeline Server REST API. https://hadoop.apache.org/docs/r3.4.1/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 后端的基础)
