diff --git a/hadoop-yarn-project/CHANGES.txt b/hadoop-yarn-project/CHANGES.txt index 0a3ee69a28c..107a502ab95 100644 --- a/hadoop-yarn-project/CHANGES.txt +++ b/hadoop-yarn-project/CHANGES.txt @@ -341,6 +341,9 @@ Release 0.23.7 - UNRELEASED YARN-227. Application expiration difficult to debug for end-users (Jason Lowe via jeagles) + YARN-443. allow OS scheduling priority of NM to be different than the + containers it launches (tgraves) + OPTIMIZATIONS YARN-357. App submission should not be synchronized (daryn) diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java index 5c22a7d2a4f..fcd22cbc8b7 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-common/src/main/java/org/apache/hadoop/yarn/conf/YarnConfiguration.java @@ -304,6 +304,17 @@ public class YarnConfiguration extends Configuration { /** who will execute(launch) the containers.*/ public static final String NM_CONTAINER_EXECUTOR = NM_PREFIX + "container-executor.class"; + + /** + * Adjustment to make to the container os scheduling priority. + * The valid values for this could vary depending on the platform. + * On Linux, higher values mean run the containers at a less + * favorable priority than the NM. + * The value specified is an int. + */ + public static final String NM_CONTAINER_EXECUTOR_SCHED_PRIORITY = + NM_PREFIX + "container-executor.os.sched.priority.adjustment"; + public static final int DEFAULT_NM_CONTAINER_EXECUTOR_SCHED_PRIORITY = 0; /** Number of threads container manager uses.*/ public static final String NM_CONTAINER_MGR_THREAD_COUNT = diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/ContainerExecutor.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/ContainerExecutor.java index 9cffde1a65d..a954e5787e3 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/ContainerExecutor.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/ContainerExecutor.java @@ -20,6 +20,8 @@ package org.apache.hadoop.yarn.server.nodemanager; import java.io.IOException; import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -35,6 +37,7 @@ import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.permission.FsPermission; import org.apache.hadoop.util.Shell.ShellCommandExecutor; import org.apache.hadoop.yarn.api.records.ContainerId; +import org.apache.hadoop.yarn.conf.YarnConfiguration; import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.Container; import org.apache.hadoop.yarn.server.nodemanager.util.ProcessIdFileReader; @@ -183,6 +186,23 @@ public abstract class ContainerExecutor implements Configurable { } } + + /** + * Return a command to execute the given command in OS shell. + */ + protected static String[] getRunCommand(String command, Configuration conf) { + List retCommand = new ArrayList(); + if (conf.get(YarnConfiguration.NM_CONTAINER_EXECUTOR_SCHED_PRIORITY) != + null) { + int containerSchedPriorityAdjustment = conf + .getInt(YarnConfiguration.NM_CONTAINER_EXECUTOR_SCHED_PRIORITY, 0); + retCommand.addAll(Arrays.asList("nice", "-n", + Integer.toString(containerSchedPriorityAdjustment))); + } + retCommand.addAll(Arrays.asList("bash", "-c", command)); + return retCommand.toArray(new String[retCommand.size()]); + } + /** * Is the container still active? * @param containerId diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/DefaultContainerExecutor.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/DefaultContainerExecutor.java index 27730f421b6..c285cf062d6 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/DefaultContainerExecutor.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/DefaultContainerExecutor.java @@ -170,8 +170,10 @@ public class DefaultContainerExecutor extends ContainerExecutor { ContainerExecutor.TASK_LAUNCH_SCRIPT_PERMISSION); // Setup command to run - String[] command = {"bash", - wrapperScriptDst.toUri().getPath().toString()}; + String[] command = getRunCommand(wrapperScriptDst.toUri().getPath().toString(), + this.getConf()); + + // Setup command to run LOG.info("launchContainer: " + Arrays.toString(command)); shExec = new ShellCommandExecutor( command, diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/LinuxContainerExecutor.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/LinuxContainerExecutor.java index e1c86eb7141..1b3d2a222e8 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/LinuxContainerExecutor.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/LinuxContainerExecutor.java @@ -50,6 +50,8 @@ public class LinuxContainerExecutor extends ContainerExecutor { private String containerExecutorExe; private LCEResourcesHandler resourcesHandler; + private boolean containerSchedPriorityIsSet = false; + private int containerSchedPriorityAdjustment = 0; @Override @@ -61,8 +63,16 @@ public class LinuxContainerExecutor extends ContainerExecutor { conf.getClass(YarnConfiguration.NM_LINUX_CONTAINER_RESOURCES_HANDLER, DefaultLCEResourcesHandler.class, LCEResourcesHandler.class), conf); resourcesHandler.setConf(conf); + if (conf.get(YarnConfiguration.NM_CONTAINER_EXECUTOR_SCHED_PRIORITY) != null) { + containerSchedPriorityIsSet = true; + containerSchedPriorityAdjustment = conf + .getInt(YarnConfiguration.NM_CONTAINER_EXECUTOR_SCHED_PRIORITY, + YarnConfiguration.DEFAULT_NM_CONTAINER_EXECUTOR_SCHED_PRIORITY); + } } + + /** * List of commands that the setuid script will execute. */ @@ -114,6 +124,13 @@ public class LinuxContainerExecutor extends ContainerExecutor { : conf.get(YarnConfiguration.NM_LINUX_CONTAINER_EXECUTOR_PATH, defaultPath); } + protected void addSchedPriorityCommand(List command) { + if (containerSchedPriorityIsSet) { + command.addAll(Arrays.asList("nice", "-n", + Integer.toString(containerSchedPriorityAdjustment))); + } + } + @Override public void init() throws IOException { // Send command to executor which will just start up, @@ -145,14 +162,15 @@ public class LinuxContainerExecutor extends ContainerExecutor { List localDirs, List logDirs) throws IOException, InterruptedException { - List command = new ArrayList( - Arrays.asList(containerExecutorExe, - user, - Integer.toString(Commands.INITIALIZE_CONTAINER.getValue()), - appId, - nmPrivateContainerTokensPath.toUri().getPath().toString(), - StringUtils.join(",", localDirs), - StringUtils.join(",", logDirs))); + List command = new ArrayList(); + addSchedPriorityCommand(command); + command.addAll(Arrays.asList(containerExecutorExe, + user, + Integer.toString(Commands.INITIALIZE_CONTAINER.getValue()), + appId, + nmPrivateContainerTokensPath.toUri().getPath().toString(), + StringUtils.join(",", localDirs), + StringUtils.join(",", logDirs))); File jvm = // use same jvm as parent new File(new File(System.getProperty("java.home"), "bin"), "java"); @@ -212,7 +230,9 @@ public class LinuxContainerExecutor extends ContainerExecutor { try { Path pidFilePath = getPidFilePath(containerId); if (pidFilePath != null) { - List command = new ArrayList(Arrays.asList( + List command = new ArrayList(); + addSchedPriorityCommand(command); + command.addAll(Arrays.asList( containerExecutorExe, user, Integer .toString(Commands.LAUNCH_CONTAINER.getValue()), appId, containerIdStr, containerWorkDir.toString(), diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/TestLinuxContainerExecutorWithMocks.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/TestLinuxContainerExecutorWithMocks.java index dfaf0460c4f..3b62277b1f0 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/TestLinuxContainerExecutorWithMocks.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/TestLinuxContainerExecutorWithMocks.java @@ -27,6 +27,7 @@ import java.io.FileReader; import java.io.IOException; import java.io.LineNumberReader; import java.net.InetSocketAddress; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedList; @@ -131,8 +132,40 @@ public class TestLinuxContainerExecutorWithMocks { } + @Test (timeout = 5000) + public void testContainerLaunchWithPriority() throws IOException { + + // set the scheduler priority to make sure still works with nice -n prio + File f = new File("./src/test/resources/mock-container-executor"); + if (!f.canExecute()) { + f.setExecutable(true); + } + String executorPath = f.getAbsolutePath(); + Configuration conf = new Configuration(); + conf.set(YarnConfiguration.NM_LINUX_CONTAINER_EXECUTOR_PATH, executorPath); + conf.setInt(YarnConfiguration.NM_CONTAINER_EXECUTOR_SCHED_PRIORITY, 2); + + mockExec.setConf(conf); + List command = new ArrayList(); + mockExec.addSchedPriorityCommand(command); + assertEquals("first should be nice", "nice", command.get(0)); + assertEquals("second should be -n", "-n", command.get(1)); + assertEquals("third should be the priority", Integer.toString(2), + command.get(2)); + + testContainerLaunch(); + } + + @Test (timeout = 5000) + public void testLaunchCommandWithoutPriority() throws IOException { + // make sure the command doesn't contain the nice -n since priority + // not specified + List command = new ArrayList(); + mockExec.addSchedPriorityCommand(command); + assertEquals("addSchedPriority should be empty", 0, command.size()); + } - @Test + @Test (timeout = 5000) public void testStartLocalizer() throws IOException {