在文章开头,我想先做几点说明:
1、本文的内容来自我对Yarn的相应功能的理解和实践。而我对该部分功能的理解主要来自对Hadoop的开发者之前相应言论的分析,并且我也将我的分析发给了Hadoop community, 并得到了Yarn的创始人兼架构师Arun Murthy的肯定回复。
2、本文中uber的配置部分,主要参考之前Hadoop开发者的言论。但是我当初看该言论的时候对一些细节有所疑惑,因此在本文中我对很多地方做了修改:使一些用词的引用前后一致,并加上了很多描述性的过渡语言。
3、本文为研究性质,并非官方文档的翻译。因此,如果读者发现任何纰漏,希望不吝赐教,万分感激!
首先,简单回顾一下Hadoop 1.x中的JVM重用功能:用户可以通过更改配置,来指定TaskTracker在同一个JVM里面最多可以累积执行的Task的数量(默认是1)。这样的好处是减少JVM启动、退出的次数,从而达到提高任务执行效率的目的。 配置的方法也很简单:通过设置mapred-site.xml里面参数mapred.job.reuse.jvm.num.tasks的值。该值默认是1,意味着TaskTracker会为每一个Map任务或Reduce任务都启动一个JVM,当任务执行完后再退出该JVM。依次类推,如果该值设置为3,TaskTracker则会在同一个JVM里面最多依次执行3个Task,然后才会退出该JVM。
在 Yarn(Hadoop MapReduce v2)里面,不再有参数mapred.job.reuse.jvm.num.tasks,但它也有类似JVM Reuse的功能——uber。据Arun的说法,启用该功能能够让一些任务的执行效率提高2到3倍(“we’ve observed 2x-3x speedup for some jobs”)。不过,由于Yarn的结构已经大不同于MapReduce v1中JobTracker/TaskTracker的结构,因此uber的原理和配置都和之前的JVM重用机制大不相同。
1) uber的原理:
Yarn的默认配置会禁用uber组件,即不允许JVM重用。我们先看看在这种情况下,Yarn是如何执行一个MapReduce job的。首先,Resource Manager里的Application Manager会为每一个application(比如一个用户提交的MapReduce Job)在NodeManager里面申请一个container,然后在该container里面启动一个Application Master。container在Yarn中是分配资源的容器(内存、cpu、硬盘等),它启动时便会相应启动一个JVM。此时,Application Master便陆续为application包含的每一个task(一个Map task或Reduce task)向Resource Manager申请一个container。等每得到一个container后,便要求该container所属的NodeManager将此container启动,然后就在这个container里面执行相应的task。等这个task执行完后,这个container便会被NodeManager收回,而container所拥有的JVM也相应地被退出。在这种情况下,可以看出每一个JVM仅会执行一Task, JVM并未被重用。
用户可以通过启用uber组件来允许JVM重用——即在同一个container里面依次执行多个task。在yarn-site.xml文件中,改变一下几个参数的配置即可启用uber的方法:
参数| 默认值 | 描述
- mapreduce.job.ubertask.enable | (false) | 是否启用user功能。如果启用了该功能,则会将一个“小的application”的所有子task在同一个JVM里面执行,达到JVM重用的目的。这个JVM便是负责该application的ApplicationMaster所用的JVM(运行在其container里)。那具体什么样的application算是“小的application”呢?下面几个参数便是用来定义何谓一个“小的application”
- mapreduce.job.ubertask.maxmaps | 9 | map任务数的阀值,如果一个application包含的map数小于该值的定义,那么该application就会被认为是一个小的application
- mapreduce.job.ubertask.maxreduces | 1 | reduce任务数的阀值,如果一个application包含的reduce数小于该值的定义,那么该application就会被认为是一个小的application。不过目前Yarn不支持该值大于1的情况“CURRENTLY THE CODE CANNOT SUPPORT MORE THAN ONE REDUCE”
- mapreduce.job.ubertask.maxbytes | | application的输入大小的阀值。默认为dfs.block.size的值。当实际的输入大小部超过该值的设定,便会认为该application为一个小的application。
最后,我们来看当uber功能被启用的时候,Yarn是如何执行一个application的。首先,Resource Manager里的Application Manager会为每一个application在NodeManager里面申请一个container,然后在该container里面启动一个Application Master。containe启动时便会相应启动一个JVM。此时,如果uber功能被启用,并且该application被认为是一个“小的application”,那么Application Master便会将该application包含的每一个task依次在这个container里的JVM里顺序执行,直到所有task被执行完(“WIth ‘uber’ mode enabled, you’ll run everything within the container of the AM itself”)。这样Application Master便不用再为每一个task向Resource Manager去申请一个单独的container,最终达到了 JVM重用(资源重用)的目的。