InfoQ深入浅出Spark(三):Spark调度系统之“权力的游戏”( 七 )


总之 , 调用 rootPool 的 getSortedTaskSetQueue 方法获得的是按照预先定义的调度规则排序后的 TaskSetManager 序列 。 一旦施工副经理们排好了队 , 塔斯克即按照顺序把到手的人力资源信息依次传达、告知 , 那么 , 排在队伍前面的施工副经理们自然是近水楼台先得月 , 所管辖的施工工程任务自然大概率优先被执行 。
为什么说是“大概率”而不是“一定”呢?这是因为咱们的建筑工人多少有些傲娇和任性—— “挑活儿”!瓦工只干砌墙、浇筑钢筋混凝土;木工只干吊顶、安橱柜、安门窗 , 让他帮忙顺带着铺个地磁都是推三阻四不乐意 。 不过这也难怪 , 毕竟现在劳动市场人力资源紧张 , 工人们是按照小时计费的 , 因此时薪低的活儿人家自然是不乐意干的 。
回答刚刚“大概率”的问题 , SchedulerBackend 返回给 TaskScheduler 的 WorkerOffer , 都标记了最大本地性级别 , 不知道各位看官对于计算的本地性是否还有印象 , 我们在第一篇《内存计算的由来 —— RDD》中有简略提及 。 本地性级别的编号是从小到大 , 对应的本地性越来越差 , 顺序依次是:
Process Local <Node Local < Rack Local < Any
因此最大本地性级别可以直接理解为可以容忍的最差的本地性级别 , 也就是说最大本地性级别标注了这份计算资源所能接受的所分配任务的“底线” , 有点绕 , 咱们来举个例子:
对于某个 Worker Offer , 假设它的最大本地性级别是 Node Local , 这就意味着分配给该 Worker Offer 的任务至少可以保证 Node Local 这个级别的本地性(任务的执行不必跨节点拉取数据);换句话说 , 如果某个排在队伍前面的 TaskSetManager 所管辖的任务都无法保证这个本地性级别 , 那么这个 TaskSetManager 里面的任务是不会被调度到这个 Worker Offer 上去执行的 , 那么 , 它不得不把这次任务调度的机会拱手让给排在后面的其他 TaskSetManager 。
至于一个 TaskSetManager 中的任务哪些满足最大本地性级别、哪些不满足 , 则完全仰仗咱们的施工副经理 , TaskScheduler 也是通过调用 resourceOfferSingleTaskSet 来调用 TaskSetManager 的 resourceOffer 方法最终获得满足条件的任务集合(TaskDescription 集合) 。
我们重点看看 TaskSetManager 在 resourceOffer 方法中都做了哪些事情 。
第一步 , 就是通过内部的 dequeueTask 方法来获得满足本地性条件的任务集合;然后 , 将满足条件的任务依次进行序列化、生成二进制字节序列;最后 , 将序列化的任务封装为 TaskDescription , 把所有封装的 TaskDescription 以序列的形式返回给 TaskScheduler 。
按理说 , 到此为止施工副经理的工作做得相当到位、得体 , 老板交代的事情完成得相当漂亮 , 塔斯克应该很满意才对 , 没有道理对下属心墙高筑 。 坏就坏在 TaskSetManager 自作聪明 , 为了表现自己积极能干 , 每次都是活儿还没干完、老板塔斯克要的东西还没交差 , 就越级向空降老大戴格事无巨细地汇报自己的工作进展:手里负责的哪些施工任务交给了哪些工人去实施 , 等等 。
我们都知道 , 在职场之中 , 越级汇报是大忌 , 作为老板 , 如果列位看官您是塔斯克本人 , 下属三天两头向自己的直属领导汇报工作 , 您作何感想?前文书咱们说过 , 虽然塔斯克对于施工副经理的越级汇报是睁一只眼闭一只眼 , 但沉稳老练的塔斯克早就想到了通过变更聘用制度来釜底抽薪、防患于未然 。
TaskSetManager 在将自己负责的 TaskSet 中的任务集全部调度完毕之后 , 即被 TaskScheduler 踢出调度池 , 随即进入僵尸(Zombie)状态 , 等候他们的命运是被垃圾回收器(Garbage Collector)清理 , 想通过跟老大戴格勾搭连环实现上位的幻想也随之化作泡影 。 狠不狠?绝不绝?论心机与城府 , 笔者只服塔斯克 。