1. 背景介绍
作者在之前的文章《在SkyForm ECP上运行深度学习框架》中介绍过深度学习框架运行在kubernetes上的优势,以及这种实践方式的基本架构。
社区中也出现了很多tensorflow on kubernetes的方案,比如jinja模板的方案(https://github.com/tensorflow/ecosystem/tree/master/kubernetes),以及后来的kubeflow(https://github.com/google/kubeflow)和Tensorflow/k8s(https://github.com/tensorflow/k8s),都是为了能够更好的把tensorflow运行在kubernetes上,简化手工搭建tensorflow集群时的繁琐工作。
其中Tensorflow/k8s用kubernetes的CRD定义新的资源类型TFJob,可以在TFJob中定义PS、Worker和TensorBoard的信息,方便创建一个分布式的tensorflow集群。
SkyForm ECP的AIaaS的方案和社区方案的一个简单对比如下:
| Tensorflow/k8s | kubeflow | AiaaS方案 |
深度学习框架支持 | Tensorflow | Tensorflow | Tensorflow,Mxnet,Caffe |
Hybrid MPI Jobs | 不支持 | 不支持 | 支持 |
深度学习工作流 | JupyterHub,Tensorflow training,Tensorflow serving | 只支持Tensorflow training,没有工作流 |
Jupyter, Tensorflow training,Tensorflow serving |
Gangscheduling | 不支持 | 不支持 | 支持,自研 |
任务控制器 | 专门针对Tensorflow的控制器 | 专门针对Tensorflow的控制器 | 自研通用的HybridJob控制器 |
其它 | 无 | 无 | 完整的多租户、日志、存储、监控方案 |
SkyFormECP平台不但支持Tensorflow、Mxnet、Caffe等多种深度学习框架,而且集成了OpenFace等AI应用,以及经过严格测试开箱即用的算法框架。
2. SkyFormECP的 AIaaS核心技术详解
目前Kubernetes社区关于深度学习的方案基本都仅支持单一框架,同时调度器的功能也很简单。在实际的应用中还存在以下不足:
1. 扩展性差:很难扩展到不同的深度学习框架。如果需要扩展其它的深度学习框架,需要重写CRD,工作量巨大。
2. 资源浪费和资源死锁:使用Kubernetes原生的调度器,只考虑资源充足情况下的分配方案,对有激烈竞争时的资源分配方案考虑较少。而GPU资源作为一种稀缺资源,在实际的生成环境中必然会发生资源争抢的情况。
为了解决上述问题,SkyFormAIaaS平台中提出了一种HybridJob混合任务的概念,使用CRD定义HybridJob任务类型,开发了HybridJob Controller控制器对HybridJob任务进行处理。HybridJob中支持对每种任务设置最大副本数和最小副本数,以便在集群资源紧张时动态调整。同时SkyForm设计了新的调度器——Gang Scheduler,它在分配资源的过程中,不再将Pod单独调度,而是把相互关联的Pod作为一个整体来打包调度,避免只有部分Pod调度成功但是训练任务不能正常执行,已启动的Pod浪费集群资源的情况。具体的工作流程如下图所示:
1).用户使用kubectl或在Portal提交HybridJob资源对象,HybridJobController根据提交的HybridJob信息生成对应的pod;
2).Gang scheduler参考集群当前资源情况,决定在minReplicas-maxReplicas范围内运行哪些pod;
3).对已成功调度的pod进行bind操作,并将其提交到kubernetes集群中运行。
1. HybridJob Controller
HybridJob Controller是SkyForm研发的一种混合任务控制器,可以在Hybridjob中同时创建PS和Worker等多种不同类型的任务。HybridJob的模型如下:
HybridJob中可以有多个ReplicaSpec,每个ReplicaSpec代表一种任务类型。每个任务类型可以自定义最小副本数minReplicas和最大副本数maxReplicas,任务实际运行的Pod数在最小副本数和最大副本数之间。其中,最小副本数是任务运行必须满足的副本数,如果任务调度后获得资源的Pod数目小于最小副本数,表示调度失败,等待下个周期重新调度;最大副本数是副本数的上限。具体运行的Pod数目是根据集群的实际可用资源动态调整的。HybridJob和每个ReplicaSpec都有状态信息记录,可以分别查看它们的当前状态。
2. Gang Scheduler
Gang Scheduler是一种Pod组调度器,它保证了只有组中的minReplicas条件满足时才会真正创建Pod。这样的做法不仅在集群资源紧张的时候更灵活地调度资源,而且能有效防止资源死锁。
Gang Scheduler的特性主要包括两点:1.以组为单位调度相互关联的多个Pod,任务实际运行的Pod数可以在minReplicas和maxReplicas之间动态变化;2.兼容原生调度器的所有规则策略,比如NodeSelector,NodeAffinity,PodAffinity等。
Gang Scheduler具体的调度流程如下:
1)以minReplicas数目为目标分别调度每个ReplicaSpec。
2)调度成功后,以maxReplicas为上限分别调度每个ReplicaSpec,调度过程中考虑每个ReplicaSpec的优先级,优先级越高,其所属Pod的调度概率就越大。
3)根据调度结果修改调度组的状态,如果ReplicaSpec最终获得资源的Pod数目小于minReplicas,则认为该任务调度失败,调度失败后释放其中已调度成功的pod资源,重新添加调度组到queue;调度成功bind所有已调度成功的pod。
4)HybridJob Controller监听Pod的状态,根据Pod实际运行情况修改HybridJob的状态,删除未绑定的多余Pod。
3. 运行结果展示
本节以Tensorflow为例展示SkyForm ECP平台,在平台上应用Tensorflow的训练过程如下图所示:
1. 上传训练代码和数据:目前支持的后端存储类型包括nfs和glusterfs。也可以创建jupyter应用在线开发。
2. 启动训练任务:在应用市场选择tensorflow,填写存储信息、任务启动命名、PS的最小和最大副本数、Worker的最小和最大副本数等参数,点击部署运行训练任务,在以下动图中可以看到实际运行的副本数在最小和最大副本数之间,具体数目由gang scheduler根据集群的资源使用情况动态调整;训练过程中可以查看每个Pod的实时日志;训练完成后可以在存储卷中查看生成的model信息;TensorBord提供的外部端口可访问TensorBoard服务。
3. 启动Serving:在应用市场选择serving,填写存储信息,model的位置,以及model的名称信息,填写serving的副本数及资源需求;选择是否启用HPA对serving服务做自动伸缩,或者在serving服务部署后手动更改serving服务的副本数。
4. 测试Serving:在demo应用中输入serving的服务地址及端口,进行手写数字识别。
5. 重新运行任务:重新运行任务支持修改任务启动命令,传入新的训练参数;每次重新执行任务都会根据集群当前的资源情况进行调度,决定实际运行的Pod副本数。
4. 后续的计划
SkyForm ECP平台上实践了多种深度学习框架,针对实际应用中存在的部分问题进行了改进,并取得了一些效果。但还有许多特殊需求和技术问题需要进一步地研究开发,主要包括:
1) HybridJob中的pod数可以根据实际资源使用情况在min和max之间动态伸缩,现阶段只考虑了调度时间点的资源使用情况,任务运行后不会改变。当集群资源紧张时,需要考虑回收min和实际运行pod数目之间的pod,让排队的任务可以尽快运行起来。
2) 整合fair scheduler(基于Kubernetes的公平调度器)和gang scheduler,平衡多租户共享集群执行训练任务时的公平问题。
3) 调度时应考虑集群资源的动态变化,结合RNN等多种深度学习算法,使用各种监控信息做更合理的资源调度。
4) 增强对Spark、Storm等数据处理框架的支持,打通包括数据、计算和算法整个AIaaS生命周期的各个环节。