转自:http://dongxicheng.org/mapreduce/hadoop-job-memory-control/
对于Hadoop而言,对作业使用资源量进行限制是非常重要的,这可以防止一些有问题的作业因耗掉集群中大量资源而干扰其他正常作业。本文主要分析了Hadoop-0.20.2中作业内存控制相关策略,包括怎样启用Hadoop作业内存使用量控制功能,Hadoop怎样实现作业内存控制等。
1. 内存相关配置项
(1) 配置内存计算插件
<property>
<name> mapred.tasktracker.memory_calculator_plugin</name>
<value>org.apache.hadoop.util.LinuxMemoryCalculatorPlugin</value>
</property>
(2) 配置限制内存的一些参数
mapred.cluster.map.memory.mb 每个map slot预留的内存
mapred.cluster.reduce.memory.mb 每个reduce slot预留的内存
以上两个选项用于计算taskTracker上可用内存
mapred.cluster.max.map.memory.mb 每个map task使用的内存上限
mapred.cluster.max.reduce.memory.mb 每个reduce task使用的内存上限
(3) 用户可指定的作业内存参数
mapred.job.map.memory.mb 一个map任务预留的内存上限, 一个map任务可以申请多个map slot为其工作, 如果内存不足的话 mapred.job.reduce.memory.mb 一个reduce任务预留的内存上限, 一个reduce任务可以申请多个reduce slot为其工作, 如果内存不足的话
这两个参数可以动态配置,即:为不同用户指定不同内存参数。
(4) 过期的配置选项
下面几个选项已经过期,不推荐使用:
mapred.task.maxvmem
mapred.task.limit.maxvmem, 用mapred.cluster.max.map.memory.mb和mapred.cluster.max.reduce.memory.mb代替
mapred.task.default.maxvmem
2. TaskTracker作业内存使用控制
2.1 TaskTracker控制task内存使用方法
TaskTracker从单个task内存使用量和所有task整体内存使用量上进行内存控制。
(1) 单个task控制
满足两个两个条件之一时,则任务该task超过了内存相知,直接杀死:
[1] 某个时刻满足:currentMemUsage > (2*mapred.cluster.max.map.memory.mb),这个条件主要是考虑到调用fork()瞬间,内存会变为父进程的两倍。
或者
[2] 相邻时间间隔内(默认是5s)两次检测到内存使用量超过mapred.cluster.max.map.memory.mb
(2) 总体控制
除了从单个task上控制内存使用,还是总体上控制。TaskTracker会周期性计算当前正在运行的task所占用的总内存数,如果超过可用内存总数,则选择适当task杀掉,直到内存使用量降到安全线以下。
[1] 定义两个变量
maxMemoryAllowedForAllTasks:为该TaskTracker所有可用内存
maxMemoryAllowedForAllTasks = maxCurrentMapTasks * mapSlotMemorySizeOnTT + maxCurrentReduceTasks * reduceSlotSizeMemoryOnTT;
memoryStillInUsage:该TaskTracker上正在运行的task占有的内存总量
[2] 变量解释
maxCurrentMapTasks为该TaskTracker上配置的map slot个数(由mapred.tasktracker.map.tasks.maximum指定),maxCurrentReduceTasks类似。
mapSlotMemorySizeOnTT即为mapred.cluster.map.memory.mb,reduceSlotSizeMemoryOnTT类似
[3] 判断标准
如果memoryStillInUsage > maxMemoryAllowedForAllTasks,则选择task杀掉,选择策略是:总是选择最近启动的task,将其杀掉,直到memoryStillInUsage <= maxMemoryAllowedForAllTasks
2.2 TaskTracker上相关类
(1) TaskMemoryManagerThread:后台线程,管理某个TaskTracker上所有task内存使用情况,如果有task超出内存使用,则将其杀掉。位于TaskMemoryManagerThread.java中
(2) ProcfsBasedProcessTree:从linux虚拟文件系统/proc/中获取ProcessTree,主要是进程之间的树关系。 位于ProcfsBasedProcessTree.java中,且该类仅适用于linux操作系统。
(3) LinuxMemoryCalculatorPlugin:计算TaskTracker上资源使用情况,包括进程所用内存,cpu资源量,cpu数目等。位于LinuxMemoryCalculatorPlugin.java中,且该类仅适用于linux操作系统。
(4) TaskTracker:启动TaskMemoryManagerThread线程,并把LinuxMemoryCalculatorPlugin计算得到的资源情况通过HeartBeat发送给JobTracker。
3. JobTracker作业内存使用控制
3.1 JobTracker控制task内存使用方法
JobTracker:如果: mapred.job.map.memory.mb > mapred.cluster.max.map.memory.mb,则直接跑出异常,告诉client提交作业的内存不合法
3.2 JobTracker上相关类方法
initializeTaskMemoryRelatedConfig:初始化内存相关的配置变量
checkMemoryRequirements:判断某个作业内存使用量是否超出限制
4. Capacity Scheduler
Capacity Scheduler较其他Hadoop Scheduler,如FIFO或者Fair Scheduler,最大的好处之一是可以根据作业的内存需求量进行调度。核心思想是:用户提交作业时,指定作业的每个task预期使用内存量,然后根据该内存量计算出对应的slot数,这当该作业的某个task在某个TaskTracker执行时,一次性占用多个slot。
该调度器解决了Hadoop本身设计的一个缺陷,即:作业调度完全按照slot数来,如果有20个slot,则会同时有20个task执行。一般而言,slot对应CPU数,也就是说,调度器完全按照cpu资源调度,并没有考虑到内存,网络IO等资源。
5. 相关的Hadoop patch
Hadoop与task内存等资源控制相关的patch有三个:
(1) MAPREDUCE-1218:TaskTracker通过Heartbeat向jobtracker汇报自己可用的内存和cpu使用率。
(2) MAPREDUCE-220:TaskTracker收集自身每个task的内存和cpu使用量,并通过hearteat汇报给JobTracker
(3) MAPREDUCE-2037:TaskTracker收集自身的内存和cpu负载,并通过HeatBeat告诉JobTracker
另外,其他资源的收集,如网络IO和磁盘IO的收集的必要性和可行性,见:https://issues.apache.org/jira/browse/MAPREDUCE-220。