diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/CGroupsMemoryResourceHandlerImpl.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/CGroupsMemoryResourceHandlerImpl.java index 053b796b5fd..fb56dac9fa4 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/CGroupsMemoryResourceHandlerImpl.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/CGroupsMemoryResourceHandlerImpl.java @@ -19,6 +19,8 @@ package org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.resources; import com.google.common.annotations.VisibleForTesting; +import org.apache.hadoop.yarn.server.nodemanager.util.NodeManagerHardwareUtils; +import org.apache.hadoop.yarn.util.ResourceCalculatorPlugin; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.hadoop.classification.InterfaceAudience; @@ -68,6 +70,13 @@ @Override public List bootstrap(Configuration conf) throws ResourceHandlerException { + return bootstrap( + ResourceCalculatorPlugin.getResourceCalculatorPlugin(null, conf), conf); + } + + @VisibleForTesting + public List bootstrap(ResourceCalculatorPlugin plugin, + Configuration conf) throws ResourceHandlerException { this.cGroupsHandler.initializeCGroupController(MEMORY); enforce = conf.getBoolean( YarnConfiguration.NM_MEMORY_RESOURCE_ENFORCED, @@ -90,9 +99,18 @@ throw new ResourceHandlerException( "Illegal value '" + softLimitPerc + "' " + YarnConfiguration. - NM_MEMORY_RESOURCE_CGROUPS_SOFT_LIMIT_PERCENTAGE + NM_MEMORY_RESOURCE_CGROUPS_SOFT_LIMIT_PERCENTAGE + ". Value must be between 0 and 100."); } + + long yarnMemoryMb = NodeManagerHardwareUtils.getContainerMemoryMB(conf); + long systemMemoryMb = plugin.getAvailablePhysicalMemorySize() / 1024 / 1024; + if (yarnMemoryMb != systemMemoryMb) { + LOG.info("YARN containers restricted memory to " + yarnMemoryMb + "M"); + this.cGroupsHandler.updateCGroupParam(MEMORY, "", + CGroupsHandler.CGROUP_PARAM_MEMORY_HARD_LIMIT_BYTES, + String.valueOf(yarnMemoryMb) + "M"); + } return null; } diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/TestCGroupsMemoryResourceHandlerImpl.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/TestCGroupsMemoryResourceHandlerImpl.java index 4d3e7e6e1d1..2f680b37cca 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/TestCGroupsMemoryResourceHandlerImpl.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/test/java/org/apache/hadoop/yarn/server/nodemanager/containermanager/linux/resources/TestCGroupsMemoryResourceHandlerImpl.java @@ -26,6 +26,7 @@ import org.apache.hadoop.yarn.security.ContainerTokenIdentifier; import org.apache.hadoop.yarn.server.nodemanager.containermanager.container.Container; import org.apache.hadoop.yarn.server.nodemanager.containermanager.linux.privileged.PrivilegedOperation; +import org.apache.hadoop.yarn.util.ResourceCalculatorPlugin; import org.junit.Before; import org.junit.Test; import org.junit.Assert; @@ -43,6 +44,8 @@ private CGroupsHandler mockCGroupsHandler; private CGroupsMemoryResourceHandlerImpl cGroupsMemoryResourceHandler; + private ResourceCalculatorPlugin plugin; + private long nodeMemoryMb = 100; @Before public void setup() { @@ -50,6 +53,8 @@ public void setup() { when(mockCGroupsHandler.getPathForCGroup(any(), any())).thenReturn("."); cGroupsMemoryResourceHandler = new CGroupsMemoryResourceHandlerImpl(mockCGroupsHandler); + plugin = mock(ResourceCalculatorPlugin.class); + when(plugin.getPhysicalMemorySize()).thenReturn(nodeMemoryMb); } @Test @@ -57,8 +62,9 @@ public void testBootstrap() throws Exception { Configuration conf = new YarnConfiguration(); conf.setBoolean(YarnConfiguration.NM_PMEM_CHECK_ENABLED, false); conf.setBoolean(YarnConfiguration.NM_VMEM_CHECK_ENABLED, false); + conf.setLong(YarnConfiguration.NM_PMEM_MB, nodeMemoryMb); List ret = - cGroupsMemoryResourceHandler.bootstrap(conf); + cGroupsMemoryResourceHandler.bootstrap(plugin, conf); verify(mockCGroupsHandler, times(1)) .initializeCGroupController(CGroupsHandler.CGroupController.MEMORY); Assert.assertNull(ret); @@ -66,14 +72,46 @@ public void testBootstrap() throws Exception { cGroupsMemoryResourceHandler.getSwappiness()); conf.setBoolean(YarnConfiguration.NM_PMEM_CHECK_ENABLED, true); try { - cGroupsMemoryResourceHandler.bootstrap(conf); + cGroupsMemoryResourceHandler.bootstrap(plugin, conf); } catch(ResourceHandlerException re) { Assert.fail("Pmem check should be allowed to run with cgroups"); } conf.setBoolean(YarnConfiguration.NM_PMEM_CHECK_ENABLED, false); conf.setBoolean(YarnConfiguration.NM_VMEM_CHECK_ENABLED, true); try { - cGroupsMemoryResourceHandler.bootstrap(conf); + cGroupsMemoryResourceHandler.bootstrap(plugin, conf); + } catch(ResourceHandlerException re) { + Assert.fail("Vmem check should be allowed to run with cgroups"); + } + } + + @Test + public void testBootstrapWithLimit() throws Exception { + Configuration conf = new YarnConfiguration(); + conf.setBoolean(YarnConfiguration.NM_PMEM_CHECK_ENABLED, false); + conf.setBoolean(YarnConfiguration.NM_VMEM_CHECK_ENABLED, false); + conf.setLong(YarnConfiguration.NM_PMEM_MB, nodeMemoryMb +1); + String expectLimit = (nodeMemoryMb +1) + "M"; + List ret = + cGroupsMemoryResourceHandler.bootstrap(plugin, conf); + verify(mockCGroupsHandler, times(1)) + .initializeCGroupController(CGroupsHandler.CGroupController.MEMORY); + verify(mockCGroupsHandler, times(1)).updateCGroupParam( + CGroupsHandler.CGroupController.MEMORY, "", + CGroupsHandler.CGROUP_PARAM_MEMORY_HARD_LIMIT_BYTES, expectLimit); + Assert.assertNull(ret); + Assert.assertEquals("Default swappiness value incorrect", 0, + cGroupsMemoryResourceHandler.getSwappiness()); + conf.setBoolean(YarnConfiguration.NM_PMEM_CHECK_ENABLED, true); + try { + cGroupsMemoryResourceHandler.bootstrap(plugin, conf); + } catch(ResourceHandlerException re) { + Assert.fail("Pmem check should be allowed to run with cgroups"); + } + conf.setBoolean(YarnConfiguration.NM_PMEM_CHECK_ENABLED, false); + conf.setBoolean(YarnConfiguration.NM_VMEM_CHECK_ENABLED, true); + try { + cGroupsMemoryResourceHandler.bootstrap(plugin, conf); } catch(ResourceHandlerException re) { Assert.fail("Vmem check should be allowed to run with cgroups"); } @@ -86,21 +124,21 @@ public void testSwappinessValues() throws Exception { conf.setBoolean(YarnConfiguration.NM_VMEM_CHECK_ENABLED, false); conf.setInt(YarnConfiguration.NM_MEMORY_RESOURCE_CGROUPS_SWAPPINESS, -1); try { - cGroupsMemoryResourceHandler.bootstrap(conf); + cGroupsMemoryResourceHandler.bootstrap(plugin, conf); Assert.fail("Negative values for swappiness should not be allowed."); } catch (ResourceHandlerException re) { // do nothing } try { conf.setInt(YarnConfiguration.NM_MEMORY_RESOURCE_CGROUPS_SWAPPINESS, 101); - cGroupsMemoryResourceHandler.bootstrap(conf); + cGroupsMemoryResourceHandler.bootstrap(plugin, conf); Assert.fail("Values greater than 100 for swappiness" + " should not be allowed."); } catch (ResourceHandlerException re) { // do nothing } conf.setInt(YarnConfiguration.NM_MEMORY_RESOURCE_CGROUPS_SWAPPINESS, 60); - cGroupsMemoryResourceHandler.bootstrap(conf); + cGroupsMemoryResourceHandler.bootstrap(plugin, conf); Assert.assertEquals("Swappiness value incorrect", 60, cGroupsMemoryResourceHandler.getSwappiness()); } @@ -110,7 +148,7 @@ public void testPreStart() throws Exception { Configuration conf = new Configuration(); conf.setBoolean(YarnConfiguration.NM_PMEM_CHECK_ENABLED, false); conf.setBoolean(YarnConfiguration.NM_VMEM_CHECK_ENABLED, false); - cGroupsMemoryResourceHandler.bootstrap(conf); + cGroupsMemoryResourceHandler.bootstrap(plugin, conf); String id = "container_01_01"; String path = "test-path/" + id; ContainerId mockContainerId = mock(ContainerId.class); @@ -155,7 +193,7 @@ public void testPreStartNonEnforced() throws Exception { conf.setBoolean(YarnConfiguration.NM_PMEM_CHECK_ENABLED, false); conf.setBoolean(YarnConfiguration.NM_VMEM_CHECK_ENABLED, false); conf.setBoolean(YarnConfiguration.NM_MEMORY_RESOURCE_ENFORCED, false); - cGroupsMemoryResourceHandler.bootstrap(conf); + cGroupsMemoryResourceHandler.bootstrap(plugin, conf); String id = "container_01_01"; String path = "test-path/" + id; ContainerId mockContainerId = mock(ContainerId.class); @@ -223,7 +261,7 @@ public void testOpportunistic() throws Exception { conf.setBoolean(YarnConfiguration.NM_PMEM_CHECK_ENABLED, false); conf.setBoolean(YarnConfiguration.NM_VMEM_CHECK_ENABLED, false); - cGroupsMemoryResourceHandler.bootstrap(conf); + cGroupsMemoryResourceHandler.bootstrap(plugin, conf); ContainerTokenIdentifier tokenId = mock(ContainerTokenIdentifier.class); when(tokenId.getExecutionType()).thenReturn(ExecutionType.OPPORTUNISTIC); Container container = mock(Container.class); @@ -251,7 +289,7 @@ public void testContainerUnderOom() throws Exception { conf.setBoolean(YarnConfiguration.NM_PMEM_CHECK_ENABLED, false); conf.setBoolean(YarnConfiguration.NM_VMEM_CHECK_ENABLED, false); - cGroupsMemoryResourceHandler.bootstrap(conf); + cGroupsMemoryResourceHandler.bootstrap(plugin, conf); ContainerId containerId = mock(ContainerId.class); when(containerId.toString()).thenReturn("container_01_01");