[关闭]
@gaoxiaoyunwei2017 2020-05-09T07:01:22.000000Z 字数 8574 阅读 568

斗鱼基于kubernetes的深度学习实践

彭小阳


作者简介:晏威,斗鱼TV资深运维,主要是负责斗鱼的所有应用的容器化落地。
2000118624988.png-88.1kB

一、深度学习在斗鱼的应用场景

那么我们先来讲第一个场景。在我们的深度学习这一块,我们在斗鱼这边有两个部门在做这个事,基本上就是分两大场景,一个是大数据场景,一个是视觉场景。

大数据场景基本就是做大数据的计算分析,比如说客服机器人,因为找客服,但是我们客服基本都是智能的,现在智能客服在互联网领域应用非常广泛,基本上都是日常学习常见的问题,生成一些学习的模型,根据用户提出的问题自动去解答常见的问题。

01.png-71.3kB

再就是智能弹幕,这个要介绍一下,斗鱼是一家直播平台,我们的主要的形式就是做视频直播,那么在这个时候其实一大特色就是发弹幕,大家平时看直播内容是什么不重要,我就是来看弹幕的。

在这种情况下,为了方便大家,比如说我在看到一些精彩的地方,我可能需要发一些弹幕的时候,你可能刚刚说了两个字,我们后台通过你这两个字,我们后台一分析,就把你整个要说的发出来,你就可以直接发出来的,这都是基于后台的强大功能。

再就是搜索排序,因为斗鱼的主播数量非常庞大,每天产生的视频内容也是海量,这个时候大家对自己感兴趣的主播和内容做搜索,我们会根据用户的偏好做搜索,检索之后对搜索内容做排序。

然后再就是智能招回,基本就是下载斗鱼尝鲜,但很长时间没有用,针对这个用户根据他历史的使用偏好向他推荐他感兴趣的信息,召回来,就是避免用户流失的场景。最后的智能推荐,这个跟搜索排序有点类似,就是主动推荐给大家。那么大家可以看到在大数据场景基本我们需要的就是海量的用户数据做分析,这是关于大数据场景。

那我们是一家做视频的,核心竞争力也是内容输出,但是我们在内容输出的时候,其实承担着各种各样的风险,到现在我还记得在2014年斗鱼流量历史高峰的时候,我相信大家听说过一个事,叫直播盗人事件,在这种情况下公司承担巨大的风险,所以我们需要尽可能规避这些风险。

但是在早期的时候,我们怎么样规避?我们可能有大量的人员盯着你的直播间,防止你违规,但是业务体量庞大通过人力做风险控制几乎不太可能,所以我们不得不引入深度学习这一块通过AI的方式做这方面的识别。

比如说图象识别,那是怎么做的呢?我们会识别你的画面有没有搞一些黄色之类的,有没有播出一些违规、违禁的游戏,或者你的视频当中是不是打上友商的LOGO等等,那在这种情况下你的画面我们不可能直接播出,那这个时候我们需要对视频进行识别。

那我们是频繁抓取你视频流的画面,通过海量的画面做一些计算,在本地计算之后形成模型,我们会有在线推理的业务,通过训练的模式实时监控你的游戏画面,或者视频画面、直播画面,以便于查看黄色、游戏违禁识别,或者一些其他图象识别等等的。

02.png-32.3kB
那除了图象识别,语音识别也一样,可能发表一些敏感言论,你说了你自己完蛋就完蛋,但是平台会跟着完蛋,这是得不偿失。这也有海量的语言,也就是大家平时说话,通过历史的海量数视频流当中把声音分离出来,通过计算分析,最终交给AI做运算,生成智能学习,学习之后在线上进行智能的云分析。
LOGO识别已经说到,我们肯定不可能允许你把友商或者敌台的LOGO拿到我们这里来。
再就是文本识别的场景,就是你发的一些弹幕内容或者是一些其他的文本的,我们可能也会屏蔽掉一些敏感词等等,这个毕竟互联网也非法外之地,不容胡来。

这是我列出来典型的应用,除此之外包括我们的打标,视频当中打上自己的LOGO,以及其他的内部一些不便公开的场景。事实上在这里我说到的就是相对来说比较主流的场景,这是我们整个斗鱼在深度学习领域基本的介绍,这一块我相信大家对我们大概的业务场景可能有了一个基本的认识。

接下来跟大家聊一下这些业务场景自始至终一直存在,但是斗鱼作为总部坐落在中部城市当中,而且公司体量不算大,那我们在云原生、容器领域的起步比一线互联网公司慢很多,那在业务场景当中,深度学习场景当中,这些东西早就存在,那我们巨大的问题就是迁移的问题,现有的东西如何适配容器的场景。

03.png-23.6kB

接下来我就跟大家接着先把业务场景说完,刚才说到的是我们的应用场景,接着跟大家介绍一下我们在应用场景下分为两种类型。做这块的同学大家了解,主要分成离线训练和在线推理,离线训练就是自己存储的海量图片、视频、语音、文本、弹幕、文件当中去抽取出来,做训练模型,在线下在离线的场景通过我们的离线训练任务去训练,最终生成模型文件,把这些模型用于在线推理。

所谓的在线推理就是在直播的时候我们会实时监控直播画面,通过我们之前训练好的文件去计算你当前的操作,你当前的画面有没有违规,有没有一些敏感的裸露,有没有敌台的标志等等,包括有没有说一些政治敏感或者一些少儿不宜的话题等等,通过在线实时我们会监控所有的直播间画面去做这些事情,以防止说哪一天栽跟头。

比如说前一段时间四位(音)老板干了这个事,那么在我们这儿,基本上你只要过来干,很快就会给你弄掉,不太可能有捅那么大篓子。

04.png-20.6kB

这是我们用到的技术栈,当然这些技术栈就是在我们还没有切入容器的时候,我们已经在跑了,使用了当下最热门的两大虚拟机框架,一个是谷歌开源的Tensorflow,一个是Facebook的Pytorch,同时使用谷歌的多开源的Kubeflow去做分布式的调度。

当然这是最早在传统场景,好在技术栈相对来说比较单一,其实这里面还使用了(1:06:46英)做任务下发,但是这种应用场景其实相对于Knative的接入本身来讲没有难度,因为这些技术的诞生就是完全符合云原生。

二、深度学习应用上容器的一些问题

接下来我就要跟大家聊聊我们接入的难点,因为从技术角度上我们接入其实问题不大,那从业务上面我们其实也有强烈的意愿去推动我们离线业务接入容器。统一调度,因为我们做一些视频流的分析,部署的时候非常复杂,不方便迁移,占有的CPU量非常大,在这种场景下几乎所有的需求就完全适合上容器,所以人的意愿也很强。

那么在这样的情况下,技术上不存在难题,人的意愿也很强,按道理我们推动起来其实是比较顺利的,我们从2019年下半年快过年的时候到当前我们已经基本上完成了全部基础设施的建设,包括60%、70%以上的接入,所以确实比较顺利。

05.png-44.9kB

那在里面挑几个小问题跟大家分享一下,第一个就是我们集群规划问题,这个跟深度学习没有关系,因为我们在业务上容器的时候我们使用的集群太多了,而且由于业务场景我们是属于混合云的场景,我们使用了多云加IDC组合构建我们的多活中心,在这种情况下集群管理本身就非常复杂的东西。

那回头当我们的离线业务和在线推理两种其实完全截然不同的业务虽然都是属于深度学习,但是业务形态上表现截然不同,那又涉及到我是单独为你跑一个集群,还是放在多个集群和现有的业务合并,尤其是在线训练,我们需要大量的GPU,在线推理也有GPU,但是用得比较少,而且我们是进程使用GPU,当你使用GPU的时候你说GPU使用率低,但是你对CPU使用率要求就非常非常高。

现在看来就不叫问题,但是当时我们确确实实做了一个规划,因为我们还涉及一个问题,就是我们数据集非常大,如果把离线训练跟在线业务放在一起全部在线上,其实代理商是一个巨大的问题,因为机房不在本地,但是办公会从本地上传视频、图片,那无论是走专线还是公网,以庞大的数据都是无法承受的。

所以后来我们仔细评估了一下,最后我们最终其实还是拆成两个集群,因为我们离线训练本身训练任务量非常庞大,对集群的要求也很高,而且对数据集的读取速度也要求非常高,在这种情况下,包括上传数据集,对带宽的要求也是非常高,这种情况下就把离线训练的任务拆分出来。

因为最早想放一个集群,低中期做离线训练,但是后来还是觉得不太现实,所以最终我们还是把离线训练放在武汉,在武汉的一个IDC当中,这样对于办公人员来讲,相当于在自己的办公电脑旁边,我们在做一些任务上传下发、模型训练、获取结果,都是相对方便。

在线推理就是直接和我们现有的在线业务直接混部,利用K8S调度做资源、容量的规划,相对来讲会省一点资源,这是关于集群规划这一块的。

06.png-39.8kB

再就是涉及到一个GPU调度,这是我画了一个简单的图,其实正常情况下,我相信大家可能在深度学习这个对Kubeflow不陌生,正常情况下我们会有一个任务,我们通过Kubeflow发起调度,一个任务可能会拆成Docker host,Docker host在不同的节点聚集起来,由Kubeflow本身帮我们完成调度,虽然底层的调度还是K8S去做。

但是有一种场景,因为应用我们想尽量不做应用改造,我们除了分布式的任务还存在一些集中式任务,那集中式任务就是一个任务不会拆,每个申请一个GPU卡,这个时候就是一个任务就要三块卡、四块卡,我不拆,因为分布式方便调度方便管理,但是训练的速度肯定不如集中式,所以分布式和集中式两种场景是并存。

这个时候产生一个问题,在我这个图有三个节点,每个节点有三块GPU卡,假如现在有三个任务,按照K8S的调度任务,三个任务会不会调度到三个节点上,比如说我node1需要一个GPU卡,就调度到node1上,在node1上使用了一块GPU。

接下来第二个任务又来了,这个时候是集中式任务,需要两块卡,K8S正常的默认调度去计算,node2和node3比较空闲,node1已经有一块在用,这个时候会把任务2放到node2,这个时候job2占用两个GPU卡,这个时候又有job3,又要一个GPU卡,这个时候调度到node3上。

这个时候看到node1有一个任务,node2有一个任务,node3也有一个任务,然后node1上的job1用了一块卡,node2上的job2用了两块卡,node3用了三块卡,这个时候整个集群还空闲一二三四五块卡。

现在我有了Job4,仍然是集中的任务,这个时候它启动就要三块卡,整个集群明明还有五块卡,但是这个图可以发现我调度不上去,这是我们遇到的比较严重的集群角度的问题。

那在传统的场景当中,在我们没有上K8S的时候,我们所有的调度是人工完成的,因为我们所有的训练都是直接在物理机上,我的任务直接在某一台物理机上发,虽然做调节麻烦一点,但是上了K8S有自己强大的调度性能,现在调度成这样,反而我的任务出现了问题,GPU出现了更大的浪费,这个时候怎么办?

为了解决这些问题我们不得不寻求一些解决方案,最早的时候我们尝试自己去开发一个插件,因为K8S支持第三方调度插件接入,后来我们评估一下成本,太高了,或者说有没有更好的开源的方案。

因为斗鱼在基础设施这一块的投入其实跟一些一线的互联网公司没法比,因为我们毕竟是业务驱动,我们比较年轻,没有历史的技术沉淀,现在的人力优先满足业务需求。后来我们调研确实发现了一个好东西,这个时候可以给大家安利一下。

07.png-104.8kB

这是由华为开源的一个专门针对AI场景、大数据、深度学习场景的一款调度器,叫Volcano,火山,这款调度器我们现在在用,几乎从各个方面来讲比较满足我们的场景,那它支持的调度的策略其实比较多。
在这里举例说四个,一种是Gang Scheduling,这个将一组容器作为整体调度,这个也是完美适配像Kubeflow,Kubeflow当你做分布式任务调度的时候存在一种场景就是说,你这个任务下去可能会分成若干个容器,假如说每个容器生成一块GPU卡,你可能需要十块卡。

但是现在整个集群的水位可能就是剩下五块八块,不满足你整体的任务类型,而这个时候你调度八个容器上去运行,另外两个容器其实没有意义,反而浪费资源,所以它会把一个任务里面所有的容器做整体的调度。当然我们也没有用到这个。

第二个是DRF,谁要的资源少,谁的优先级高,这个存在的问题占用资源多的有可能饿死。

我们用到的是第三个,那回到我的这个场景当中,我们使用Binpck之后,调度场景变成node1,node1上job1,然后job2也会用在node1上,job3会运行在node2上,那这个时候node3的三块GPU会全部空出来,job4是可以运行。

在这种场景下就完全满足我们这种分布式的任务和集中式的任务一起调度的场景。所以当我们发现这个东西的时候我们其实会觉得说挺好的,又省了我们一大把时间。那在我整个分享当中我安利给大家的都是开源的产品,因为基础设施这一块是多个社区减少我们自己的工作量。

最后一个proportion不多解说,因为我们用到Binpack这种方式,就是整个调度的算法是怎么计算的,它其实大概的计算就是当前的节点当中谁的水位最高,反而把节点往他上面调度,优先把你填满。当然这个在在线业务场景当中不合适,但是完美使用我们GPU场景,这是Volcano完美解决我们GPU多调度问题。

08.png-31.5kB

第二个是GPU资源利用率,这个是针对我们的推理场景。因为推理使用的资源比较低,所以尽量使用CPU,但是你仍然不排除有一些场景是使用GPU的,但是我们的一个推理任务可能用GPU,但是又用到一块GPU,而我们知道在K8S当中调度不只是K8S,就是整个GPU使用方式基本都是独占。

我们在分布资源的时候GPU只能按照整块看分配,但是我们的任务可能不需要一块卡,但是空闲的资源其他又用不了,所有当前的云厂商无论是阿里云还是腾讯云、华为云,他们的云厂商毫无里外退出自己的GPU虚拟化的方式。

所以现有的方案可以借鉴,但是基本上大多数没有开源,我们想那来用也用不了,一直在去年年底的时候我记得是2019年12月份腾讯的GPU团队将他们整个的核心代码全部开源掉,然虽然他们的芯比较小,但在一些场景当中提供的强大的功能是我们急需的,除了我说的GPU虚拟化。

关于这个项目的地址我也放在这里,在我们自己的IDC做测试的时候完全可以满足,可以将一块GPU虚拟化成一百块,可以要其中的十块,二十块这样的资源,如果说你只需要使用0.1块卡,那就意味着这块GPU可以同时有10个应用。

说到底就是解决了GPU浪费的问题,包括在上面我们说到的GPU的调度,也是为了解决资源浪费的问题,这个是因为我们有多GPU调度,而这个是要解决我们单块GPU资源不够,应用仍然使用不到整个GPU的时候。

所以呢有了这两个东西,其实我们最大的障碍其实就不存在了,基本上就非常省事了,因为我们在拿到整体规划的时候,我们做整体方案申请的时候,在解决一些问题的时候确实还是有一些头疼,因为我们也没有足够的人力做这些东西。

那我说到了GPU的虚拟化我顺便给大家安利一波,在我们的一些业务场景当中,大家都在鼓吹说云原生,我们将我们的应用切入K8S,但是总有一些应用不适合这种场景,或者必须做业务上的改造,尤其在业务上线之初的时候最大的工作难度来源于人员的思想改造,当然我说的不是视觉服务,不是深度学习,因为最难的我们已经过去了。

我是给大家聊一下像GP团队他们还开源了一个叫(1:24:40英)的组件,这个组件可以让我们的应用不做改造,维持ID不变,IP不变,就是将你的容器当做虚拟机用,虽然这很不云原生,但是能解决问题,因为在业务上容器的过程当中总会遇到各种各样的问题,总会遇到业务方的一些白眼。

因为这个东西会增加他们的工作量,而云不云跟他们没有关系,业务方可能不会关心工作设施,只关心自己的业务量和稳定,就是有没有在虚拟机上和物理机上稳定这是不言而喻的。那这是一些题外话。

09.png-95.6kB

这里有一个图,就是GPU-Manager部署的示例,可以看到我们会做一些资源的控制,基本上使用了一些字段来做到我们的进化。右边的图就是我的一个场景当中,在一块GPU卡的情况下运行了两个GPU应用,这个就是给大家展示一下,没有太大可以说的东西。

三、深度学习应用管理

最后跟大家聊一聊关于应用切入到容器之后的一个应用管理。首先这是我们识别服务的一个完整的整体架构。

10.png-87kB

从硬件的基础层,有CPU的计算、GPU的计算,当我们做一些离线任务的时候,我们会有大量的数据集,这种数据集是需要支撑的,我们会用到一些共享存储设备。

再上来就是引擎框架层,我们会有pytorch/tensorflow,还有一些推理和模型训练等等,还有涉及到GPU集群监控、GPU分布式训练、资源调度问题,当然这些问题现在已经解决。

还有平台工具层,最重要做到可视化,可视化这边其实借助的也都是开源的项目,像Jupyter,本身它是一个外部端,还有Tensorboard,我们希望整个过程做一些自动部署,模型的训练、推理等等,就是我们提供各种各样的工具去实现我们的一些功能。

最终我们会展现业务在视频、图象、文本、语音全方面做到自动的推理,做到不出锅,做全方位的视频监控。因为斗鱼最核心的业务就是视频这一块。

11.png-53.7kB

接下来是训练任务,这是离线任务的流程,我们在上传数据集的时候还是使用IDP,因为会把所有的训练任务放在本地,你走IDP可以上传各自的数据集,有了数据集之后可以创建训练任务。

在创建的时候你这个训练任务是否要训练,什么时候开始,会做一些审核,审核完成之后就可以训练,训练完成之后会输出模型文件,输出结果,包括日志和模型文件等等,这是整个大概用户使用的基本流程。

那基于以上从我们的架构以及我们的训练任务整个管理的流程,这一块我们其实自己做了一个内部的任务管理的管理平台,但是很遗憾告诉大家我们的管理平台这一块没有脱敏,所以我是没有办法展示给大家,那在这种情况下我就干脆就换了一个老图,这个老图已经包含我们整个管理平台的所有功能。

12.png-31.3kB

我可以把功能列出来给大家,如果大家有兴趣可以列为参考。那在整个模型训练完整的流程过程当中,首先是数据中心,数据中心用来存放数据集,那上传数据集的过程当中需要指定数据集的名称,还有数据集是哪种模型的类型,用什么训练。

比如说文本分类还是图象分类还是语音其他的等等,这个数据集存放在哪些路径,还有简单的描述,这是数据中心的内容,你首先创建数据集,接着你开始创建你的模型训练,那就是在模型仓库这一块,你要创建你的模型,训练模型基本上包括模型名称,应用场景,模型用在什么场景,内容识别、语音识别还是图象审核还是其他的,算法类别,那种算法。

镜像版本就是最终你的模型会以容器的方式下放到K8S当中,还有选择数据集用一些训练,再加上描述信息。你这个模型正式训练使用的时候之前要做测试,模型测试这一块也是必要的,在训练之前还要做一些审核,除了这一块的训练,其实模型这一块是分布式训练,还有集中式的。

这些任务是单个,每个任务启用Jupyter,那在这里也一样,要求你填你的任务名称,镜像类型,是GPU还是CPU,你的镜像版本,你所需要的计算资源有多少,你需要GPU还是CPU,需要多少GPU,需要训练多长时间,后面显卡数量就是GPU,再就是你要在哪个集群当中训练,因为我们的训练集群也不止一个。

最后还有监控,因为整个任务的执行过程当中我需要观察到整个集群状态和GPU使用状态,我们要求做到可观测,这是整个平台的能力。大家有兴趣可能根据这个东西自己去做或者怎么样,只是给大家提供一个参考。

13.png-33.3kB

接下来这一块就是刚才说到的,我在做任务管理的时候我是需要上传我的镜像,指定镜像,使用这个镜像下发到集群当中,至于镜像生成这一块是没有问题的,可以展现给大家,这是我们的发布系统,这是镜像构建,和任务系统是两个平台。

但是在发布系统上面做镜像构建之后,这个镜像会重置系统平台,可以在训练平台选择镜像,拿到镜像。这个镜像配置这一块涉及到你的配置名称,镜像生成的分支,因为我们是一个系统,我们这里还有一个应用管理,应用管理还有应用的基本信息,应用的仓库地址等等。

当你在镜像构建的时候会拿到应用的基本信息,然后会选择你构建你要生成镜像的模板,包括编译的脚本和参数,会引入这些以及K8S上下文等等,或者可以自己指定K8S的配置,最后通过你填写的生成一个镜像,这是关于镜像构建这一块。

那我们刚才说到这些内容都是我们的离线训练,接下来说的是在线推理,那在线推理的应用其实虽然使用了GPU,但是对我们来讲就是我们的在线业务,那会走我们的应用发布,就是在我们的发布系统中正常发布,这是我给大家展示我们的发布端,供大家参考。

14.png-42.2kB

比如说做一些配置,你这个发布流的名称,你是否支持,当然大部分是不需要互联的,这是容器提供的能力。会有你的应急环境、测试环境、生成环境,会有模板,基于这个模板渲染成一个模板,还会让你选择集群。

如果你需要指定运行的虚拟机上,比如说多少CPU,多少类型,启动指令,实例组的标签,镜像从哪里来,镜像的名称,日志路径,持久挂载,虚拟机的IP,更新方式是滚动更新还是,更新方式先建后插还是先插后建,因为是固定IP的时候只能先插后建,就是先删除30%。然后你选择要发布的运行空间,还有启动预热,是否使用虚拟机网络等等等等,这是整个发布系统提供的相关能力。

15.png-36.7kB

最后这是一个应用访问,你需要选择环境和关联的服务,要为你的软件指定名称,还有你要绑定的运营,你选择的路径最终生成一个预览,这样完成了整个应用的发布,这是关于推理这一块。

我们整个其实就是除了应用管理以及我们的应用上线发布,整个DevOps的基本流程跟大家大概分享一下。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注