背景
在我们实际生产开发中,Flink作业通常以per-job的模式提交到yarn集群上运行。当作业结束或因异常退出后,此时无法从yarn web ui上查看具体的日志信息来定位异常问题;如果yarn端未开启日志聚合,yarn logs命令就无法使用了,那么我们也就无法定位问题了。
History Server简介
当相应的Flink Cluster集群down掉后,Flink提供了一个History Server服务可以查询已归档的job,同时也对外提供了接口供用户进行封装获取数据。默认情况下,该服务绑定在localhost:8082端口上,需要用户手动启动。当然也可以把该服务以独立的服务运行,接下来讲解详细配置
相关配置demo
-
下载Flink1.12客户端
wget https://mirror.bit.edu.cn/apache/flink/flink-1.12.0/flink-1.12.0-bin-scala_2.11.tgz
-
修改flink-conf.yaml文件
# 是否清理不存在的作业(即已经过期的) historyserver.archive.clean-expired-jobs:false # 每一个归档目录下可以保留的最大job数,设置为-1即不限制 historyserver.archive.retained-jobs:-1 # HistoryServer 地址 historyserver.web.address:0.0.0.0 # HistoryServer web地址 historyserver.web.port:9999 # web端刷新间隔 historyserver.web.refresh-interval: 10000 # 配置已归档jm路径 jobmanager.archive.fs.dir: hdfs:///project/flink/history-server/ #historyserver监控归档路径,该路径要和jm配置的一样 historyserver.archive.fs.dir:hdfs:///project/flink/history-server/ # 每10s扫描一次归档路径 historyserver.archive.fs.refresh-interval: 10000
-
启动HistoryServer服务
# 注意:要先配置Hadoop环境变量 export HADOOP_CLASSPATH=`hadoop classpath` # 启动服务 bin/historyserver.sh start
-
提交per-job作业,用于测试
bin/flink run -t yarn-per-job --detached ./examples/streaming/TopSpeedWindowing.jar -qu yarn.queue -p 1
-
web端停用该作业
-
查看归档路径信息
-
打开localhost:9999界面即可查看已结束掉的作业
可以看到该historyServer将作业完整的执行计划以及任务信息完整的展示出来,通过该服务可以及时定位到作业异常情况
Rest API
除了上述的web界面可以供用户进行查询,同时也提供了对外接口方便开发者进行封装集成到私有开发平台中。目前已提供的接口如下,所有的请求格式样例均为http://hostname:9999/jobs(注意:这里的9999端口是笔者更改后的)。另尖括号中的值是变量,例如http://hostname:port/jobs/<jobid>/exceptions将必须以http://hostname:port/jobs/7684be6004e4e955c2a558a9bc463f65/exceptions请求.
-
/config
-
/jobs/overview
-
/jobs/<jobid>
-
/jobs/<jobid>/vertices
-
/jobs/<jobid>/config
-
/jobs/<jobid>/exceptions
-
/jobs/<jobid>/accumulators
-
/jobs/<jobid>/vertices/<vertexid>
-
/jobs/<jobid>/vertices/<vertexid>/subtasktimes
-
/jobs/<jobid>/vertices/<vertexid>/taskmanagers
-
/jobs/<jobid>/vertices/<vertexid>/accumulators
-
/jobs/<jobid>/vertices/<vertexid>/subtasks/accumulators
-
/jobs/<jobid>/vertices/<vertexid>/subtasks/<subtasknum>
-
/jobs/<jobid>/vertices/<vertexid>/subtasks/<subtasknum>/attempts/<attempt>
-
/jobs/<jobid>/vertices/<vertexid>/subtasks/<subtasknum>/attempts/<attempt>/accumulators
-
/jobs/<jobid>/plan
这里的接口返回示例不再给出,读者们有兴趣可自行调试。
源码分析
HistoryServer的源码部分相对比较简单清晰,同时这里也把如何看源码的经验分享给大家。
-
首先一开始我们是通过historyserver.sh脚本来启动HistoryServer服务,那么这里先看下脚本的功能(一般其他相关框架的源码入口也是从脚本开始着手的,对hadoop熟悉的读者应该比较清楚)
可以看到,当我们使用start参数来启动的时候,调用的是flink-daemon.sh脚本
-
通过第一个脚本发现,在调用flink-daemon.sh脚本的时候传入了historyserver参数
-
直接查看HistoryServer类,找到该类时,首先第一步要看的就是类注释,先了解一下该类主要实现什么功能
如截图可见,该类主要是HistoryServer的入口,进行web启动和提供对外接口,同时有一个main方法,那么就方便我们下手了。
-
主要逻辑
//1.参数解析 ParameterTool pt = ParameterTool.fromArgs(args); //2.加载flink-conf.yaml文件 final Configuration flinkConfig = GlobalConfiguration.loadConfiguration(configDir); FileSystem.initialize(flinkConfig, PluginUtils.createPluginManagerFromRootFolder(flinkConfig)); //3.启动HistoryServer SecurityUtils.install(new SecurityConfiguration(flinkConfig)); SecurityUtils.getInstalledContext().runSecured(new Callable<Integer>() { @Override public Integer call() throws Exception { HistoryServer hs = new HistoryServer(flinkConfig); hs.run(); return 0; } });
-
从主入口可以看到,主要是通过调用run方法来启动HistoryServer,而run方法再次调用了start方法
public void run() { start(); } void start() throws IOException, InterruptedException { synchronized (startupShutdownLock) { //1.创建本地目录用于缓存,本地文件路径通过“java.io.tmpdir”参数来配置,文件以flink-web-history-开头 Files.createDirectories(webDir.toPath()); Router router = new Router(); router.addGet("/:*", new HistoryServerStaticFileServerHandler(webDir)); if (!webDir.exists() && !webDir.mkdirs()) { throw new IOException("Failed to create local directory " + webDir.getAbsoluteFile() + "."); } //2.将job信息写到归档目录下的json文件 createDashboardConfigFile(); //3.启动归档Fetcher任务用于扫描归档目录下的所有作业 archiveFetcher.start(); //4.启动web ui netty = new WebFrontendBootstrap(router, LOG, webDir, serverSSLFactory, webAddress, webPort, config); } }
通过以上简单的源码分析,可以大致梳理出HistoryServer的工作原理,即把指定的hdfs归档目录下的作业内容写入到本地的临时目录缓存,大多数是Json文件。然后启动Fetcher任务来定期扫描归档目录下是否有新的作业,然后刷新web ui进行显示。
本地缓存目录
该截图即是本地的缓存目录,该目录下大多是js文件和html相关文件,同时还包含job相关的信息,被写到了json文件中