特点
以队列为单位划分资源,每个队列可设定一定比例的资源最低保证和使用上限,同时,每个用户也可设定一定的资源使用上限以防止资源滥用。而当一个队列的资源有剩余时,可暂时将剩余资源共享给其他队列。总之,Capacity Scheduler主要有以下几个特点:
- 容量保证:管理员可为每个队列设置资源最低保证和资源使用上限,而所有提交到该队列的应用程序共享这些资源
- 灵活性:如果一个队列中的资源有剩余,可以暂时共享给那些需要资源的队列,而一旦该队列有新的应用程序提交,则其他队列释放的资源会归还给该队列
- 多重租赁:支持多用户共享集群和多应用程序同时运行。为防止单个应用程序、用户或队列独占集群中的资源,管理员可为之增加多重约束(比如单个应用程序同时运行的任务数等)
- 安全保证:每个队列有严格的ACL列表规定它的访问用户,每个用户可指定哪些用户允许查看自己应用程序的运行状态或者控制应用程序(比如杀死应用程序)。此外,管理员可指定队列管理员和集群系统管理员
- 动态更新配置文件:管理员可根据需要动态修改各种配置参数,以实现在线集群管理
Capacity Scheduler的功能
- Capacity Scheduler有自己的配置文件,即存放在conf目录下的capacity-scheduler.xml
- 在Capacity Scheduler的配置文件中,队列queueX的参数Y的配置名称为yarn.scheduler.capacity.queueX.Y
- 资源分配相关参数:
- capacity:队列的最小资源容量(百分比)。注意,所有队列的容量之和应小于100
- maximum-capacity:队列的资源使用上限
- minimum-user-limit-percent:每个用户最低资源保障(百分比)
- user-limit-factor:每个用户最多可使用的资源量(百分比)
- 限制应用程序数目的相关参数:
- maximum-applications:集群或者队列中处于等待和运行状态的应用程序数目上限,这是一个强限制项,一旦集群中应用程序数目超过该上限,后续提交的应用程序将被拒绝。默认值为10000。Hadoop允许从集群和队列两个方面该值,其中,集群的总体数目上限可通过参数
yarn.scheduler.capacity.maximum-applications
设置,默认为10000,而单个队列可通过参数yarn.scheduler.capacity.<queue-path>.maximum-applications
设置适合自己的值 - maximum-am-resource-percent:集群中用于运行应用程序ApplicationMaster的资源比例上限,该参数通常用于限制处于活动状态的应用程序数目。所有队列的ApplicationMaster资源比例上限可通过参数
yarn.scheduler.capacity.maximum-am-resource-percent
设置,而单个队列可通过参数yarn.scheduler.capacity.<queue-path>.maximum-am-resource-percent
设置适合自己的值
- maximum-applications:集群或者队列中处于等待和运行状态的应用程序数目上限,这是一个强限制项,一旦集群中应用程序数目超过该上限,后续提交的应用程序将被拒绝。默认值为10000。Hadoop允许从集群和队列两个方面该值,其中,集群的总体数目上限可通过参数
- 队列访问权限控制
- state:队列状态,可以为
STOPPED
或者RUNNING
。如果一个队列处于STOPPED状态,用户不可以将应用程序提交到该队列或者它的子队列中。类似的,如果root队列处于STOPPED状态,则用户不可以向集群提交应用程序,但正在运行的应用程序可以正常运行结束,以便队列可以优雅地退出 - acl_submit_application:限定哪些用户/用户组可向给定队列中提交应用程序。该属性具有继承性,即如果一个用户可以向某个队列提交应用程序,则它可以向它所有子队列中提交应用程序
- acl_administer_queue:为队列指定一个管理员,该管理员可控制该队列的所有应用程序,比如杀死任意一个应用程序等。同样,该属性具有继承性,如果一个用户可以向某个队列中提交应用程序,则它可以向它的所有子队列中提交应用程序
- state:队列状态,可以为
- 当管理员需动态修改队列资源配置时,可修改配置文件conf/capacity-scheduler.xml,然后运行“
yarn rmadmin -refreshQueues
” - 当前Capacity Scheduler不允许管理员动态减少队列数目,且更新的配置参数值应是合法值,否则会导致配置文件加载失败
Capacity Scheduler实现
应用程序初始化
- 应用程序被提交到ResourceManager之后,ResourceManager会向Capacity Scheduler发送一个SchedulerEventType.APP_ADDED事件,Capacity Scheduler收到该事件后,将为应用程序创建一个FiCaSchedulerApp对象跟踪和维护该应用程序的运行时信息,同时将应用程序提交到对应的叶子队列中,叶子队列会对应用程序进行一系列合法性检查。只有通过这些合法性检查,应用程序才算提交成功,这些合法性包括以下几个方面:
- 应用程序所属用户拥有该叶子队列的应用程序提交权限
- 队列及其父队列当前处于RUNNING状态(递归检查)
- 队列当前已提交的应用程序数目未达到管理员设定的上限
- 应用程序所属用户提交的应用程序数目未超过管理员设定的上限
资源调度
当ResourceManager收到来自NodeManager发送的心跳信息后,将向Capacity Scheduler发送一个SchedulerEventType.NODE_UPDATE事件,Capacity Scheduler收到该事件后,会依次进行以下操作:
- 处理心跳信息:NodeManager发送的心跳信息中有两类信息需资源调度器处理,一类是最新启动的Container,另一类是运行完成的Container,具体如下:
- 对于最新启动的Container,资源调度器需向ResourceManager发送一个RMContainerEventType.LAUNCHED,进而将该Container从超时监控队列中删除。当资源调度器为ApplicationMaster分配一个Container后,为了防止ApplicationMaster长时间不使用该Container造成资源浪费,它会将该Container加入一个超时监控队列中。如果一段时间内,该队列中的Container仍未被使用,则资源调度器会回收该Container
- 对于运行完成的Container,资源管理器将回收它使用的资源,以便接下来对这些资源进行再分配
处理完以上两类信息后,Capacity Scheduler将节点上的空闲资源分配给应用程序
- 资源分配
- Container主要包含5类信息:
- 优先级
- 期望资源所在节点
- 资源量
- Container数目
- 是否松弛本地性(即是否在没有满足节点本地性资源时,选择机架本地性资源)
- 资源调度器收到资源申请后,将暂时将这些数据请求存放到一个数据结构中,以等待空闲资源出现后为其分配合适的资源
- 当一个节点上有空闲资源时,它会依次选择队列、应用程序和container(请求)使用该资源
- 步骤1:选择队列
- 从根队列开始,按照它的子队列资源使用率由小到大依次遍历各个子队列。如果子队列为叶子队列,则依次按照步骤2和步骤3中的方法在队列中选出一个Container(请求),否则以该子队列为根队列,重复以上过程,直到找到一个合适的队列并退出
- 注意:上述“队列资源使用率”计算方法为用已经使用的资源量除以最小队列资源容量(由管理员配置)。对于非叶子队列,它的已使用资源量是各个子队列已使用资源量之和
- 步骤2:选择应用程序
- 在步骤1中选中一个叶子队列后,Capacity Scheduler按照提交时间对子队列中的应用程序进行排序(实际排序时用的是Applition ID,提交时间越早的应用程序,Application ID越小),选择最早提交的 Application 分配资源
- 步骤3:选择Container(请求)
- 对于同一个应用程序,它请求的Container可能是多样化的,涉及不同的优先级、节点、资源量和数量。当选中一个应用程序后,Capacity Scheduler将尝试优先满足优先级高的Container。对于同一类优先级,优先选择满足本地性的Container,它会依次选择node local、rack local和no local的Container
- 步骤1:选择队列
- Capacity Scheduler有两种比较器用以比较两个资源的大小(比如比较用户当前使用的资源量是否超过了设置的上限资源量),默认是DefaultResourceCalculator,它只考虑内存资源。另外一种是DominantResourceCalculator,它采用了DRF比较算法,同时考虑内存和CPU两种资源。管理员可通过参数
yarn.scheduler.capacity.resource-calculator
设置资源比较器 - 其他事件处理
- APP_REMOVED:在多种情况下Capacity Scheduler将收到该事件,包括应用程序正常结束、应用程序被杀死等。Capacity Scheduler收到该事件后,首先会向所有未运行完成的Container发送一个RMContainerEventType.KILL事件,以释放正在使用的Container;然后才会将应用程序相关数据结构从内存中移除
- NODE_ADDED:当集群中动态加入一个节点时(比如管理员动态扩充集群规模或者节点断开后又复活等),Capacity Scheduler将收到该事件。Capacity Scheduler收到该事件后,只需在相应数据结构中记录NodeManager信息并增加系统总资源量即可
- NODE_REMOVED:当集群中动态移除一个节点时(比如管理员动态移除节点或者节点在一定事件内未汇报心跳而被ResourceManager移除集群),Capacity Scheduler将收到该事件。Capacity Scheduler收到该事件后,除了移除NodeManager信息并减少系统总资源外,还需向所有正运行的Container发送一个RMContainerEventType.KILL事件,以清空相关信息
- CONTAINER_EXPIRED:当Capacity Scheduler将一个Container分配给ApplicationMaster后,ApplicationMaster在一定时间内必须使用该Container,否则ResourceManager将进行强制回收,此时会触发一个CONTAINER_EXPIRED事件
- Container主要包含5类信息:
参考:《Hadoop 技术内幕:深入解析 YARN 架构设计与实现原理》