前阵子凌晨2点多,线上一个实时链路的数据倾斜任务突然失败,当时我人在家里只来得及瞄了一眼异常概览,想着第二天到公司再拉完整日志复盘。结果早上到公司打开 JobManager 的 Web UI,里面干干净净——因为集群在这期间被运维重新拉起过,JobManager 内存里的作业状态全没了,运行到一半的异常堆栈、算子耗时分布、Checkpoint 记录全部清零。从那一刻起,我就在每一套 Flink 集群上部署了 History Server。现在哪怕整个集群已经停机,我依然能打开 Web UI 查看所有已完成作业的运行数据,也可以通过 REST API 把失败作业的异常信息批量拉出来做复盘。这篇文章就系统聊聊这套东西的部署配置、实际用法和我在生产环境踩过的坑。
1. 先搞清楚 History Server 到底解决了什么问题
1.1 一个真实痛点:集群重启后作业数据一夜清零
先做个模拟。假设你凌晨有一个作业跑挂了,JobManager 重启之前,你根本来不及记录完整信息。等你回到工位,想打开 Web UI 找到那个作业,看一眼失败原因、哪个算子出问题、Checkpoint 卡在哪一步,结果页面空白,作业 ID 都查不到。之所以会这样,是因为 Flink 作业的运行时状态默认保存在 JobManager 的内存里,JobManager 进程一去,这些信息就跟着丢了。做过大数据运维的朋友都知道,这种“事后想复盘却找不到数据”的体验有多折磨人。
History Server 的核心价值就在这:JobManager 在作业到达终态(FINISHED、CANCELED、FAILED)时,会把作业的完整元数据、执行计划、运行统计、异常信息等打包成归档文件,写到一份持久化存储里(一般是 HDFS、S3,也可以是本地磁盘)。History Server 是一个独立的轻量级进程,它不依赖 JobManager 是否存活,只需要能读到归档文件,就能在 Web UI 和 REST API 上还原出这些作业的运行情况。简单说,只要归档文件还在,集群停了也不妨碍你看数据。
1.2 理解它的原理:从归档文件里恢复作业视图
History Server 的工作机制可以拆成三步。第一步,JobManager 在作业运行期间和结束之后,会定期把作业的概要信息、执行图、各顶点的指标、异常信息等序列化成 JSON 格式的归档文件,写入 jobmanager.archive.fs.dir 指定的目录。第二步,History Server 进程启动后,会周期性地扫描 historyserver.archive.fs.dir 指定的目录,把新出现的归档文件读取并缓存到自己的内存里,重建出作业的运行视图。第三步,用户访问 History Server 的 Web UI 或 REST 接口时,看到的就是从这些归档文件还原出来的数据。
这里有个细节值得注意:归档文件在作业运行过程中就可能持续写入,但 History Server 通常只把“已经进入终态”的作业加载到自己的列表里,还在 RUNNING 状态的作业,即使归档文件里有部分数据,也不会通过 History Server 对外展示。所以你要记住一个边界——History Server 管的是“历史完成作业”,实时看运行状态还得靠 JobManager 自己的 Web UI。
1.3 它和 JobManager Web UI 的分工
生产环境里这两者最好搭配着用,而不是二选一。JobManager Web UI 负责“此刻发生了什么”,比如当前正在运行的作业、实时指标、连接状态、反压情况,这些都是需要从 JobManager 内存里拿的,集群一重启就没了。History Server 负责“之前发生了什么”,比如上周某个作业失败时的完整异常堆栈、当时每个算子的耗时分布、Checkpoint 成功与否的时间线,这些数据从持久化的归档文件里读,不受集群生命周期影响。
所以我在每套集群上都把这两套东西同时部署。日常排查用 JobManager UI,事后复盘、周报统计、故障回溯用 History Server,两者数据互补,基本
