package org.apache.hadoop.mapred;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.mapred.JobConf;
import org.apache.hadoop.mapred.TaskTracker;
import org.apache.hadoop.metrics.MetricsContext;
import org.apache.hadoop.metrics.MetricsRecord;
import org.apache.hadoop.metrics.MetricsUtil;
import org.apache.hadoop.metrics.Updater;
import org.apache.hadoop.metrics.util.MetricsBase;
import org.apache.hadoop.metrics.util.MetricsRegistry;
import org.apache.hadoop.metrics.util.MetricsTimeVaryingRate;
import org.apache.hadoop.util.StringUtils;
public class MultiTaskTracker {
private static final Log LOG = LogFactory.getLog(MultiTaskTracker.class);
public static class MultiTaskTrackerMetrics implements Updater {
/** Registry of a subset of metrics */
private final MetricsRegistry registry = new MetricsRegistry();
private final MetricsRecord metricsRecord;
private final List<TaskTracker> trackerList;
/** Aggregates the metrics between task trackers for task launch */
private final MetricsTimeVaryingRate aggTaskLaunchMsecs =
new MetricsTimeVaryingRate("taskLaunchMsecs", registry,
"Msecs to launch a task after getting request.", true);
public MultiTaskTrackerMetrics(List<TaskTracker> trackerList) {
this.trackerList = trackerList;
MetricsContext context = MetricsUtil.getContext("mapred");
metricsRecord = MetricsUtil.createRecord(context, "multitasktracker");
context.registerUpdater(this);
}
@Override
public void doUpdates(MetricsContext context) {
LOG.info("Updating metrics");
int numTrackers = trackerList.size();
long totalMapRefill = 0;
long totalReduceRefill = 0;
int totalRunningMaps = 0;
int totalRunningReduces = 0;
int totalMapSlots = 0;
int totalReduceSlots = 0;
for (TaskTracker tracker : trackerList) {
totalMapRefill += tracker.getAveMapSlotRefillMsecs();
totalReduceRefill += tracker.getAveReduceSlotRefillMsecs();
totalRunningMaps += tracker.getRunningMaps();
totalRunningReduces += tracker.getRunningReduces();
totalMapSlots += tracker.getMaxActualMapTasks();
totalReduceSlots += tracker.getMaxActualReduceTasks();
// If the metrics exists, aggregate the task launch msecs for all
// trackers
TaskTrackerInstrumentation instrumentation =
tracker.getTaskTrackerInstrumentation();
if (instrumentation != null) {
MetricsTimeVaryingRate taskLaunchMsecs =
instrumentation.getTaskLaunchMsecs();
if (taskLaunchMsecs != null) {
taskLaunchMsecs.pushMetric(null);
aggTaskLaunchMsecs.inc(
taskLaunchMsecs.getPreviousIntervalAverageTime());
}
}
}
long avgMapRefill = totalMapRefill / numTrackers;
long avgReduceRefill = totalReduceRefill / numTrackers;
metricsRecord.setMetric("aveMapSlotRefillMsecs", avgMapRefill);
metricsRecord.setMetric("aveReduceSlotRefillMsecs", avgReduceRefill);
metricsRecord.setMetric("maps_running", totalRunningMaps);
metricsRecord.setMetric("reduces_running", totalRunningReduces);
metricsRecord.setMetric("mapTaskSlots", totalMapSlots);
metricsRecord.setMetric("reduceTaskSlots", totalReduceSlots);
for (MetricsBase metricsBase : registry.getMetricsList()) {
metricsBase.pushMetric(metricsRecord);
}
metricsRecord.update();
}
}
public static void main(String[] args) throws Exception {
StringUtils.startupShutdownMessage(MultiTaskTracker.class, args, LOG);
LOG.debug("MultiTaskTracker starting");
int numTaskTrackers = Integer.parseInt(args[0]);
String ttType = "mapred";
Class ttClass = TaskTracker.class;
if (args.length > 1) {
ttType = args[1];
}
if (ttType.equals("corona")) {
ttClass = Class.forName("org.apache.hadoop.mapred.CoronaTaskTracker");
}
List<TaskTrackerRunner> runners = new ArrayList<TaskTrackerRunner>();
List<TaskTracker> trackerList = new ArrayList<TaskTracker>();
LOG.info("Will start " + numTaskTrackers + " " + ttType + " trackers");
for (int i = 0; i < numTaskTrackers; i++) {
Configuration conf = new Configuration();
JobConf jConf = new JobConf(conf);
jConf.set("mapred.task.tracker.http.address", "0.0.0.0:0");
jConf.setBoolean("mapred.tasktracker.simulated.tasks", true);
jConf.setBoolean("mapred.tasktracker.task.completion.event.store", true);
// Dummy instrumentation.
jConf.set("mapred.tasktracker.instrumentation",
TaskTrackerInstrumentation.class.getName());
String[] baseLocalDirs = jConf.getLocalDirs();
List<String> localDirs = new LinkedList<String>();
localDirs.clear();
for (String localDir : baseLocalDirs) {
File baseLocalDir = new File(localDir);
File localDirFile = new File(baseLocalDir, "TT_" + i);
localDirFile.mkdirs();
localDirs.add(localDirFile.getAbsolutePath());
}
jConf.setStrings("mapred.local.dir",
localDirs.toArray(new String[localDirs.size()]));
TaskTracker tracker = createTaskTracker(jConf, ttClass);
trackerList.add(tracker);
TaskTrackerRunner runner = new TaskTrackerRunner(i, tracker);
runner.setDaemon(true);
runners.add(runner);
runner.start();
LOG.info("Started tracker# " + i);
}
MultiTaskTrackerMetrics metrics = new MultiTaskTrackerMetrics(trackerList);
for (TaskTrackerRunner runner : runners) {
try {
runner.join();
} catch (InterruptedException iex) {
}
}
}
public static TaskTracker createTaskTracker(JobConf jConf, Class ttClass)
throws IOException {
try {
Constructor<?> constructor =
ttClass.getDeclaredConstructor(new Class[]{JobConf.class});
TaskTracker tt =
(TaskTracker) constructor.newInstance(jConf);
return tt;
} catch (NoSuchMethodException e) {
throw new IOException(e);
} catch (InvocationTargetException e) {
throw new IOException(e);
} catch (InstantiationException e) {
throw new IOException(e);
} catch (IllegalAccessException e) {
throw new IOException(e);
}
}
private static class TaskTrackerRunner extends Thread {
private TaskTracker ttToRun = null;
private int id;
public TaskTrackerRunner(int id, TaskTracker tt) {
super();
this.ttToRun = tt;
this.id = id;
}
@Override
public void run() {
LOG.debug("Running TT #" + id);
ttToRun.run();
}
}
}