我们首先来回顾一下热情仪的历史热情仪它其实不是一个新的话题其实从很多年之前业界就已经在尝试做热情仪这方面的努力了那么在2011年的时候CRIU这个项目启动了这个项目它的功能就是把进程checkpoint为文件然后再从文件恢复成完整的进程这也是至今为止我们主要使用的一个有关进程checkpoint和restore的一个主要的工具我们也是使用的这个工具但是作为容器热情仪来讲你光迁移进程光实现这一部分是远远不够的所以从2015年开始也就是在早在K8S 1.0发布之前其实K8S社区就开始了一个讨论就是在讨论说K8S到底要不要支持热情仪由于热情仪涉及的领域比较多而且问题可能比较复杂所以这个讨论这个e-shoot一直open到现在并且社区也一直没有提供热情仪的功能以至于连其实明确的roadmap都是没有的目前为止我们唯一可查的明确的商业用到的热情仪是2018年GoogleGooglebog的一次分享他们分享了自己公司内部在bog基金上采用热情仪的经验我们的热情仪项目是从2021年开始然后20年上线上线以后我们每天大概会执行2万次的热情仪这也应该是目前K8S领域里第一个可能也是唯一一个的生产级的热情仪的项目那么我们究竟为什么要做热情仪这个项目呢它的背景是我们腾讯的广告团队它在Flinger上实现了一套离线训练的一个平台像这种离线训练它对实验是不敏感的但是它占用了很大的资源所以它使用了很高的成本广告团队为了压低这个成本所以他们尝试把这种离线训练跑在一些廉价的腾讯内部的资源上但是使用这种廉价资源的时候也会带来一系列的问题首先就是廉价资源它虽然便宜但是它也不稳定这一点大家可以参考AWS的净价实力第二点就是因为它资源不稳定所以我们其实我们还是期望说这个作业能够长期的运行在这些资源比较充沛的这些节点上这就要求我们需要不定期的对Flink的这些Task Manager做一个重调度但是在Flink现有架构里你对单一的Task Manager做重调度的开销是非常高的它可能或者涉及到丢出去或者涉及到可能整个Job的一个重新的恢复所以我们是想通过热千银这个功能来做出一种低开销的重调度的方式这也展示了我们热千银工作的一个概述我们热千银工作可以分成三个方面第一方面最上面就是进程迁移它是单纯的进程层面的迁移这里我们也使用到了CRU然后我们在CRU的基础上做了一些backfix以及高级功能的一个开发同时我们还涉及到一些Linux kernel的一些patch因为我们需要去用到Time Name Space这个功能然后中间是KBS相关的内容KBS内容又可以分成三个部分第一个部分就是容器的网络因为我们在千银泡的时候其实也要把这个IP给牵走这部分我们是在Flamo上实现的这个我们之后也不会太详细的去说明因为这个还相对比较简单然后中间是Runtime运行时的部分运行时的部分这个之后我们会讲最底下就是编排部分编排部分它的工作就是把其他所有工作都串在一起那在整个KBS这一部分的工作里我们其实不仅仅实现了容器热签音的功能而且我们还实现了一些高级的特性比如首先我们实现了两种热签音的模式pre-copy所谓的pre-copy就是我我把进程的数据全部考到另外一个节点然后在另外一个节点启动进程这叫pre-copyhybrid copy意思就是我先考一部分数据然后在另外一个节点启动进程然后我剩下的数据在按虚的从原来节点去读取这个叫hybrid copy然后接下来叫no to no叫节点对节点的直接传输这个我们之后也会讲这个对性能会有很大的提升最后是我们也实现了一个单炮的多容器的一个前移功能最后一部分是flink就是flink因为我们这个项目是和flink团队以及广告团队一起合作的所以flink团队在他们的job manager里也对我们的这个工作做了一定的适配但是这部分的适配的功能量是非常小的大概也就是主要就是识别一些我们迁移功能中可能用到的label这些东西这一页展示的是我们在进程迁移上的工作左边这一部分是我们我们在迁移功能中进程的状态的变化首先我们看这张图就是从我们热迁移触发开始我们首先做的一件事就是传输进程使用到的文件在这个传输过程中我们的进程是正常运行的之后从cru.dump这个操作开始进程会进入到一个冻结的状态这个dump里它所dump的就是进程的状态比如计程计状态等等以及进程的内存同时在这个dump的过程中我们还会对进程的文件做一次增量的传输增量传输的目的是为了保证说我在恢复的时候两端的文件状态是一致的因为我们一开始传输文件的时候它的进程是在正在运行的所以可能文件会有修改整个进程的冻结是到cru的restore执行完毕之后我们在restore的这个过程里也使用了一个叫LaserRestore的技术它的特点就是我可以很快地让那个进程启动起来然后让它按需的去加载它所使用的使用的内存在这部分工作里我们可以看到这里提到了一个叫第一点就是我们没有使用cru自带的这种迭代迁移的模式因为所谓迭代迁移就是我一次可能只传输一部分脏页不断地传输脏页然后期待它脏页数量足够小然后我再一次性传输过去这种方式经过我们的测试它的性能非常不稳定因为它非常依赖于这个进程的具体行为所以我们在实现的时候是把这个进程一次性传输的同时为了增加这个传输的速度我们采用了这个书记压缩以及并发传输的方式然后这里还提到一点叫这是第三点叫Ghost FilesGhost Files是cru自己的一个专用名词它就指的是那些进程已经打开但是文件又被remove掉的这些文件在原本的cru中这些Ghost Files它首先是限定了大小它是只限定必须是100兆以内第二它的传输时间是必须在cru-dump之后的所以我们可以想象如果我们放在cru-dump之后在传输文件的话它一定会延长我们的进程的进程的动结的时间所以我们做的优化就是首先我们不再限制大小第二我们把这种Ghost Files也支持了这种增量的传输右边是展开的我们对文件系统的一个恢复操作首先我们在目的节点上我们会确保接收数据的目录和我们容器启动的时候要使用的目录在同一个FS里这样我们可以通过Rename这个系统调用来快速的恢复文件系统而不涉及到这种四盘上的拷贝操作第二就是我们容器使用的镜像的loader点这部分其实它本身就是容器的镜像所以这部分我们不是从原来的节点去拿的而是从镜像侧户里拉来的第三点就是我们目的节点在接收原来进程的内存部分的时候我们是在目的节点上开PD一块掛了一个碳排FS直接把对方的内存传到自己的内存里所以之后我们在恢复进程的时候也是从内存恢复到内存这个速度就会非常的快这部分是我们Rename的工作我们大家都知道就是在K8s里它其实没有容器的恢复流程的它只有新建和删除所以Rename的工作它的核心目边就只有一个就是我们希望在不修改K8s代码的情况下实现出一套容器的恢复流程我们的做法是我们开发了一个叫Migrate Run Time的这种热纤衣Ren Time它的位置是介于Continence D和RenC之间它可以拦截Continence D对RenC的这种调用然后通过这种拦截以及对OciBundle的这种分析我们去把原本的RenC Create替换成RenC Restore然后当我们在用了这个运行时用了一段时间以后我们发现这种从比较底层对OciBundle进行处理的这种方式非常适合于我们对业务的一些扩展因为我们都知道OciBundle里其实它提供了很丰富的扩展功能不仅仅是说你可以在里面进行自定义的比如Namespace、C Group等等的各种配置还包括它提供了很多丰富的互看而这些功能其实K8s只使用了很小的一点而如果我们在底层我们提供一些扩展的功能允许我们根据业务的需求直接修改这种OciBundle那就使得我们能够获得很大的灵活度以及非常直接的方式去实现用户的需求所以我们基于此也在我们的Runtime上实现了一系列的插件这些插件包括我们对大数据以及AI应用的一些扩展的功能这部分是容器编排我们在容器编排部分重点实现的就是右边的点对点支传在介绍右边之前我们先来看一下如果没有点对点支传它的恢复流程会是怎么样左边这个图其实也是跟Google报告当年分享的流程图基本是一致的就是它首先会把容器先淡迫到一个远端的存储然后它再重新创建炮的然后这个炮的经过调度以后选出一个目的接点它在目的接点启动进程的时候再从这个远端存储把数据拉回来进行进程的恢复这个流程的缺点比较明显首先我们可以看到因为你远端存储你在Drum和Restore的时候都是要用时间的而对于这个方案来讲进程的冻结时间是从头到尾从我一开始Drum的时候它就是冻结的直到我最后完成Restore它才恢复所以这里整个过程非常地长而我这个数据如果比较大的我会推送一次再拉取一次这个时间也会非常的长第二点就是远端存储本身也有可能成为系统的瓶颈因为我们想在一个比较大的机器里我们很有可能同时会有比较多的容器去迁移如果大家都存到远端存储的话它本身的性能就会影响我们迁移的性能至少它会导致我们的迁移的性能手柄非常不确定我们很难给用户一个明确的标准就是我们大概多长时间能完成这个操作第三点就是刚才说的我们这个进程的冻结时间是从第一步到最后一步一直是冻结的我们看到中间有两部操作就是operator去创建砲的以及砲的调度这两部操作在KBS里是完全是异部执行的所以当你在一个比较大的或者相对比较繁忙的机器圈里去做这种操作的时候它所耗的时间是不确定的而这种不确定对KBS本身来讲是完全正常的可是对我们若先进一来讲就会比较关键最后一点就是在这个流程里我们可以看到就是这两个砲是存在一定依赖关系的就是我肯定是要先杀掉第一个我才能有第二个那这种依赖关系影响的是什么呢影响的就是我们没有办法做这种hybrid的迁移你想hybrid的迁移它需要的是我两边的进程都活着因为我后边那个新的进程我要按需的从前面那个进程去存但是如果你在流程上就要求第一个进程必须先被干掉的话那我hybrid的这种方式就没有办法做所以我们综合了很多的考量以后我们自己实现了这种右边的这种点对点直传在这个点对点直传里我们第一步做的就是要选定一个我们要迁移的目的节点有了这个目的节点以后我们直接会把进程的数据淡迫到这个目的节点同时我们淡迫完了以后马上就会开始进程的恢复然后这个等进程恢复完了以后我们才会再去创建一个pod然后把这个pod调度到我们之前指定的这个节点然后最后我们会做一个remap就是容器和pod的remap这个remap是什么呢就是大家看那个流程里可能也会有疑问就是你如果先把一个容器恢复好了那你之后后来那个pod创建的那个容器怎么办所以我们remap做的操作就是它可以把一个已经存在的容器映射到一个新创建的pod上这样那个新的pod在创建出来以后它就已经有一个跟它配对的容器它不需要去新建同时我之前恢复好的这个容器我不需要做任何重启等等这一系列的操作同时我们这种remap还帮助我们实现了这种hybrid的潜移的模式因为我们可以看到右边这种图里其实新旧的两个pod是完全独立的它没有任何的关系所以我可以自由地控制它们两个共存多少时间这样就实现了给我们提供了说两边两个进程同时存在的这么一个基础然后第三呢我们可以看到右边这种右边这种我们这种方案的话因为没有从远端去拉取数据进行进程恢复的这个操作所以我们恢复数据都是从本地进行这个本地进行恢复的速度是非常快的根据我们对和google的blog的这个比较googleblog它当时没有公布它迁移的进程到底有多大但是从它的图里可以看到它的checkpoint和restore过程的耗时基本是一半一半在我们这个方案里我们的restore耗时几乎就没有所以不管这个进程有多大我们的方案至少会比它快一半左右最后我们可以看到我们的这个方案里在整个流程里能够影响进程冻结时间的其实只有远接点和目的节点两个节点的性能中间没有任何的远端存储或者operator的时间所以这套方案你不管是用在小提群还是大提群它的性能都是稳定的这也是我们展示了一下我们的性能数据左边这两个是我们比较的比较的热谦仪和泡的重建的性能我们这个测试的环境是在那种所谓腾讯的这种低优的资源上所以它的性能本身是有浮动所以我们大家可以看到P99怎么比P10好像多了这么多因为它本身的性能就会有一定浮动但是即便如此我们可以看到Precopy模式的进程冻结时间它和我把泡的干掉重新启动的时间总体时间是差不多的在那层为实际的情况下而你干掉泡的它就会涉及到数据丢失以及Flink这个恢复的操作但是热谦仪是没有这些问题的右下角那张图是我们Hybrid模式的这些数据从我这张图我们可以看出来Hybrid模式不管你的内存是怎么增长它的进程的冻结时间基本是一致的基本都是秒计有影响的就是它的按需加载的过程可能会随着你内存数量的增大而逐渐变长也就是说进程可能会在之后的一段时间内它的运行速度会慢一些最后我想讲一下我们对热谦仪和余恩生的这样一个思考首先在我们的认知中我们认为重雕度能力它应该是余恩生的一个核心能力我们在下面列了四种我们认为余恩生能够明显区别于传统应用架构的这四种能力首先第一个就是这种精加实力精加实力最大优点就是它便宜它非常的便宜所以你如果能通过重雕度利用好这种资源那你就可以直接降低大量的业务成本第二点就叫第二点是脱补优化脱补优化是什么意思呢就是我们可以看到很多雕度器它其实都会提到自己有脱补感知能力然后通过这种感知来让Worker之间实现一个更好的脱补但是我们知道极臣是变化的而你的雕度是一次性的所以说如果没有重雕度你一次性的这种雕度你最多实现一个局部的优化就是说在当前这个环境这个状态下你能做到也就是这个水平所以它能够提升的上限非常的低而当你有了重雕度以后你就可以不断地去找时间找策略去优化你整个的极臣脱补让极臣脱补得到一个接近于全局最优的一个水平第三是资源碎片资源碎片如果没有重雕度的话我们解决资源碎片无非也就是靠预测或者是规划但是我们知道我们永远无法得到一个极臣状态或者说我们明天将要提交了应用的一个准确的信息所以这种基于预测和规划的这种资源碎片处理方案它的上限也是比较低的而真正好的方案是什么是我们根据极臣当前的状态去动态地调整我们去动态地调整部署这样我们才能去不断地减少我们的碎片最后一个就是VPAVPA这个话题其实在社区已经持续很多年了但是它最大的一个问题就是它始终没有办法解决就是当我这个节点资源不够了而我这个容器又想往上扩容的时候怎么办目前如果没有重雕度的话能做到的无非也就是杀掉A或者杀掉B反正你就自己去选一个策略总要杀点东西但是如果有重雕度的话我们是完全可以把这个进程从当前节点迁移到另外一个资源充足的节点去给它进行扩容的那么热谦仪和整个上面的我们说到这些重雕度以及原生是什么关系呢我认为热谦仪提供的就是一种低开销的重雕度的方式我们为什么上面的很多的重雕度方案听起来很好但是一直没有人用呢因为我们即便是对于那种有完整的容错措施的这种大数据营用它也没有办法接受自己无缘无故的频繁的被杀所以当我们有了热谦仪以后我们就可以把上面的所有这种重雕度的策略有一个低开销的方式去执行同时上层的不管是应用还是隐形都可以为自己定制一套比较灵活的这种热谦仪的策略然后我们目前我们在腾讯呢我们也在和腾讯的大数据的隐形团队去把热谦仪能力和这种大数据隐形做一个深度的结合我们也是希望能够把这种热谦仪能力作为一种标准的服务提供给这些隐形的用户让这些隐形的用户一方面能够享受到比较低的成本另一方面又能有自己灵活的策略去完成自己的工作好 下面我的部分介绍完了下部分就是由我的同事刘华为大家介绍GPU热谦仪方面的工作大家下午好刚才我同事蓝眼蓝给大家介绍了一下针对于CPU这次我们做的工作其实对GPU来说其实这种需求也是存在的比方说其实对GPU来说它的TOP对它的计算性能影响是最大的所以说如果我们有重调的能力的话对性能影响是非常好的所以说我们在想就是我们能不能在GPU上实现热谦仪呢这里首先我们先看一下线状我这里其实以库达为例这是一个库达的一个栈大家看到栈是非常深的从底层是硬件然后内核中有些膜块然后用户态的话其实底下层是一些库达Driver的利部至上的话有哪个英伟达还封了一些Runtime的利部包括Runtime利部BLAST 还有CUDN这些库然后在这上的话其实那些框架比如TemperFloor和Pytox就建立起来了然后用户可以用这些框架的鞋带也可以直接使用库达的这些Driver或者是Runtime的APR来写这样的话其实相当于用户就可以直接去写库达应用了但是就这个价格来说其实GPU是作为一种直动设备来使用的但是对于直动设备来说其实现在没法其实支持这些意义对 我们可以看到其实这里其实主要有机链非常大的挑战首先是对于硬件来说它硬件状态其实是没法迁移的我们看了比如说GPU的机身器比如GPU的一些Q之类的状态文都是没法迁移的然后再又是其实对于库达来说它会把一些显存MAP到应用地址空间里这时候它就会把英文的地址空间进行一个污染这时候英文其实也没法迁移了然后再又是其实我们会用到一些设备文件比如说一些DV 引力达这些设备这些设备文件其实是和PCIE关联的它也是没法迁移的所以说一般来说如果我们想支持热情移的话一般需要这些Vendor 这些厂商来做这个事情这里其实我举了几个例子首先是引力达引力达其实它的VGPU是支持热情移的它有个限制首先是它需要拉屏然后再又是它比较适合于迅速商业的容器商业是没法用的然后再又是现在对于库达来说它是不支持CR的热情移的然后对于下面还提到AMDAMD它其实是GPU这个领域的一个GT者所以说它希望做一些额外的特性来吸引开发者它其实做了一些事情我们来简单介绍一下这是AMD给社区推广推广了它们的一个方案从这个方案我可以看到其实是英文大组做了几方面的事情首先是它修改了它的内核模块增加了很多GPU应用状态的导书导书接口比如说Memory, Queue, Event之类的然后再又是它为了配合CRU它还增加了一些英文的一个Resume和Pulse这样的接口来对进程进行暂停和恢复然后再又是它还提供了一个英文大的SO这个SO其实是可以连接CRU还有内核模块然后真正的去做这个GPU状态的一个策划然后再又是它还在给CRU增加了几个Hook这几个Hook就可以关联起就可以把CPU状态和GPU状态的迁移关联起来完成整个任务的迁移这是一个AMD做的事情但是对于英文大来说其实它没有提供中央的能力对库达来说我们应该怎么迁移呢其实这个事情在工业界其实尝试不多学术界有人在尝试现在其实大家比较一致的看法是一定要把GPU和CPU状态分开分开迁移比如说在CPU测我们可以用CRU来做对GPU测其实我们可以用LogReplay来做后面我会讲详细是怎么做的那这里其实就签了两个问题就是一个问题是我怎么能把方声Call转升到IPC Call然后再又是我怎么能够把这些GPU的操作进行Log然后再Replay当这两个事情做到之后其实相当于对于GPU和CPU来说它在两个地址空间里对CPU测我用CRU来迁移对GPU测这一测我可以完全用LogReplay来做对首先这两个问题的话我就分开来讨论一下首先是IPC怎么把方声转升怎么把方声转升应该到IPC Call这里其实一般大家方法也是比较固定的我们可以用LDP Load的方式把底层的库进行接持然后转发到远达去这里其实有两个层次我们既可以在Runtime做的蓝节也可以在Drawers蓝节这里我就分枚讲一下这两种蓝节方式的区别首先比较简单的方式就是我们可以直接在Runtime蓝节就是我们可以把用户的一些请求发给Runtime的发给Blast发给CODNA的这种API进行蓝节这里好处是因为这个大网是用户写的所以说用户用户的API都是一些公开的没有一些COD的API对这个实验起来就相对简单来说相对简单但它有一个问题首先是它的API数量是非常大的我们可以看到我们要蓝节上面所有的这种Runtime API同时用户也可以直接调Runtime API所以说我们需要把这些所有的API都进行蓝节这个数量是非常大的可能有几千个对然后再又是对于Runtime API来说它的一般是变化的会非常频繁所以说只要它发动变化了你的蓝节方式就要变所以说这里其实蓝节上就非常困难并且如果大家在容器中运行过那个裤带应用的时候就会发现这些裤其实是用户进行到自己带的所以说它的可供性其实是不是很高对然后再又是当你编一个裤带应用的时候其实默认变异的时候它Runtime这层它是默认是静态变异的所以说静态变异之后你就没法蓝节所以说你还需要重变应用让Runtime这个层进行一个动作链接所以这里就很大就限制了它的应用范围然后最后就是对于Java API来说它是C的对于Runtime API来说是CIA加的这两层API你如果转上IPC Core的话就会非常复杂特别是CIA加如果有CIA加它里边可能会一个参入可能是CIA加的一个Class这时候其实你如果比它IPC的时候可能就涉及到比较复杂的一个转换对然后除了这种Runtime蓝节的话其实它有方式是在Java层蓝节这里其实有几个好处就是首先它的接口是非常稳定的它完全是和Ning和摩块是稳定的所以说只要Ning和摩块不升级这个接口就是稳定的Runtime又是其实它的数量其实非常有限应该是一个版本可能有400加也会再增加但是不会增加非常多Runtime又是其实我们使用枯大Java Label的方式其实都是用动态的方式比如用Dial Open然后再用Dial Simple去找到对应的符号来使用所以应用其实不需要修改那最后是这层API其实都是C的所以说实验基态也非常简单但它有一个非常大的问题就是其实英明达实现的时候它Java层去调Runtime去调Java Dema的时候其实它不仅仅使用了这种开放的API它还会使用一些它的隐藏的函数比如说它可以通过COGatex PowerTable的函数获取一个函数指针然后它在Runtime后边就会直接用在指针在指针是完全没有任何公开的文档的所以这点的话就是会导致这个方案会比较复杂当中方考虑来看我们其实还是希望在对英文的影响计量小并且这个方案天下稳定我们其实还想在Java层进行拦截然后接下来就看我们是怎么拦截的这里可以看到其实我们可以把API分成两个部分一个部分是Open的一个部分是Close的 是封闭的对于Open的部分来说其实它的文档都在枯大.h里我们可以完全解析这枯大.h文件来生成一个把信息处理出来放在一个枯大.h 压帽这个文件里然后有些API是可以直接生成IPC的比如说一些简单的COE的这类的但有些API是比较复杂的比如说它可能设议到一些内存的传递内存的拷贝这时候其实我们就要对这个枯大压帽进行一个改变进行一个配置配置完了之后其实我们就可以用一些软件直接把代码生成出来这样的话其实我们测的是8-90%的API都是可以做生成的就不需要做然后另一部分是刚才说过的是这种封闭的部分这部分的话其实我们没有含住原型我们只能去做一些影响工程来把它解析出来这块我就不相信说了然后这又是刚才提到了我们有一个方法能够把这个API都进行拦截然后这部分是我们需要对API进行load replay其实不是所有的API都需要load replay的所以还要对API进行分类首先是有一部分API我们是不需要replay的比如说机身器机身器我们提到我们知道对于GPU来说它的核数也要远远大于CPU的核数它的GPU的数量也要远远大于CPU的数量并且我们没有办法去把它担不出来CPU那时候我们可以用PPC很方便担不出来这里我们的方法是一个我会让的方式我们可以用一个think方法就是把整个库大的Q给排空这时候当我迁移的时候我就没有任何活动看到了这时候其实我就没必要迁移这个中间的状态了这样的话其实我只需要迁移只需要迁移最终状态的显身就可以了只需要迁移显身就可以了另一种API是它只要不需要contact我们知道contact是库大变成中有一个很重要的概念库大contact它会把所有的GPU资源进行会计都属于contact我们认为只要不需要修改contact的这种API都是可以不需要replay的比如说CPU LUNCH CORNALCPU MAPIN COFFEE这种都是不需要replay的然后剩下就是两种需要replay的函数比如说一些涉及到资源的创建删除的这种接口比如说我创建contact我删除contact我申请mabry还是释放mabry这种其实都会修改contact我们都需要来replay然后再就是一些直接修改contact的API比如说CPU LUNCH CORNAL这种API我们也是需要进行replay的在这时候其实我们就对API进行分类然后我们分出来哪些需要replay但是还有一个问题是我们replay之后这些变量能不能发生变化发生变化之后会不会对业务场影响这里其实又需要对API进行一个更细的分类我们需要把这个和API相关类的资源进行一个分类分成可变和不可变的首先这一部分其实我们有一个分类就是在API其实这些资源对应用来说是不透明的这种是什么意思呢就是开启几个例子比如说contact module stream function这种资源这种资源应用是完全不需要去了解这种资源的他们只会把这种资源当中一种handle当需要用的时候就把这个handle通过库达考的询设发给库达列布它不需要任何理解这时候其实我们也很容易它可以变 没关系我们只需要再做个重新设就好了对然后另一种是对应用来说可见的这种资源这里其实最重要的那个就是显存地址我们知道parts和parts和tentaflow这种框架它会自己管理一个显存它管理方式其实当它启动的时候它会申请一个大块显存然后把它显存进行持化当它需要用的时候它可以拿出一个小块的然后供应户使用比如说它可以用传给meme copy传给less kernel这时候其实相当于它就需要对这个显存进行操作加下减减来获取它的指摘这种情况下其实如果你replay之后地址发生变化了然后再分配的显存很可能会和之前的显存地址冲突这种情况下如果冲突的话你这个工作就没有办法进行了所以说我们从我们的进行来看是我们需要把这种显存地址不变在replay的logreplay在replay之后才能进行下半工作那我们怎么做到这一点呢关键是我们发现其实我们需要做的是就是我们需要把我们proxy的地址空间进行一个重建重建之前和重建之后要保持一致才行首先我们看一下进行地址空间这里其实有两个部分其实是我们比较关心的就是第一个是这个heap区域heap区域相当于它的作用其实是当用户用malloc分裂的时候如果单身够小它就直接在heap区域分了如果这个区域太小了它就用brk来扩然后另一个表关键的区域就是这个map区域这个区域其实是表关键的现在有几种套道会影响这个地址空间的一个布局比如说如果我用大块的mallocmalloc的情况下是只要是大于128k的malloc它都会在这个map区域分配然后它又是fabrace的map一些匿名的map它都会在这个区域分配然后它又是枯大它也会在这个区域分裂的时候比如说它会掉malloc比如说它会把写成印上了这个空间里来所以说这里的问题就是我们关键是要把这个map区域进行重建怎么重建呢其实现在方法也比较简单首先是我们要把进行了地址随意化关掉地址随意化其实是一种安全手段它可以保证每次malloc的时候加个偏量所以有它之后其实地址每次都会变了所以说我们需要把这个功能关掉然后再又是我们可以然后我又可以把这个所有map区域的操作进行logreplay按讯息来做就可以达到这种目的其实大家如果调试过GDP的时候就会发现GDP它每次调试的时候它寄生的地址空间是不变的原因就是它其实它就关掉了这种地址随意化所以说这个方案是可行的然后这里前面提到了那个显存其实对于显存和内存来说它的关系其实现在来说越来越紧密我这里的标题是从分立到统一这怎么理解呢其实对于我们用显存来说一般有两个方式第一种方式是表传统的方式我们首先我们要从内存里把数据考到显存上然后再计算计算完了之后我们再把数据考回到内存里这个操作其实是表传统的我们中间加个proxy是没这个问题的加个转发模块是没这个问题的因为它都要经过我们然后另外另一种方式是其实应用也可以直接访问显存GPU也可以直接访问内存这种情况下其实由于我们加了一个中间的proxy库大应用和GPU之间它并不在一个地址空间里它没法直接访问所以说如果用到应用户用到的这种方式的话其实我们这个方案其实就blog了那这种方案是会不会影响我们的方案呢其实我们可以看库大社怎么做的怎么演进的首先是库大四的时候其实他就引入一种叫UVA的内存布局它其实也比较简单它其实相当于就是它在应用地址空间里把内存和显存进行的统一的编织这时候其实这样就能保证所有的显存地址所有内存地址都不会发生冲突也就是为它相互访问提供了一个基础然后它在这个版本中引入的一个表状的函数是库大Hosemann-Elloc这个函数这个函数可以获取一个P memory它其实有两个用处第一个用处是它可以加速GPU和GPU之间和GPU和GPU之间的这种数据传输它可以通过一些DMA的方式来加速这种用处方式是没这个问题的它其实只是一个加速而已还是类似于方案一的用法然后另一个是ZeroCopyZeroCopy什么意思呢就是如果你用库大Hosemann-Elloc分配的地址其实GPU可以直接访问不需要经过拷贝这种情况下其实它就是方案二这种方案的话其实相当于我们就不能支持但是通过分析通过我们的测试发现这种方式它对性能影响非常大可能就是有10倍的性能证号它是一种很低效的通过PTRE传输的一个方式然后再要是现在PrivateHosemann-Elloc这种注重性能的这种框架其实都没有用所以说这个方式其实对我们影响不大对 另一种方式是UVM其实库大6之后其实库大提供那个API叫库大Manage的这个接口它可以分配Unified的Memory这种Memory很特别的时候是其实我不太需要指定我到底是在CPU上分配还是GPU上分配显存了我只需要分配然后用的时候它会产生TRA-PCFOT比如说我在CPU上想访问一块这个地址它又会产生PCFOT然后这个地址这个信息就会从GPU考到CPU你在GPU访问的时候也是一样也会产生PCFOT从CPU考到GPU就是库大来负责保证这个数据的一致性这其实也是类推方案二这种方案有好处是什么其实它可以实现用户无感之类的一种齿化就是你可以用比显存更多的资源去跑一个应用原来不能跑现在可能能跑了但它问题是其实它一性能是不可控的当你用的显存大于实际显存的时候它的性能会积蓄下降所以说一般的像这种夸架它或者TRA-PCFOT这种夸架的话它宁愿自己去管理这种层级关系比如说它可以自己管理显存到内存内存到SZ的这种swap机制它也不会让库大做因为库大的库大的话它性能是不可控的所以说这种方式的话目前来看这种主流框下也都是没有使用的对 从现在来看其实我们不管是库大眼睛的话也不会影响我们这个方案的运行实际上也是这样的就是我们现在其实已经跑通了PATOX的一个backmark包括上面这里举了两个典型例子一个是Zenin的一个例子下边是一个Bort的训练例子我们看到其实性能还是不错的对于Bort这块的性能比较差原因是它运行时间比较短它这个时间大部分你都在加早加的Final Binary和Club它有800多个Final Binary有30,000多个Club这时候其实把时间都浪费在这里了其实我们这里没有做优化如果优化之后性能可能会好得多对 然后我们就是还找了一个例子就是我们可以14000亿Bort应用这个Bort的数据来源是应该是库大眼大学的一个电影台词对 大家可以看一下这个例子大家可以看一下就是不小声 没声音这里是吧 好 开始了不好意思啊大家可以看到其实上面两个例子其实是我们弄的一来个GPU利用率还有APP我们左边是一个套子窗口所以现在我们已经把APP和Proxy起来了大家可以看到对于APP来说在启伦光的钟现在我们的Proxy已经在使用GPU了这些APP应该是在启伦中还没起来这里它GPU U2和显存应用率都是0现在Bort应该是现在已经起来了我们可以看到它显存是用了50%也就是8G附近的显存这时候其实我们现在已经跑下来了现在我们触发迁移而这时候你发现这个应用其实退出了应用已经退出了然后对于GPU这块的话它的显存应用率已经下来了它在迁移在LOG整个整个操作这时候应用已经退出了因为我们没有话说 这个过程可能会表慢对 现在已经拆除完了现在在Replay我们的DrummerReplay我们的Proxy现在Proxy引起来了对现在还没有一话所以说速度相对慢点这里其实已经结束了我们看到这个应用已经跑起来了它和上面已经接着跑的它的Loss之类的也没有什么区别对这就是我们的Demo我们演讲就到这里大家有什么问题可以问一下我想问一下刚才那个热签的话它那个对内核版本有什么要求吗还有你们对内核有做什么感动吗这个内核这块主要是一个比较比较一个比较需要的特性是他们NibbisFace这个特性的话是在5.6有的可能你说一下你需要在版地板本上的话你需要把它泡到过去主要是他们NibbisFace对那上一位讲了您也是用同一个是吧内核签议方案也是一样是吧当然GPU对内核其实没有要求只是主要CIO对内核有要求你好老师我想问一下这个签议有实效性吗就比如说我先把它冻结然后两个小时以后我再给它泡起来那是签个Port也可以做也可以对签个Port现在很多大树英文都有签个Port的功能现在就是说在有资源的时候先运行但没资源的时候签个Port它过来现在拉起来也是可以做的刚才您说的那个Log和Replay是那个Log就是我之前那个GPU的进程执行的一些行为是吧对API我们其实只需要Log一部分API影响看开的API然后到时候我再Replay回去就比如说我有一个训练它可能要跑一周对吧它跑了三天段然后它Replay的话是它会把那个影响Contact的API都Log出来像你那个Lenskinal之类的虽然很大的它不需要Log但是Log确实会越来越长你运行时间长的话它Log会越来越长可能会变慢但我现在来看其实我们测试还是可以的还挺快的好的