在使用YARN SLS时,我们经常需要分析其运行结束时生成的jobruntime.csv文件来对调度效果进行分析。但是可以发现,在jobruntime.csv中每个Application的信息反复输出了两次,并且simulate_end_time
时间不尽相同。为了了解其原因,我阅读了SLS的实现代码,弄清楚了其背后的原因。
使用的Hadoop版本为2.9.2,全部代码都在org.apache.hadoop.yarn.sls
下。
在appmaster.AMSimulator.lastStep()
中,有schedulerMetrics.addAMRuntime(appId, traceStartTimeMS, traceFinishTimeMS, simulateStartTimeMS, simulateFinishTimeMS);
这行代码。它的作用是在jobruntime.csv中写入一行数据,比如说application_1547030914929_0001,0,99375,1547030917579,1547031029590
。
整个SLS中只有两个地方调用了appmaster.AMSimulator.lastStep()
。一个在appmaster.AMSimulator.run()
直接调用,一个在appmaster.AMSimulator.run()
调用的appmaster.AMSimulator.middleStep()
中的appmaster.MRAMSimulator.processResponseQueue()
调用。直接调用的条件是nextRun > endTime
,也就是在运行即将结束的最后一次模拟时调用;间接调用的条件是mapFinished >= mapTotal && reduceFinished >= reduceTotal
,也就是map、reduce任务完成的时候。在使用官网的例子时,日志会输出
19/01/09 10:05:21 INFO appmaster.MRAMSimulator: Added new job with 96 mapper and 0 reducers
19/01/09 10:05:21 INFO appmaster.MRAMSimulator: Added new job with 96 mapper and 0 reducers
而在日志中刚好有192次Application ${application_id} has one mapper finished
的输出,可以证明这个结论。
因此,可以得出结论,在jobruntime.csv中第一次记录是由appmaster.AMSimulator.middleStep()
间接调用appmaster.AMSimulator.lastStep()
产生的,第二次是直接调用appmaster.AMSimulator.lastStep()
产生的。
同时,也可以注意到最后一个记录只有一个,而不是两个,例如在官网数据的日志
JobID,real_start_time,real_end_time,simulate_start_time,simulate_end_time
application_1547030914929_0001,0,99375,1547030917579,1547031029590
application_1547030914929_0001,0,99375,1547030917579,1547031030584
application_1547030914929_0002,105204,197256,1547031022783,1547031140787
中application_1547030914929_0002
只有一个,这是因为SLSRunner.decreaseRemainingApps()
的缘故。这个函数在APP_ATTEMPT_REMOVED
事件被触发的时候在scheduler.SLSCapacityScheduler.handle()
或scheduler.SLSFairScheduler.handle()
中被调用,而它会在remainingApps == 0
时把SLS tear down。最后一个应用在第一次执行lastStep()
时就调用了finishApplicationMaster()
,之后一系列调用后发送了APP_ATTEMPT_REMOVED
事件,也就把SLS停止了,不会调用第二次lastStep()
,所以也不会写两遍了。
可以判断,输出两次不是自己的配置出现了问题,而是SLS设计的会输出两次。至于原因,则有待探究。