Spark提交任务流程
总体概况:
1.在提交脚本中配置需要的资源(粗颗粒分配),向ResourceManager提交app
2.RM启动一个NM来启动ApplicationMaster,driver运行在此机器上,并创建了DAGScheduler,TaskScheduler.
3.AM向RM请求资源的,AM然后在对应的NM启动Excutor
4.Excutor初始化线程池并向driver注册,为driver监控做准备
5.Driver开始执行用户写的代码,遇到action时产出一个job
6.DAG 根据宽依赖和窄依赖切割Stage,并在stage中将Task包装成TaskSet,传递给TaskScheduler,它只做Stage级别的调度
7.TaskScheduler将TaskSet封装成TaskSetManger加入队列中,与SchedulerBackend合作调度任务,SchedulerBackend会定时询问TaskScheduler有满足要求的资源需要调度任务吗,这就是Task调度
与其他方式的区别
1.上面是Yarn cluster模式,它与YarnClient模式的区别:YarnClient的Driver会在提交机器运行,但是申请的资源还是AppMaster。
整个过程中的需要通讯的位置
1.Executor对Driver的心跳机制
2.SchedulerBackend与ExcutorBackend的通讯
3.AppMaster启动Excutor的通讯
从上面的图中了解了大概的流程,那么在文字中提到Stage调度与Task调度是怎么做的?
Stage调度
DAG在划分stage中有以下几点注意:
1.stage划分为两种:
- ResultStage Action算子产生的最后一个Stage
- ShuffleMapStage 给下游提供数据的Stage
2.从第一个Stage开始计算,即没有父stage的stage,在DAG图中肯定是会出现同时调度多个Stage
3.只有当excutor丢失或者task拉取数据失败后,DAG才会重新提交Stage重试,其他情况的task重试都是TaskScheduler来做的
4.一个Stage是否被提交,需要判断它的父Stage是否执行,只有在父Stage执行完毕才能提交当前Stage,如果一个Stage没有父Stage,那么从该Stage开始提交。
Task调度
1.两种调度策略
- FIFO调度
- FAIR调度
- 调度器使用的参数:
name: 该调度池的名称
weight: 该调度池的权重,各调度池根据该参数分配系统资源。每个调度池得到的资源数为 weight / sum(weight),weight 为 2 的分配到的资源为 weight 为 1 的两倍。
minShare: 该调度池需要的最小资源数(CPU 核数)。fair 调度器首先会尝试为每个调度池分配最少 minShare 资源,然后剩余资源才会按照 weight 大小继续分配。
schedulingMode: 该调度池内的调度模式
2.FAIR调度策略通过配置文件fairscheduler.xml来配置队列
任务包装为TaskSetManager放入队列,在这种策略下是多队列的方式。通过一定的规则去在多个队列中取出任务给SchedulerBackend。
每个队列有两个参数:minshare和weight(minshare个人理解为一个资源的使用的最低下限,低于它说明队列的使用效率低下,不用担心不够使用)
-
当队列A的runingTask < A的minshare , B的runingTask > B的Minshare, 首先使用队列的A
-
当两个队列都满足runingTask < minshare 后,计算runingTask/minshare的比值,谁小使用谁
-
当以上的两种情况都一样,比较runningTask/weight的比值,谁小使用谁,即权重大的,运行任务小的更容易被选中
-
如果上面的条件都一样,比较名字
Task的本地性
本着减少数据传输的原因,在DAG阶段就会确定每个任务的优先在哪个executor,原则是尽可能的靠近数据。最好是在同一executor上。
当然在资源不足或者等待超时的情况下,任务会被移动到其他的executor上执行。所以如果发现任务的本地性不好时,可以提高一些等待超时的参数。
以下是各种任务本地性的描述:
- process local
- node local
- rack local 同一个机架
- any
Task的重试与黑名单机制
如果任务失败了,并且重试次数没有超过配置的次数,那么TaskSheduler会记录失败的executor的Id,并且放入调度池等待重新调度。
TaskSetManager就知道Task的失败与成功状态,对于失败的Task,会记录它失败的次数,如果失败次数还没有超过最大重试次数,那么就把它放回待调度的Task池子中,否则整个Application失败。
在记录Task失败次数过程中,会记录它上一次失败所在的Executor Id和Host,这样下次再调度这个Task时,会使用黑名单机制,避免它被调度到上一次失败的节点上,起到一定的容错作用。