Hadoop Job Scheduler作业调度器

http://hi.baidu.com/zhengxiang33/blog/item/655c8e039a0b619bd53f7c67.html

作者:hovlj_1130 | 可以任意转载, 但转载时务必以超链接形式标明文章原始出处 和 作者信息 及 版权声明

http://hi.baidu.com/hovlj_1130/blog/item/fb84dd1e3558d8f8e0fe0b8e.html

HadoopJobScheduler

Hadoop的作业调度器,可以以插件的方式加载,常见的作业调度器有三种:

默认调度算法FIFO

计算能力调度算法CapacityScheduler(Yahoo!开发)

公平份额调度算法FairScheduler(Facebook开发)

默认调度算法FIFO

简介:

最早的HadoopMap/Reduce计算架构中,JobTracker在进行作业调度时使用的是FIFO(FirstInFirstOut)算法。所有用户的作业都被提交到一个队列中,然后由JobTracker先按照作业的优先级高低,再按照作业提交时间的先后顺序选择将被执行的作业。

优点:

调度算法简单明了,JobTracker工作负担轻。

缺点:

忽略了不同作业的需求差异。例如如果类似对海量数据进行统计分析的作业长期占据计算资源,那么在其后提交的交互型作业有可能迟迟得不到处理,从而影响到用户的体验。

新的调度算法:

当前,新的调度器已经作为插件的形式集成在Hadoop当中。

计算能力调度算法CapacityScheduler

基础知识:

CapacityScheduler的每个队列中采用的调度策略是FIFO算法。

CapacityScheduler默认情况下不支持优先级,但是可以在配置文件中开启此选项,如果支持优先级,调度算法就是带有优先级的FIFO。

CapacityScheduler不支持优先级抢占,一旦一个作业开始执行,在执行完之前它的资源不会被高优先级作业所抢占。

CapacityScheduler对队列中同一用户提交的作业能够获得的资源百分比进行了限制以使同属于一用户的作业不能出现独占资源的情况。

配置:

#将capacityscheduler的jar包copy到lib目录下

cp$HADOOP_HOME/contrib/capacity-scheduler/hadoop-*-capacity-scheduler.jar$HADOOP_HOME/lib/

#配置mapred-site.xml

#添加mapred.jobtracker.taskScheduler设置为org.apache.hadoop.mapred.CapacityTaskScheduler

#这里分了两个组,在mapred.queue.names里面定义,同时组的具体配额在capacity-scheduler.xml里面定义

vimapred-site.xml

<property>

<name>mapred.jobtracker.taskScheduler</name>

<value>org.apache.hadoop.mapred.CapacityTaskScheduler</value>

</property>

<property>

<name>mapred.queue.names</name>

<value>default,putindb</value>

</property>

#设置具体的queue的配额信息,前面两组分别配置default和putindb组,后面是整理的配置

vicapacity-scheduler.xml

<?xmlversion="1.0"?>

<configuration>

<property>

<name>mapred.capacity-scheduler.queue.default.capacity</name>

<value>5</value>

</property>

<property>

<name>mapred.capacity-scheduler.queue.default.supports-priority</name>

<value>true</value>

</property>

<property>

<name>mapred.capacity-scheduler.queue.default.minimum-user-limit-percent</name>

<value>100</value>

</property>

<property>

<name>mapred.capacity-scheduler.queue.default.maximum-initialized-jobs-per-user</name>

<value>2</value>

</property>

<property>

<name>mapred.capacity-scheduler.queue.putindb.capacity</name>

<value>95</value>

</property>

<property>

<name>mapred.capacity-scheduler.queue.putindb.supports-priority</name>

<value>true</value>

</property>

<property>

<name>mapred.capacity-scheduler.queue.putindb.minimum-user-limit-percent</name>

<value>100</value>

</property>

<property>

<name>mapred.capacity-scheduler.queue.putindb.maximum-initialized-jobs-per-user</name>

<value>2</value>

</property>

<property>

<name>mapred.capacity-scheduler.default-supports-priority</name>

<value>true</value>

</property>

<property>

<name>mapred.capacity-scheduler.default-minimum-user-limit-percent</name>

<value>100</value>

</property>

<property>

<name>mapred.capacity-scheduler.default-maximum-initialized-jobs-per-user</name>

<value>2</value>

</property>

<property>

<name>mapred.capacity-scheduler.init-poll-interval</name>

<value>5000</value>

</property>

<property>

<name>mapred.capacity-scheduler.init-worker-threads</name>

<value>5</value>

</property>

</configuration>

配置完成后,重启jobtracker即可。

stop-mapred.sh

start-mapred.sh

注意在提交Job时,记得设置job.set(),指定组或者Pool;

如何选择合适的作业去执行

为队列定义了一个指标—队列中正在运行的任务数与其应该分得的计算资源(配置文件中为此队列分配了相应数量的资源,而实际中该队列可能没有分配到)之间的比值。当系统中出现空闲的tasktracker,算法会首先选择一个该比值最低的队列。

队列被选中后,将按照作业优先级(如果支持的话)和提交时间顺序选择执行的作业。

在选择作业的时候,还需要考虑作业所属的用户是否已经超出了他所能使用的资源限制。

此外,还会考虑tasktracker内存资源是否满足作业的要求。

内存资源的有效管理

CapacityScheduler能有效地对hadoop集群的内存资源进行管理,以支持内存密集型应用。

作业对内存资源需求高时,调度算法将把该作业的相关任务分配到内存资源充足的tasktracker上。

在作业选择过程中,CapacityScheduler会检查空闲tasktracker上的内存资源是否满足作业要求。tasktracker上的空闲资源(内存)数量值可以通过tasktracker的内存资源总量减去当前已经使用的内存数量得到,而后者包含在tasktracker向jobtracker发送的周期性心跳信息中。

目前,基于内存的调度只能在linux平台下起作用,关于内存调度的相关参数可以通过配置文件来设置。

公平份额调度算法FairScheduler

设计思想

尽可能保证所有的作业都能够获得等量的资源份额。系统中只有一个作业执行时,它将独占集群所有资源。有其他作业被提交时就会有TaskTracker被释放并分配给新提交的作业,以保证所有的作业都能够获得大体相同的计算资源。

作业池

用户提交的作业将会放进一个能够公平共享资源的pool(池)中。

每个作业池设定了一个最低资源保障(aguaranteedminimumshare),当一个池中包含job时,它至少可以获得minimumshare的资源——最低保障资源份额机制。

池中的作业获得一定份额的资源。

可以通过配置文件限制每个池中的作业数量。

缺省情况下,每个作业池中选择将要执行的作业的策略是FIFO策略,先按照优先级高低排序,然后再按照提交时间排序。

作业和作业池的权值weight

缺省情况下,FairScheduler会为每一个用户建立一个单独的pool。所有用户能够获得等量的资源份额而无论他提交了多少作业,而每个pool中,各个作业将平分分配给所在池的资源。

实际应用中,无论是作业池还是作业,都被赋予一定的权值,并以此为依据获得相应比例的资源。这种情况下,作业池和作业在资源分配时不是严格的平均分配,但这有利于根据作业的重要程度及实际需求合理分配资源。

如何选择合适的作业执行

默认是FIFO策略,此外还有一种基于赤字的策略。

FairScheduler为每个作业定义了一个deficit(赤字)指标。

Deficit是一个作业在理想情况下的获得的计算资源和实际中获得的计算资源之间的差距。

FairScheduler会每隔几百毫秒观察每个作业中有多少任务已经在这个时间间隔内执行,并将结果与它应得的资源份额比较,以更新该作业的deficit值。一旦有空闲的tasktracker出现,首先分配给当前具有最高deficit值的作业。

例外——如果系统中存在着尚未获得最低资源保障的作业池,那么该池中的作业将会优先调度,而选择池中的作业需要根据它们的deficit来决定。这样做是为了尽可能满足作业池最低保障资源份额的机制。

如何确定每个作业的资源份额

缺省情况是平分资源,此外提供一种基于权值的资源分配方法。

作业资源份额的计算是根据作业的权值将集群的资源总量划分给各个可以运行的作业。

默认情况下,权值基于作业优先级,每个优先级对应的权值是低一个优先级的2倍(优先级共有VERY_HIGH,HIGH,NORMAL,LOW,VERY_LOW五个等级,则VERY_HIGH具有4倍NORMAL的权值)。

作业和作业池的权值可以在池配置文件中进行设定,例如可以基于作业的大小和提交时间来设定。

作业池的最低资源保障也是按照权值比例分配给其中的作业。

配置:

#将fairscheduler的jar包copy到lib目录下

cp$HADOOP_HOME/contrib/fairscheduler/hadoop-*-fairscheduler.jar$HADOOP_HOME/lib/

#配置mapred-site.xml

vimapred-site.xml

<property>

<name>mapred.jobtracker.taskScheduler</name>

<value>org.apache.hadoop.mapred.FairScheduler</value>

</property>

<property>

<name>mapred.fairscheduler.allocation.file</name>

<value>$HADOOP_CONF/pools.xml</value>

</property>

<property>

<name>mapred.fairscheduler.preemption</name>

<value>true</value>

</property>

<property>

<name>mapred.fairscheduler.assignmultiple</name>

<value>true</value>

</property>

<property>

<name>mapred.fairscheduler.poolnameproperty</name>

<value>mapred.queue.name</value>

<description>job.set("mapred.queue.name",pool);//poolissettoeither'high'or'low'</description>

</property>

<property>

<name>mapred.fairscheduler.preemption.only.log</name>

<value>true</value>

</property>

<property>

<name>mapred.fairscheduler.preemption.interval</name>

<value>15000</value>

</property>

<property>

<name>mapred.queue.names</name>

<value>default,putindb</value>

</property>

vipools.xml

<?xmlversion="1.0"?>

<allocations>

<poolname="putindb">

<minMaps>90</minMaps>

<minReduces>20</minReduces>

<maxRunningJobs>20</maxRunningJobs>

<weight>2.0</weight>

<minSharePreemptionTimeout>30</minSharePreemptionTimeout>

</pool>

<poolname="default">

<minMaps>9</minMaps>

<minReduces>2</minReduces>

<maxRunningJobs>20</maxRunningJobs>

<weight>1.0</weight>

<minSharePreemptionTimeout>30</minSharePreemptionTimeout>

</pool>

</allocations>

不管是CapacityScheduler还是FairScheduler,我都没有配置任务抢占成功。具体表现在:

当一个优先级更高的任务提交时,jobtracker会将新回收的map/reduce单元用于新的这个优先级更高的任务,但是对于一直running而没有完成的计算资源,jobtracker无法将这些资源回收。也就是说,当一个hadoop集群里面的reduce资源有限时(在我们的应用中,map单元都很快就跑完了,但是存在一些长时间的reduce),而一些长时间运行的低优先级的任务占用完了所有的reduce单元后,新提交的优先级更高的Job的reduce全被pending,而无法抢占资源运行,导致无法完成。

在网上查到FairScheduler将在hadoop0.21里实现任务抢占preemption,网上有一些补丁,但是打上patch4665:Addpreemptiontothefairscheduler后依旧无法抢占。

看来只有自己修改源码了,这个问题不解决,问题很大啊。

http://hadoop.apache.org/common/docs/r0.19.2/capacity_scheduler.html