diff --git a/app-conf/HeuristicConf.xml b/app-conf/HeuristicConf.xml
index bd24e0a72..76086703e 100644
--- a/app-conf/HeuristicConf.xml
+++ b/app-conf/HeuristicConf.xml
@@ -245,6 +245,19 @@
-->
+
+ mapreduce
+ Mapper Data Locality
+ com.linkedin.drelephant.mapreduce.heuristics.MapperTaskLocalityHeuristic
+ views.html.help.mapreduce.helpMapperTaskLocality$$$
+
+
+
+
mapreduce
Reducer Skew
diff --git a/app-conf/JobTypeConf.xml b/app-conf/JobTypeConf.xml
index 90e20f113..817490e83 100644
--- a/app-conf/JobTypeConf.xml
+++ b/app-conf/JobTypeConf.xml
@@ -43,17 +43,11 @@
pig.script
- Hive-Tez
- TEZ
- hive.execution.engine
+ Tez
+ tez
+ hive.mapred.mode
-
- Pig-Tez
- TEZ
- exectype
- TEZ
-
Hive
mapreduce
@@ -86,4 +80,4 @@
mapred.child.java.opts
-
+
\ No newline at end of file
diff --git a/app/com/linkedin/drelephant/mapreduce/data/MapReduceCounterData.java b/app/com/linkedin/drelephant/mapreduce/data/MapReduceCounterData.java
index ae121ef19..196b19693 100644
--- a/app/com/linkedin/drelephant/mapreduce/data/MapReduceCounterData.java
+++ b/app/com/linkedin/drelephant/mapreduce/data/MapReduceCounterData.java
@@ -98,6 +98,7 @@ public static enum GroupName {
FileInput,
FileSystemCounters,
MapReduce,
+ JobCounters,
FileOutput;
}
@@ -131,12 +132,19 @@ public static enum CounterName {
COMBINE_OUTPUT_RECORDS(GroupName.MapReduce, "COMBINE_OUTPUT_RECORDS", "Combine output records"),
SPILLED_RECORDS(GroupName.MapReduce, "SPILLED_RECORDS", "Spilled Records"),
+ DATA_LOCAL_MAPS(GroupName.JobCounters,"DATA_LOCAL_MAPS","Data Local Map tasks"),
+ RACK_LOCAL_MAPS(GroupName.JobCounters,"RACK_LOCAL_MAPS","Rack Local Map Tasks"),
+ OTHER_LOCAL_MAPS(GroupName.JobCounters,"OTHER_LOCAL_MAPS","Other Local Maps"),
+ TOTAL_LAUNCHED_MAPS(GroupName.JobCounters,"TOTAL_LAUNCHED_MAPS","Total Launched Map Tasks"),
+
CPU_MILLISECONDS(GroupName.MapReduce, "CPU_MILLISECONDS", "CPU time spent (ms)"),
GC_MILLISECONDS(GroupName.MapReduce, "GC_TIME_MILLIS", "GC time elapsed (ms)"),
COMMITTED_HEAP_BYTES(GroupName.MapReduce, "COMMITTED_HEAP_BYTES", "Total committed heap usage (bytes)"),
PHYSICAL_MEMORY_BYTES(GroupName.MapReduce, "PHYSICAL_MEMORY_BYTES", "Physical memory (bytes) snapshot"),
VIRTUAL_MEMORY_BYTES(GroupName.MapReduce, "VIRTUAL_MEMORY_BYTES", "Virtual memory (bytes) snapshot");
+
+
GroupName _group;
String _name;
String _displayName;
diff --git a/app/com/linkedin/drelephant/mapreduce/heuristics/MapperTaskLocalityHeuristic.java b/app/com/linkedin/drelephant/mapreduce/heuristics/MapperTaskLocalityHeuristic.java
new file mode 100644
index 000000000..edd2ca146
--- /dev/null
+++ b/app/com/linkedin/drelephant/mapreduce/heuristics/MapperTaskLocalityHeuristic.java
@@ -0,0 +1,107 @@
+package com.linkedin.drelephant.mapreduce.heuristics;
+
+
+import com.linkedin.drelephant.analysis.Heuristic;
+import com.linkedin.drelephant.analysis.HeuristicResult;
+import com.linkedin.drelephant.analysis.Severity;
+import com.linkedin.drelephant.configurations.heuristic.HeuristicConfigurationData;
+import com.linkedin.drelephant.mapreduce.data.MapReduceApplicationData;
+import com.linkedin.drelephant.mapreduce.data.MapReduceCounterData;
+import com.linkedin.drelephant.util.Utils;
+import org.apache.log4j.Logger;
+
+import java.util.Arrays;
+import java.util.Map;
+
+public class MapperTaskLocalityHeuristic implements Heuristic {
+
+ private static final Logger logger = Logger.getLogger(MapperTaskLocalityHeuristic.class);
+
+ // Severity parameters.
+ private static final String NODE_LOCALITY_RATIO = "node_locality_severity";
+ private static final String RACK_LOCALITY_RATIO = "rack_locality_severity";
+ private static final String COUNTER_GROUP_NAME = "org.apache.hadoop.mapreduce.JobCounter";
+ private static final String DATA_LOCAL_MAPS = "DATA_LOCAL_MAPS";
+ private static final String RACK_LOCAL_MAPS = "RACK_LOCAL_MAPS";
+ private static final String OTHER_LOCAL_MAPS = "OTHER_LOCAL_MAPS";
+ private static final String TOTAL_LAUNCHED_MAPS = "TOTAL_LAUNCHED_MAPS";
+
+ private double[] nodeLocalityRatioLimits = {0.5d, 0.4d, 0.3d, 0.2d};
+ private double[] rackLocalityRatioLimits = {0.7d, 0.6d, 0.5d, 0.4d};
+
+ private HeuristicConfigurationData _heuristicConfData;
+
+ private void loadParameters() {
+ Map paramMap = _heuristicConfData.getParamMap();
+ String heuristicName = _heuristicConfData.getHeuristicName();
+
+ double[] nodeLocalityThreshold = Utils.getParam(paramMap.get(NODE_LOCALITY_RATIO), nodeLocalityRatioLimits.length);
+ if (nodeLocalityThreshold != null) {
+ nodeLocalityRatioLimits = nodeLocalityThreshold;
+ }
+ logger.info(heuristicName + " will use " + NODE_LOCALITY_RATIO + " with the following threshold settings: "
+ + Arrays.toString(nodeLocalityRatioLimits));
+
+ double[] rackLocalityThreshold = Utils.getParam(paramMap.get(RACK_LOCALITY_RATIO), rackLocalityRatioLimits.length);
+ if (nodeLocalityThreshold != null) {
+ rackLocalityRatioLimits = rackLocalityThreshold;
+ }
+ logger.info(heuristicName + " will use " + RACK_LOCALITY_RATIO + " with the following threshold settings: "
+ + Arrays.toString(nodeLocalityRatioLimits));
+
+ }
+
+ public MapperTaskLocalityHeuristic(HeuristicConfigurationData heuristicConfData) {
+ this._heuristicConfData = heuristicConfData;
+ loadParameters();
+ }
+
+ @Override
+ public HeuristicConfigurationData getHeuristicConfData() {
+ return _heuristicConfData;
+ }
+
+ @Override
+ public HeuristicResult apply(MapReduceApplicationData data) {
+
+ if(!data.getSucceeded()) {
+ return null;
+ }
+
+ MapReduceCounterData currentJobData = data.getCounters();
+
+ Map totalCounters = currentJobData.getAllCountersInGroup(COUNTER_GROUP_NAME);
+
+ long dataLocalMaps = totalCounters.containsKey(DATA_LOCAL_MAPS) ? totalCounters.get(DATA_LOCAL_MAPS) : 0;
+ long rackLocalMaps = totalCounters.containsKey(RACK_LOCAL_MAPS) ? totalCounters.get(RACK_LOCAL_MAPS) : 0;
+ long otherLocalMaps = totalCounters.containsKey(OTHER_LOCAL_MAPS) ? totalCounters.get(OTHER_LOCAL_MAPS) : 0;
+ long totalLaunchedMaps = totalCounters.get(TOTAL_LAUNCHED_MAPS);
+
+ long nodeLocalityRatio = (dataLocalMaps + otherLocalMaps) / totalLaunchedMaps;
+ long rackLocalityRatio = rackLocalMaps/totalLaunchedMaps;
+
+
+ Severity severity = getTaskLocalitySeverity(nodeLocalityRatio);
+
+ severity = Severity.min(severity, getTaskLocalitySeverity(rackLocalityRatio));
+
+ HeuristicResult result = new HeuristicResult(_heuristicConfData.getClassName(),
+ _heuristicConfData.getHeuristicName(), severity, Utils.getHeuristicScore(severity, data.getMapperData().length));
+
+ result.addResultDetail("Data Local Map Tasks", Long.toString(dataLocalMaps));
+ result.addResultDetail("Other Local Map Tasks", Long.toString(otherLocalMaps));
+ result.addResultDetail("Rack Local Map Tasks", Long.toString(rackLocalMaps));
+ result.addResultDetail("Total Launched Map Tasks", Long.toString(totalLaunchedMaps));
+
+ return result;
+ }
+
+ private Severity getTaskLocalitySeverity(double ratio) {
+ return Severity.getSeverityDescending(
+ ratio, nodeLocalityRatioLimits[0], nodeLocalityRatioLimits[1], nodeLocalityRatioLimits[2], nodeLocalityRatioLimits[3]);
+ }
+
+
+
+
+}
diff --git a/app/com/linkedin/drelephant/tez/TezMetricsAggregator.java b/app/com/linkedin/drelephant/tez/TezMetricsAggregator.java
index c04edd7fd..deec8b33a 100644
--- a/app/com/linkedin/drelephant/tez/TezMetricsAggregator.java
+++ b/app/com/linkedin/drelephant/tez/TezMetricsAggregator.java
@@ -15,6 +15,8 @@
*/
package com.linkedin.drelephant.tez;
+
+import com.google.common.base.Strings;
import com.linkedin.drelephant.analysis.*;
import com.linkedin.drelephant.configurations.aggregator.AggregatorConfigurationData;
import com.linkedin.drelephant.tez.data.TezApplicationData;
@@ -29,7 +31,9 @@ public class TezMetricsAggregator implements HadoopMetricsAggregator {
private static final Logger logger = Logger.getLogger(TezMetricsAggregator.class);
- private static final String TEZ_CONTAINER_CONFIG = "hive.tez.container.size";
+
+ private static final String TEZ_CONTAINER_CONFIG = "tez.task.resource.memory.mb";
+ private static final String HIVE_TEZ_CONTAINER_CONFIG = "hive.tez.container.size";
private static final String MAP_CONTAINER_CONFIG = "mapreduce.map.memory.mb";
private static final String REDUCER_CONTAINER_CONFIG = "mapreduce.reduce.memory.mb";
private static final String REDUCER_SLOW_START_CONFIG = "mapreduce.job.reduce.slowstart.completedmaps";
@@ -84,26 +88,37 @@ public HadoopAggregatedData getResult() {
}
private long getMapContainerSize(HadoopApplicationData data) {
- try {
- long mapContainerSize = Long.parseLong(data.getConf().getProperty(TEZ_CONTAINER_CONFIG));
- if (mapContainerSize > 0)
- return mapContainerSize;
- else
- return Long.parseLong(data.getConf().getProperty(MAP_CONTAINER_CONFIG));
- } catch ( NumberFormatException ex) {
- return CONTAINER_MEMORY_DEFAULT_BYTES;
+ long mapperContainerSize;
+ if(!Strings.isNullOrEmpty(data.getConf().getProperty(TEZ_CONTAINER_CONFIG)) && Long.valueOf(data.getConf().getProperty(TEZ_CONTAINER_CONFIG)) > 0){
+ mapperContainerSize = Long.valueOf(data.getConf().getProperty(TEZ_CONTAINER_CONFIG));
+ }
+ else if(!Strings.isNullOrEmpty(data.getConf().getProperty(HIVE_TEZ_CONTAINER_CONFIG)) && Long.valueOf(data.getConf().getProperty(HIVE_TEZ_CONTAINER_CONFIG)) > 0){
+ mapperContainerSize = Long.valueOf(data.getConf().getProperty(HIVE_TEZ_CONTAINER_CONFIG));
+ }
+ else if(!Strings.isNullOrEmpty(data.getConf().getProperty(MAP_CONTAINER_CONFIG)) && Long.valueOf(data.getConf().getProperty(MAP_CONTAINER_CONFIG)) > 0){
+ mapperContainerSize = Long.valueOf(data.getConf().getProperty(MAP_CONTAINER_CONFIG));
+ }
+ else {
+ mapperContainerSize = CONTAINER_MEMORY_DEFAULT_BYTES;
}
+ return mapperContainerSize;
}
private long getReducerContainerSize(HadoopApplicationData data) {
- try {
- long reducerContainerSize = Long.parseLong(data.getConf().getProperty(TEZ_CONTAINER_CONFIG));
- if (reducerContainerSize > 0)
- return reducerContainerSize;
- else
- return Long.parseLong(data.getConf().getProperty(REDUCER_CONTAINER_CONFIG));
- } catch ( NumberFormatException ex) {
- return CONTAINER_MEMORY_DEFAULT_BYTES;
+ long reducerContainerSize;
+ if(!Strings.isNullOrEmpty(data.getConf().getProperty(TEZ_CONTAINER_CONFIG)) && Long.valueOf(data.getConf().getProperty(TEZ_CONTAINER_CONFIG)) > 0){
+ reducerContainerSize = Long.valueOf(data.getConf().getProperty(TEZ_CONTAINER_CONFIG));
}
+ else if(!Strings.isNullOrEmpty(data.getConf().getProperty(HIVE_TEZ_CONTAINER_CONFIG)) && Long.valueOf(data.getConf().getProperty(HIVE_TEZ_CONTAINER_CONFIG)) > 0){
+ reducerContainerSize = Long.valueOf(data.getConf().getProperty(HIVE_TEZ_CONTAINER_CONFIG));
+ }
+ else if(!Strings.isNullOrEmpty(data.getConf().getProperty(REDUCER_CONTAINER_CONFIG)) && Long.valueOf(data.getConf().getProperty(REDUCER_CONTAINER_CONFIG)) > 0){
+ reducerContainerSize = Long.valueOf(data.getConf().getProperty(REDUCER_CONTAINER_CONFIG));
+ }
+ else {
+ reducerContainerSize = CONTAINER_MEMORY_DEFAULT_BYTES;
+ }
+ return reducerContainerSize;
+
}
}
diff --git a/app/com/linkedin/drelephant/tez/heuristics/GenericMemoryHeuristic.java b/app/com/linkedin/drelephant/tez/heuristics/GenericMemoryHeuristic.java
index 7447d62c5..f4c3658fc 100644
--- a/app/com/linkedin/drelephant/tez/heuristics/GenericMemoryHeuristic.java
+++ b/app/com/linkedin/drelephant/tez/heuristics/GenericMemoryHeuristic.java
@@ -82,6 +82,7 @@ private void loadParameters() {
}
+
public GenericMemoryHeuristic(String mapredContainerMemConf, HeuristicConfigurationData heuristicConfData) {
this._mapredContainerMemConf = mapredContainerMemConf;
this._heuristicConfData = heuristicConfData;
@@ -135,7 +136,6 @@ public HeuristicResult apply(TezApplicationData data) {
String containerSizeStr;
-
if(!Strings.isNullOrEmpty(data.getConf().getProperty(TEZ_MAPPER_MEMORY_CONF)) && Long.valueOf(data.getConf().getProperty(TEZ_MAPPER_MEMORY_CONF)) > 0){
containerSizeStr = data.getConf().getProperty(TEZ_MAPPER_MEMORY_CONF);
}
@@ -144,6 +144,7 @@ else if(!Strings.isNullOrEmpty(data.getConf().getProperty(HIVE_MAPPER_MEMORY_CON
}
else if(!Strings.isNullOrEmpty(data.getConf().getProperty(_mapredContainerMemConf)) && Long.valueOf(data.getConf().getProperty(_mapredContainerMemConf)) > 0) {
containerSizeStr = data.getConf().getProperty(_mapredContainerMemConf);
+
}
else {
containerSizeStr = getContainerMemDefaultMBytes();
diff --git a/app/com/linkedin/drelephant/tez/heuristics/MapperMemoryHeuristic.java b/app/com/linkedin/drelephant/tez/heuristics/MapperMemoryHeuristic.java
index 3a52fa92d..f487b8234 100644
--- a/app/com/linkedin/drelephant/tez/heuristics/MapperMemoryHeuristic.java
+++ b/app/com/linkedin/drelephant/tez/heuristics/MapperMemoryHeuristic.java
@@ -33,8 +33,10 @@ public class MapperMemoryHeuristic extends GenericMemoryHeuristic {
private static final Logger logger = Logger.getLogger(MapperMemoryHeuristic.class);
public static final String MAPRED_MAPPER_MEMORY_CONF = "mapreduce.map.memory.mb";
+
public MapperMemoryHeuristic(HeuristicConfigurationData __heuristicConfData) {
super(MAPRED_MAPPER_MEMORY_CONF, __heuristicConfData);
+
}
@Override
diff --git a/app/com/linkedin/drelephant/tez/heuristics/ReducerMemoryHeuristic.java b/app/com/linkedin/drelephant/tez/heuristics/ReducerMemoryHeuristic.java
index be8820e86..27a03abba 100644
--- a/app/com/linkedin/drelephant/tez/heuristics/ReducerMemoryHeuristic.java
+++ b/app/com/linkedin/drelephant/tez/heuristics/ReducerMemoryHeuristic.java
@@ -34,6 +34,7 @@ public class ReducerMemoryHeuristic extends GenericMemoryHeuristic {
public ReducerMemoryHeuristic(HeuristicConfigurationData __heuristicConfData) {
super(MAPRED_REDUCER_MEMORY_CONF, __heuristicConfData);
+
}
@Override
diff --git a/app/com/linkedin/drelephant/util/InfoExtractor.java b/app/com/linkedin/drelephant/util/InfoExtractor.java
index 6ff0f4d1b..045350cd9 100644
--- a/app/com/linkedin/drelephant/util/InfoExtractor.java
+++ b/app/com/linkedin/drelephant/util/InfoExtractor.java
@@ -22,7 +22,6 @@
import com.linkedin.drelephant.configurations.scheduler.SchedulerConfigurationData;
import com.linkedin.drelephant.tez.data.TezApplicationData;
-import com.linkedin.drelephant.clients.WorkflowClient;
import com.linkedin.drelephant.mapreduce.data.MapReduceApplicationData;
import com.linkedin.drelephant.schedulers.Scheduler;
diff --git a/app/views/help/mapreduce/helpMapperTaskLocality.scala.html b/app/views/help/mapreduce/helpMapperTaskLocality.scala.html
new file mode 100644
index 000000000..d5c5e7e5a
--- /dev/null
+++ b/app/views/help/mapreduce/helpMapperTaskLocality.scala.html
@@ -0,0 +1,71 @@
+@*
+* Copyright 2016 LinkedIn Corp.
+*
+* Licensed under the Apache License, Version 2.0 (the "License"); you may not
+* use this file except in compliance with the License. You may obtain a copy of
+* the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+* License for the specific language governing permissions and limitations under
+* the License.
+*@
+
+
+ This analysis shows the data locality for your apps.
+ We check the ratio between your job's node local map tasks AND the total number of map tasks.
+ Also check the ratio between your job's rack local map tasks AND the total number of tasks
+ The setting in question here is container memory is "yarn.scheduler.capacity.node-locality-delay". This is the Number of missed scheduling opportunities after which the capacity-scheduler attempts to schedule
+ rack local containers.
+ For Cloud based storage systems: This number should be low (0 or -1) as there is no notion of data locality and there is no point even checking for it
+ For on-prem storage/hdfs with cloud or on-prem compute, this number should be equal to the number of nodes in the cluster to guarantee a scheduling attempt to each data local node.
+ If this heuristic is above MODERATE, it means you are making good use of hadoop's most important feature of data locality.
+
+
+Example
+
+
+
+ Mapper Task Locality
+
+ | Severity: Critical |
+
+
+ | Data Local Map Tasks |
+ 1 |
+
+
+ | Other Local Map Tasks |
+ 1 |
+
+
+ | Rack local Map Tasks |
+ 56 |
+
+
+ | Total Launched Map Tasks |
+ 127 |
+
+
+
+
+
+
+Suggestions
+
+
+
+ The problem indicates your tasks are not running local to the data. This will cause large network data flow and could lead to bottlenecks for very large jobs.
+
+ You should try to increase yarn.scheduler.capacity.node-locality-delay to atleast the number of nodes on the cluster
+
+ See yarn.scheduler.fair.locality.threshold.node and yarn.scheduler.fair.locality.threshold.rack for fair scheduler
+ This will make sure that there is at least one scheduling attempt to each data local node
+
+
+ See Capacity Scheduler Node Locality Settings for further information.
+
+ See Fair Scheduler Node Locality Settings for further information.
\ No newline at end of file