各位早上好 欢迎来到我们的Session然后我们今天主题是Building ProxyWith New Synchronous IO APIExploring ANVOID IO-Urain Integration也有所使用一个全新的IO API来构建代理来探索在ANVOID中间的IO-Urain集成我们今天的Session的话会比较多的涉及到一些技术细节方面的内容然后我是来自Intel的谢志浩以及我的同事徐赫杰在开始之前我们先介绍一下我们自己赫杰的话是Intel的一位云软件工程师他也在这个季度成为了一名ANVOID的Maintainer他也同样是OpenStackNover Placement Core Reviewer他主要专注于在ServiceMesh中的Data Plane然后在ANVOID中间社区中间的话主要负责类似于Lison IO-Urain相关的工作他在Ice以及OpenStack有了十年以上的经验然后我也同样是一名来自Intel的云软件工程师也主要围绕着NVOID展开工作主要涉及到是围绕着网络相关的一些组建的性能优化然后我们今天Session的议题的话是主要有这么几个方面首先的话我会为大家简单的介绍一下NVOID加Urain的一些背景知识接下来会由赫杰为大家介绍NVOID的L架构以及我们是如何在NVOID中间应用上LU-Urain的接下来我们还会为大家简单介绍一下我们即将推出的API以及它的性能数据以及现在的社区进展我们大概会用30分钟时间完成这些内容并且会为大家留出5-10分钟的Q&A时间好的那我这里首先为大家来介绍一下一些背景知识我们这个Session是一个Advanced Session所以我相信大家肯定已经知道NVOID是个什么东西了NVOID的话是在Service Match或者是Colonelative中间一个比较常用的proxy它从Ingress Gateway到Egress Gateway以及各个Container中间的Sidecar中间都会广泛应用可以说NVOID是在Service Match的方方面面中间都被使用到的然后在我们之前的一些性能测试中我们发现在NVOID中间有大约30%的CPU占用会消耗在RadeWrite相关的系统调用上面即使是在一个简简单单HTTP Routed的Case上然后或许各位可以通过类似于VCL之类的方法来进行优化但是如果应用上VCL的话就需要着一个Advanced VPP Process对VPP进行调优也是一项非常耗时费力的这么一个工作于是在这种背景下我们开始了对IoUrin的这么一个调研IoUrin的话是自Linux 5.1开始引用的一套全新的异部框架可以说不新也不旧但是在各地方的应用场景还是相对比较少的IoUrin的话它主要是有两个RimBuffer组成这两个RimBuffer会很跨在Uther SpaceColonel Space之间然后应用可以像Submission Cure也就是提交对列提交它的作业之后IoUrin会通过它的Work thread来完成这些作业并将结果返回到Combination Cure也就是结果事件对列中间然后应用上IoUrin的话将会有这么几个好处首先相比起以前单次的Read the write都需要通过SysCore系统调用来进行IoUrin的话可以一次性一批量的往Submission Cure中间提交作业然后只需要一条SysCore就能让IoUrin工作起来所以说会有着更少的系统调用同时相比起以前Read the write会有Colonel Space到Uther Space的这么一次Memory CopyIoUrin的话你可以提前将Uther Space死的一些空间给映射好了然后将相关的内容直接存给Submission Cure那么IoUrin再进行Read the write的时候就会直接作用到这些Uther Space上面所以说也会表明了更少的内存拷贝然后IoUrin虽然好归好但是它是一个完全异部的架构跟NV的试验驱动的架构其实有着比较大的区别所以在这种情况下面我们就开始了调演如何在NV中间用上IoUrin接下来的话就请贺杰为我们介绍一下NV的架构以及我们的一些实践谢谢志浩计划是先给大家大概的介绍Inmo的IoUrin的架构是什么样的然后大家有一个大概的印象之后然后我就可以开始给大家介绍我们大概是如何把IoUrin集成在Inmo的IoUrin当中首先其实Proxytel这已经存在很多年了然后对于IoUrin的模型其实是比较固定的所以我最用了很简单的也把一些重点给大家介绍一下首先介绍Inmo的现成模型然后很标准的单进成多现成的模型然后对于熟悉Kubinets或者熟悉OpenSI或者Eastrow同学都知道对于编排层我们可以我们都这儿分为两部分一部分是控制评变一部分是数据评变其实你看到Inmo内部也是这样的你可以把MindStrike去想想看这些控制评变然后把WalkerStrike想成数据评变然后对于MindStrike主要做的事情其实就是解极你的配置或者从XDS API下发的配置然后它将这些配置分发到各个WalkerStrike当中然后对于WalkerStrike的其实它就根据MindStrike下发来的配置然后做相应的网络代理所以所有的网络IO基本都是在WalkerStrike当中做的当然除了MindStrike的WalkerStrike还有什么FailFlashStrike当然不是我们今天重点我们今天重点其实是想让WalkerStrike中这些网络IO的操作可以用到Socket API挪到IO Urino API上下一步介绍一下Invote IO模型其实当你当invote启动的时候invote基本上是按照你所指定的WalkerStrike数量然后启动对应数量的WalkerStrike然后每一个WalkerStrike的都会按照你Listener所配置的那个地址去Listen然后从非常highlight你其实可以想成Colonel会当任何一个Downstream的新连接来的时候Colonel会帮你唤醒其中一个线程然后在这个线程去接受这个新的连接随后这个新的Downstream连接以及这个Downstream连接所对应的Upstream连接基本都与这个WalkerStrike所绑定了当然Invote也支持说在你Colonel唤醒其中一个Strike以后你接受这个连接以后你可以在用户空间做一个Balancing这是唯一一个机会一个连接在Strike中迁移的当然这只是一个特殊成竞我们大部分时候这一个连接其实都跟一个WalkerStrike的生命周清榜那一起了所以你当在Invote的数据平面去coding的时候大部分时候是不用考虑多线程当然Invote为每一个WalkerStrike都跑了一个事件循环然后通过事件循环我们实际上Io服用所以在每一个WalkerStrike的中我们会处理很多网络连接的Io操作当然这个事件循环是基于LibbEvent然后对于LibbEvent其实大家从Highlightwork可以理解其实就是个对EPU或Slacks这些Io服用的API的一个封装OK 这些是Invote Io的基本一些概念然后下面给大家介绍我们是如何把IoU Run集成在Invote Io当中然后第一步其实要想事情是怎么把IoU Run集成在Invote的事件循环里头然后基本上Invote里所有的网络Io文件Io 甚至Timer都是基于LibbEvent的这个事件循环实现的所以我们第一步想的是如何要把IoU Run去集成在事件循环里这是最重要的事情但是很不幸是LibbEvent当今不支持IoU Run就是说你现在想通过LibbEvent的事件循环然后把IoU Run直接用起来是做不到但是很幸运的是IoU Run支持Event FD也就是说每当IoU Run有一个Io请求完成的时候它都会pulse一个事件到Event FD上然后这个时候呢我们其实可以通过Event FD去注册到Invote事件循环当中然后我们就把IoU Run和LibbEvent的这事件循环瞧解起来了就是说每当IoU Run有一个Io请求完成的时候然后IoU Run就会pulse一个事件到Event FD然后这个Event FD我们针对这个Event FD会注册对应的Callback也就是说这个Event Loop会返回然后调用我们所VoU Run注册的Callback然后这个Callback就会调用我们后面想要介绍我们VoU Run这个仔细统实现的代码然后下一个我们就要实现Soccer Interface然后如果熟悉invo配置的同学应该知道Soccer Inface基本上是你使用invo时候用来选择一个Io实现的方法当然它也是一个接口用来给dviper来提供不同的Io实现当今Soccer Interface有三种实现一个就是defaultdefault就是我们传统的Soccer API另外一个是VCR刚才只好也说了是一个用户空间协议站还有一种是User SpaceUser Space基本上就是实现从同一个invo进程的一个listener到同一个invo进程的另外一个listener所以它就是纯粹的一个memory的一块模拟出来一个连接然后这个最大场景用的其实是internal listener然后最大用户其实是ambient mesh如果熟悉ambient mesh同学应该知道这个东西所以第一件事情我们想的可能是我们需要给IoUrun先实现Soccer Interface然后但是跟社区讨论下来说社区认为IoUrun还是Linux Kernel未来很重要的一个API所以他们希望把IoUrun直接做到defaultSoccer Interface所以我们在defaultSoccer Interface就实现了自动的Linux Kernel的能力检测首先我们要确定当前invo所运行的主机上的Linux Kernel由我们所要所有IoUrun的基本的feature然后有这个feature以后我们就会自动把IoUrun由先用起来当决定用IoUrun的时候Soccer Interface基本上就会去每一个线程当中去出手化IoUrun当然后面的讲解你会知道为什么要去每一个线程里去优化去出手化IoUrun然后下一步就是实现IoHandoIoHando可以理解为是在invo当中对于IoUAPI的一个封装基本上它也是保证invo上层的所有代码四层 七层代码对底层IoU平台的无感知比如说对于Linux屏台我们有默认的IoHando的实现然后对于Windows屏台有一个实现然后有这个实现的原因存在其实就是因为Windows上Soccer API跟Linux上Soccer API在行为上有些不一样所以要特殊实现一个Win32的用来保证invo上层代码对底层的这些平台上API的差异无感知所以到了我们IoUrun上面其实遇到同样的问题因为看到这里其实这个IoHando是一个IoAPI的出象但这个API的模型基本上是基于Soccer API的所以Soccer API的模型跟IoUrun API也是完全不一样就像前面致号介绍IoUrun的API是完全异补的所以举一个最简单的例子比如说这里写的是Rat比如举一个Close的场景比如说我们要CloseSoccer的你用传统Soccer API你一定要用CloseSoccer以后基本上就可以认为我已经完成这个连接的所有的事情了然后Invo就会开始让IoHando已经上层四层三层所有资源就开始吸购了然后这对于Soccer API是工作但放到IoUrun上我去CloseSoccer的时候我发了一个异补的Close请求然后发完这个请求并不代表这件事情做了所以如果这时候IoHando已经上层所有的资源开始吸购了但是当这个Close请求一完成的时候它回来发现所有资源都不在了就变成野指针了然后你的Invo就变成Crash了所以为了把IoUrun集成了起来我们基本上为了IoUrun介绍了一个紫模块然后能保证IoUrun的实力能与IoHando有分离的生命周期所以第一步是我们介绍了IoUrunSoccerIoSoccer其实理解就是对于每一个Soccer的FDSoccer的文件描述服的一个封装以及针对Soccer的所有操作读写IoHando也是通过IoSoccer的读写的API去模拟上层的操作的所以当IoSoccer的启动的时候其实它背景的就是已经去提交比如提交Rid的Io请求了然后上层的IoHando其实不知道只有说当Rid的请求已经返回来我们才会去通知IoHando说你现在这FD是可读了然后IoHando就会来去读IoUrun已经读回来的数据的Buffer其实这跑去传统API看似的是也是类似的只不过是用传统Soccer的API的时候是IoHando去从ColonelBuffer里通过Rid的SysCode取出来但是IoUrun是我提前已经把你读出来了然后IoHando直接从我这个IoSoccer的已经读回来的Buffer里把数据取回去下一个概念就是IoWalkerIoWalker其实就可以想象成是IoUrun的一个事件循环既然是事件循环刚才也说了IoInfo对于每一个Walker thread都运行了一个事件循环所以对于IoUrun一样我们也对每一个Walker对于每一个 threadWalker thread我们要跑一个IoUrun的一个事件循环然后这两个事件循环其实就通过前面说Even的FD串接起来了同时IoUrunWalker还要管理所有在Sride上所运行的SoCade它会负责他们生命周期它会负责创建SoCade以及消费一些SoCade所以在串集前面的故事就会变成说每当有一个IoUrun的Io请求完成了然后IoUrun就会Pulse的一个事件到他所对应的EvenFD上然后这个Even的FD变成可读了所以LibEven的这事件循环就会触发我们当初为IoUrun注册的codeback然后这个codeback就会把事件发送到IoUrunWalker上然后IoUrunWalker又会针对说这个Io请求是对于哪个SoCade以及是某一种是哪一种是Red还是Red还是Closed操作然后将这个请求去分发到IoSoCade的所对应的codeback上然后这样整个事件恋爱就基本上连在一起了所以这是多谢只好画一张图然后把所有东西都放在一起了然后当然讲这张图就讲不清楚了所以从highlight我看一件事情就像我前面讲每一个Walker帅其实相对独立的然后我只画了一个Walker帅然后我没有画七层直接从四层画因为七层也通过四层在写然后从四层基本上表达所有的事情上面可以看Connection基本上是Invo对四层连接的抽象然后TransformSocket就是对SSL、TRS这种操作抽象当然如果你不用TRS你用明文的Rogue是基本上TransformSocket就是什么也没做就透传到调用IoHando所以看到这条黑线这条黑线的代表这条黑线以上所有代码是对平台不感知的它不知道底下你是Linux你是Windows它也不知道你是用的是默认的Socket API还是用的VCL还是用的IoUrin所以我们这里紫色就是我们要实现一个IoUrin的IoHando然后这个IoHando基本是用来用底下这些粉色的IoUrin的模块去来模拟Linux上这个Socket API的行为然后粉色这块基本上就是我们的IoUrin的一个仔细统然后前面也说了IoUrinSocket是对每一个Socket FD封装当然IoHando也是针对每一个Soldier会创建一个实力所以它们是一一对应的但是它们会有独立的生命周期底下IoUrinWorker负责管理上面所有这些IoSocket然后最底层是DispatcherDispatcher其实就是IoInvoteLinux Event那个事件循环然后这个Dispatcher与IoUrinWorker就是根据英文的FD连接起来了然后整条Channel就串起来了OK,后面让之后为大家介绍API和Banchmark好,刚刚的话就是我们的所有的技术细节的部分然后包括这个Slice是中文的还是英文版其实我们都已经传到了Coopcone & ClownativeCone的日程中间了所以各位可以去下载一下就像刚刚那张图表复杂如果没有看清楚的话然后再做的话应该会大家可能不太关心细节的话可能更加会关心它是怎么用的然后包括IoUrin它的性能会怎么样然后我们为IoUrin的话引入一套其实来说相对比较简单的API没有加出的部分的话是NV原本的API就是虽然说你在配置文件中可能没有写这一部分但是NV还是会默认去调用它然后我们只要简单的一行EnableIoUrin就能把IoUrin的功能打开了同样的我们也给了一些IoUrin的可以自定义的部分比如说IoUrinSizeSize的话就表示你的Submission Queer以及Connection Queer中间的大小Size越大就表示承担的作业的数量越多AcceptSize是我们为IoUrinAcceptSocket设计的一个API它的话类似于TCPListen的backlog的一项功能最多可以接收几项AcceptSocketReadBufferSize和WriteTimeout是为IoUrin的ServerSocket以及ConnectedSocket也就是说是传入以及传出连接设计的APIReadBufferSize的话是你提前预留给Write的作业的一个大小然后WriteTimeout的意识正如刚贺杰为我们描述的因为IoUrin是全部一部的在你close了之后这个close的作业交上去虽然是交上去了但不一定它已经做完了比如说在Write的缓冲区中还有一些上位写出的数据那么我们就会给它一个额外这么一个宽限时间来让这些作业全部完成最后的话是IoUrin的一项功能就是Submission Queer Pulling简称就是Accept Pull这也就是说IoUrin可以通过CPU来换取更短的掩饰它将激进地去Pull它自己的Submission Queer中间是否有作业还存在然后会去做它们就有种类似于像DPDK的那种Pulling Mode那种感觉然后我们根据了这样的作业负载然后对IoUrin进行了一个测试我们把NV和一个Fort IoU的Echo Back Server放在了一个容器中间来模拟这种Sidecar的场景NV是单线程工作的我们也首先是没有限制QPS来测试一下我们最大的这么一个through port然后会将QPS进行动态调整来测试一下它们的延迟然后简单来讲的话就是应用了IoUrin之后在through port上面我们大概会有10%左右的提升同样的延迟也是类似当作业量比较高的情况下的话也会有不到10%差不多10%的这么一个延迟的减少然后接下来是我们的一些社区动态的事情因为荷杰是NV的Maintainer我就不在这里办门弄斧了还是让它为我们介绍一下然后最后给大家update一下我们社区开发的进展然后我们基本做了三个版本的迭代然后在第三个版本时候基本上我们解决所有不稳定的问题然后终于Ci变绿了然后当然这是对比我们第一个迭代第一个迭代的时候基本上我们除了IoUrin自己UniTest和IntegreationTest我们主要是靠invo自己的invo自带这些integreationTest来保证我们IoUrin的实现是兼容的所以初算的话如果invo有80个测试文件然后保守算一个测试文件里10个integreationTest其实有小800可能所以在我们第一个实现里基本上有90%的integreationTest都错的而且如果在做各位有Dewyver你们大概测试测试都是大概的某一个ACB请求某个数据是你预期的但是在我们开发当中基本上全是断错和貪冒的因为那些测试都是从highlight我说我发某一个ACB请求然后期望得到一些ACB的respond但是真正错误到底曾经已经变成read write所以说我们都要解析到说最后这些read write到底在干嘛然后还多谢我们最后IoUrinSocket的抽象然后所以我们实现了隔离是一个积累所以它是一个抽象但是针对于Listener的SocketServiceSocketClientSocket都会继承自己的实现然后他们有独立的逻辑所以在开发中给我们了一个便利就是相当相当用把inmode这个底层的Socket的一排T换成IoUrinSocket的一排你可以想象说inmode是一个100层大楼然后我们把第一层给敲掉然后重新盖当然你直接全敲掉了能不塌吗这塌的很稀碎幸亏有IoUrinSocket这个抽象我们可以把它分成三份去做但是每一份还是比较大的所以费了很大金然后前面说我们基本资料都过了当然有些测试还没过这些测试没过的原因基本上是因为这些测试去假定了底层IoU这个IoU操作的行为所以导致说那些测试还不能过但并不是代表那些测试是不是IoUrin实现的问题其实我们最后可以为这些测试重写一个IoUrin的版本就OK了然后好消息我们已经开始merge然后大概应该有merge了30%促算下来然后我们跟社区上令的第一个版本我们只是限TCB因为TCB的实践已经在第三版本的跌带已经接近六千行然后估计最终merge的肯定会要大于六千行所以第一步我们只是让TCB因为TCB用的场景最多然后后面再考虑UDP然后后面后面进化器当然很重要的就是把剩下代码的模式置进去然后我们还有很多问题没有解决比如说我们Buffer大小应该是多大我们的Buffer管理更产品化的管理所以这些东西其实还没有做我们第一步其实想让能测出基本性能让完整的营贸功能是能跑起来的然后然后后面我们当前基于的是cernal的5.15版本然后因为这个版本有我们满足实现iO URIIN整个Invose iO操作最小的feature级然后基本上iO URIIN会随着cernal升级老有新的feature加进来后面我们希望说能更新力度检查cernal的能力然后一旦有新的feature能把它们也用起来但是最最最最后是终极的理想如果有天大家说OKiO URIIN可能应付了对大部分场景是OK的然后有足够的稳定就像我们说iO URIIN Worker其实实现了也是世界循环也许如果LVUIN的也不去支持iO URIIN也许有一天我们就可以用iO URIIN去替代LVUIN的去实现世界循环了好 今天就这么多然后最后是Q1会在QA环解大家有什么问题吗您请说就是这个Buntmark看起来这个收益不是很高在10%左右就是说这个是跟你们测试刚才这个基准的那几个参数有关系还是怎么样的因为其实10%的收益其实大家可能比如在生产环境可能是不太会去因为10%的收益去调整的因为像iO URIIN它的这个内核的版本其实是5.1其实是蛮高的大家在生产环境其实都不太可能有这么高就大家如果说要想用这样的一个新的feature的话可能需要可能有更多的这个Performance的一个Boost可能大家才会有动力去想用这样的新的feature不知道你这边会我看你刚才的一个后面的一个follow-up里面也会提到有些关于Performance方面的东西可以再稍微聊一聊吗谢谢就确实来讲的话我们的最小版本要求应该是5.6就是能提供了我们现在的iO URIIN的所有的支持然后我们这里也提到了一些就是iO URIIN的Fix the Buffer以及iO URIIN的Zero Copy的这些内容他们的话可能会需要一些更高的版本要求所以我们还在去看他们我们相信的话有了这些功能之后的话可能也会给iO URIIN有一个更大的提升其实从底层这一层来说就是在不动它架构的情况下面百分之十的提升已经算是已经很难把它扣出来这么多了其实您问的对刚才志浩其实在前几页看了整个invoid的iO操作也就百分之三十的占比就那么多所以提升百分之十我们觉得是OK其实我们觉得我们想iO URIIN可能最大一优势就是它是Linux原生的一个API你不用去依赖某一个用户空间的协议站你不会用EPBF在你的系统就是插各种EPBF程序所以它是最小的如果说某天iO URIIN API被采用的很多变得很成熟所以就相当于说你默认就会得到一个东西而这个东西给你了百分之十或者更多的性能所以我们想的既然社区Linux Kernel社区认为iO URIIN API是一很新的API他们也其实还是在积极开发当中所以我们觉得这值得是社区其实也很阴谋社区其实也欢迎它觉得是我们应该去支持的方向因为也许未来它会很有用而且你不会付出很多成本去得到这件事情当然如果你期待得到说特别大量提高百分之八十百分之九十百分之一百我们可以说就是bypass了其实并不是在阴谋内部做任何事情能做到其实那就更多去看bypass或其他的东西希望回答您的问题谢谢还有其他问题吗OK没有别的问题我们今天就您请说好谢谢我可能想问一下如果我们引入iO URIIN之后它有一些额外的成本吗因为您获得收益之后总归是有一些额外的成本或者说有成本来获得这些收益的我想问一下我们需要付出的成本会是什么样的呢其实就刚才说其实它是Linux的原生的API了我们觉得算是比较小的成本了可以这么说当然眼前的成本其实很明显就是需要更新版本的carnal但这个随时间的增长你的成本会变得更小然后另外一成本就是我们需要时间就需要时间让这个时间变得稳定下来然后去挣还需要去当然Linux的carnal也只持续开发希望它去最后中证明整体的性能提升如果整个Linux在carnal从面向性能提升都不够那整件事就没了可谈了就这么多谢谢还有别的问题吗我们还剩三分钟可能还够有一个问题OK那没有了我们今天就到这里了谢谢大家谢谢大家来参加我们的赛事