K8s Spark on 提升集群资源利用率的方法我也有

K8s Spark on 提升集群资源利用率的方法我也有

如果你想在 Kubernetes 集群中运行 Spark 任务,那么你可能会对:如何在 K8s 上运行 external-shuffle-service 感兴趣。把 Driver 和 Executor 都当做容器,丢到 K8s 上(K8s 集群则把他们当做一般的容器,和其他业务类 app 一样对待), 这种模式,可以使得集群资源池归一 ,避免 Spark 一个资源池,业务类(K8s)集群一个资源池。提升整体资源利用率,统一维护也降低运维成本。这也是 Spark 官方在 2.3 版本后为什么要支持 Spark on K8s 的主要驱动力。

external-shuffle-service 作用

如果想要 executor 数量可以动态变化,就需要依赖 external-shuffle-service 功能(因为在 K8s 集群中,容器启动关闭很方便。所以非常希望 executor 数量可以动态调整,提升资源利用率)。

原因是在 shuffle 过程中,一个 executor 会到另一个 executor 那里取数据。如果一个 executor 节点挂掉了,那么它也就无法处理其他 executor 发过来的 shuffle 的数据读取请求,之前生成的数据也就都没有意义了。

为了解决“取 shuffle 数据”,和“目标 executor 是否运行”分开的问题。Spark 引入了 external-shuffle-service 服务。相当于先把 shuffle 数据暂存到 external-shuffle-service,然后大家去 external-shuffle-service 那里取就行了(类似于中介)。

更多运行原理请见

原来怎么部署

在原 Spark 框架中,external-shuffle-service 是部署在每个节点上的。

图片来自

(1)executor 告诉 external-shuffle-service 数据存放在哪里,(2) external-shuffle-service 记下来,供别人查询。所以 问题的关键是 ,数据放“哪里”支持哪些格式呢?我们看(1)里面通知是结构是这样的:

public class RegisterExecutor extends BlockTransferMessage { public final String appId;// spark application idpublic final String execId;// executor id public final ExecutorShuffleInfo executorInfo; // 《==文件路径
复制代码

可以看出,关键在 “在哪里” 要看(2):

public class ExecutorShuffleInfo implements Encodable { public final String\[\] localDirs; // 《== 第一级目录列表 public final int subDirsPerLocalDir; // 第二级目录列表 public final String shuffleManager; // shuffleManager的类型,目前只有一种类型 SortShuffleManager
复制代码

可以看出,shuffle 数据 “在哪里” 只能支持 HostPath(本地路径)。

问题的关键来了 :executor 容器跑在 K8s 节点上面,external-shuffle-service 跑在另一个容器里,要想共享相同 Path 文件,那就必须使用节点路径(k8s-hostpath);要用 Hostpath 还得拥有节点的所有权,这个对于多用户共享的 K8s 集群来说,权限不安全,数据未隔离。

在 K8s 上如何解决

Spark 的 external-shuffle-service 要怎么在 K8s 上运行,这是个问题。

[Spark 社区关于这个有个讨论:]

这个文档主要是表达当前 external-shuffle-service 的实现有缺点:

所以提出了 改进方向 :即 executor 保存 shuffle 数据时,不限定非得是保存在本地 Path 中。

具体实现方案可以有多种:

总体思路就是:以前 external-shuffle-service 是本地写,远程读, 调整为远程写,远程读

其实要在 K8s 上实现 executor 数量动态调整(dynamic resource allocation),还有另一条小路(即不通过 external-shuffle-service 的方式)。并且这条路已经实现了,在如下PR里

实现原理:

当发现 executor 里面是 shuffle 数据没有用了,则可以删除该 executor。如果这个 executor 里面的 shuffle 数据,还会被其他 Jop 读取,那么就保持这个 executor 存活着不被删除。从而实现 executor 数量可以动态调整。

缺点:

可以看出,这种方式其实是缓兵之计。

PR 里面的讨论也表示这是无法用来完整替代 external-shuffle-service 的。

社区路标

通过上面的分析,可以基本了解在 K8s 上面跑 external-shuffle-service 的困难和思路。

所以要达到目的的路径为:

看Spark的规划是在 3.0.0 版本提供完整能力,让我们期待 Spark on K8s 越来越 6 吧。

添加小助手微信,加入【容器魔方】技术社群。

声明:本文来自用户分享和网络收集,仅供学习与参考,测试请备份。