导语 | 通过 WebAssembly,腾讯云 Serverless 让开发者只写几行代码,就能在生产环境部署 TensorFlow 模型。Serverless 让开发者不用另起服务器,同时也比 AI SaaS 服务更易定制化,达到提高开发效率与业务灵活扩展的效果。本文由 Second State CEO Michael Yuan 在 Techo TVP 开发者峰会 ServerlessDays China 2021上的演讲《在腾讯云 Serverless 上部署AI推理函数》整理而成,向大家分享他的见解。
点击可观看精彩演讲视频
一、 Serverless的未来在哪里?
去年在美国疫情特别严重的时候,我在家看 ServerlessDays China 的直播,了解到腾讯云在这个领域做了很多事。那时我在做浏览器之外的 WebAssembly,有种拿着锤子找钉子的感觉——就是一直在找应用场景。看完 ServerlessDays China 后,觉得把 WebAssembly 用在公有云、边缘云上的函数服务,特别有价值。于是就有了后来我们和腾讯云 Serverless 的合作,也是今天我的分享背景。我们专门定制了一个口罩“Make Serverless Great Again”,Serverless 的作用是什么?是让服务端编程又变得伟大起来。我们一直做服务端编程,多年来大家都觉得太复杂,但我觉得 Serverless 终于让它变得 sexy again 或者是 great again。
我今天分享的主题是“在腾讯云 Serverless 上面部署 AI 推理函数”。
顺便介绍一下,我们的开源项目叫做 WasmEdge。下面是去年 Datadog 做的 AWS Serverless 的调查,大家都在用什么语言对 Serverless Function 进行编程?结果是绝大多数人用 Java和Python 这种所谓比较重的、运营起来比较复杂的语言。
更有意思的是,有一半的 Serverless Function 在 800 毫秒以内执行完毕,也就是 0.8 秒执行完毕了。但我看这个图的想法是,god!有一半的 Serverless 都在 0.8 秒执行不完。如果我们考虑一些互联网的场景、实时的场景,比如一个应用有前端、后端,后端是用 Serverless 做的,如果每个函数执行0.8秒,这个应用基本很难被用起来。如果要是有10个函数,每一个执行时间就要 0.8 秒,一两秒才能给用户respond,对于大部分用户来说是不可接受的。所以得出一个结论,今天最常见的 Serverless 函数用例是在一个繁重的技术栈上运行一个简单的函数。
其实 Serverless 干的事情特别简单,把message queue里的 A 搬到 B,或者文件存储里面的文件从 A 搬到B。但在公有云的环境里没有很好的方法解决。所以,就用一个非常复杂的办法,比如用Java或Python来干这个事,因为别人已经提供很多的framework。干服务端的人知道这个事叫做“胶水代码”,今天公有云里面,大量的 Serverless function 就是用来做这个的。一个非常简单的函数,用了一个非常复杂的技术栈,只办一件非常简单的事。我们觉得FaaS 或者 Serverless function 真正要有未来,一定得要用到在服务端里面最常见的场景——用后端服务前端。
二、Jamstack revolution
先看一下,现在前端在流行什么?
现在前端可能最流行的 buzzword 叫做 Jamstack:JavaScript, API and Markup。核心原理是预渲染与解耦。传统的Web application有多年历史,从Java Server开始,我们需要从数据库开始到中间件,然后中间件上面产生用户需要的HTML和JavaScript UI,把这个UI通过网络送到浏览器里面,然后用户在浏览器里面与我进行交流。这个模式当然很好,但整个stack都是我的。所谓 Jamstack 的解耦,就是客户端和服务端是完全分开的。客户端是预渲染出来,用另外一种语言写我的客户端,用一种编译的方法把它编译成JavaScript和 HTML ,编译出来的内容是self-contain,因为它自己就能运行。可以把客户端放在本地运行,可以用 CDN 部署,甚至可以用区块链部署。因为不需要后端就可以运行起来。当它需要后端功能的时候,是用后端微服务或者 Serverless function 形成一段后端的函数,前后端进行交互。这是 Jamstack 的核心思想。
一个热门的 Jamstack——Next js,在GitHub上是6万多颗星,Hugo 和 Gatsby 有5万多颗星。当然还有我们特别熟悉的 Vue。有人称它们为生成网站工具,也有人称前端的编译器。这样的工具,现在找的话至少是以百计,这只是三个比较popular的而已。大家知道,前端的工具特别能给 engage developer,几乎所有的开发者都是从前端开始的。所以前端的开发者选什么,对后端开发者是有直接影响的。今天前端开发者很明显想要用 Jamstack 这种做法。国内也有做得很好的,比如DCloud的uni-app,已经在微信小程序里占了60%到70%的市场份额。基于Vue,前端生成了小程序,然后能够通过CDN解耦地部署,后端是用Serverless Function。我想说的是,现在特别多的人喜欢用这个做法。
但这对后端的 Serverless 函数提出了很高的要求。Serverless 函数主要是执行速度很慢,冷启动也很慢,这样造成的结果就是不能服务这样的前端。因为这样的前端最大的好处就是速度快,因为它是编译出来的,可以被放在 CDN 上运行,可以在离用户很近的地方运行。但是后端目前 Serverless Function 跟不上这个趋势的发展,因为今天的 Serverless Function 有冷启动,计算慢等各种各样的问题。
讲一个应用场景,前端有个程序,后端的 Serverless Function 要进行复杂的运算,比如进行AI推理。所有人都说应该用Python做 AI 推理,因为 Python 工具链最全,所有的文档都是用Python写的。可是大家知道,在Python下面,包括Google的TensorFlow都只是表面上 Python,下面都是C++,因为Python是很慢的语言。这是去年6月份Science上发表的文章,文章的题目也很有意思:There's plenty of room at the Top。40年前,Richard Feynman发表的文章叫做 There's plenty of room at the bottom,这篇文章一直以来被人说成是“摩尔定律”。摩尔定律讲的是软件的优化不重要,因为硬件每18个月就会翻番,今天运行的软件18个月之后就会运行得更快。当年比尔盖茨说过同样的话。有人抱怨Windows的软件写得太烂了,太慢了!有着各种各样的问题。比尔盖茨回应为什么要在软件的性能上花费很多时间?因为硬件18个月就会catch up,我要管的是用户体验,开发者体验。对于软件,我并不重视。在摩尔定律的时候,大家一直这么想:软件不重要。我也是在这个行业里面成长起来。但直到最近,摩尔定律这件事情不成立了。Apple的M1出来的时候,性能提高20%,现在硬件提高20%就可以上新闻了,以前硬件每18个月可是要翻番的。所以硬件的速度提高,现在已经基本停止了。
那我们还要从计算机行业里面挖出更多的生产力,就要用软件的方法来挖。所以,在这篇文章里,用Python实现矩阵运算或者张量运算,同时用 Java、C、C++硬件加速进行对比,如果bench mark是 1 的话,用C + 硬件加速能够实现6万多倍的增加。这些顶级的科学家写这篇文章的目的是说有很大的空间,大家现在需要考虑的是怎么才能有新的软件 framework,怎么才能在软件里用新的 framework 和方法把效率挖出来,而不是总等着硬件升级。
右上角的另一个研究是对不同的编程语言进行了一些常用的算法benchmark,主要对比时间和内存的消耗。大家可以看得很清楚,Java并不是特别慢,但内存消耗特别大,大家也可以理解,因为它有garbage collector机制。Python 内存消耗不大,但运行速度特别慢。C++不进行硬件加速的情况下,也是 Python的200倍左右。速度最快的是C、C++、 Rust。我们如果有计算密集的函数,想放在 Jamstack 的后端做Serverless function,不能用Python。因为用 Python 的话,今天是 0.8 秒,就会变成 80秒才能return。我知道腾讯云 Serverless 一个很厉害的功能 long running process,但还是为胶水代码设计的,并不是为一个用户等着Serverless function去反应设计的,这是为什么不用Python 的原因。
为什么不直接用Native C code?因为在 Serverless 下面就是容器,可以运行Linux,为什么不直接用C、C++写?比如做 AI 推理,为什么不直接用C、C++调用TensorFlow的C库。当然这是可以的。不过,这其中有几个问题。回到当年我们为什么用Java的原因。我的第一家公司 Jboss,是第一个做开源的Java server的。JBoss 在 2004年的时候卖了4亿美金。我们当年把Java用在Server side的时候,是因为我们不懂。那个时候我刚物理博士毕业,CEO Marc Fleury 是法国伞兵,在MIT学物理博士,毕业后找不到工作,于是就有了 Jboss 这个项目。我们不懂Server side上要不要用 Java。所有懂行的人都告诉我们,把Java放到Server side是个很傻的想法。Server side对性能要求高,应该用C++写apache extension,appache extension能够加载动态库,所以要用C、C++写,这是只是其一。其二,如果不要性能的话,就应该用curl写。Java 明显是为客户端设计,Write once, run everywhere。在服务端我已经知道我的机器是什么,为什么还需要 call platform 的东西?但是最后Java成功了,因为前端的开发者愿意用。
这个行业之所以不停在造轮子,就是因为行业不停有新人进来,新人都是从前端开始的。这些新人在前端学了Java,跑到后端来说,你们干的东西太复杂了,我不懂你们为什么这么干,我要重新干,重新用Java搞一遍,这就是我们当年的想法。我们干的这件事的10年之后发生什么事,发生了 JavaScript 从前端变到了后端,就轮到我们跟当年 Node.js 的人说,JavaScript是单线程的东西,怎么可能用到后端呢。每一轮都会这个想法。
长话短说,回到这个时代。Serverless 也是有container的,也是有native的运行环境,为什么不用C、C++写?第一是太困难。第二,很重要的原因是腾讯云的 Serverless 可能是一个比较uniform的环境,但是今天问下不是腾讯的同学们,你们知道腾讯云的 Serverless 里面Docker 写的是第几版的 centOS 吗?大部分人不知道具体的细节,因为用 Serverless 就是不想去关心这个事。这就造成了,写一段代码能够在所有目标环境中运行,这件事情又变得重要起来。这有的时候重要,有的时候不重要,取决于行业发展阶段。行业发展到 Serverless,已经不知道下面运行的 container 是什么,以及这个container里面的操作系统被云服务商进行哪些改动,libc进行了什么改动,现在我们已经不知道了。所以又需要一个中间层,用native写这个代码也不是很靠谱的主意,虽然它能够写出性能很好的东西。
我们当时拿着锤子找钉子,我们做 WebAssembly,而且写出来了高性能的 WebAssembly 虚拟机,觉得自己是搞 Rust 的大拿,一定要在云计算里面找到场景。尤其是Docker的创始人已经说了云计算的未来就是 WebAssembly,那一定要找到这条路。
三、 Rust + WebAssembly
所以,我们找到一条路, Rust + WebAssembly,特别像当年的Java加JVM,一个是语言,另一个是runtime。当然,结构已经发生很大的变化, 编译器现在变得越来越强大,我们刚才讲 Jamstack 就是前端的编译器, Rust 是一个语言的编译器,他的编译也很强大。Rust 这个语言大家一开始可能都觉得很难用,但是 Rust 的学习过程非常直接的。无论你做错什么,编译器都会告诉你,就像一个很好的老师,会不停地告诉你,哪个地方错了,应该怎么改。所以, Rust 是一个内存安全的语言,现在很多大厂也在用。而 WebAssembly 是一个非常轻量机的虚拟机,不做内存管理,只做隔离。所以造成了memory footprint很小,而且运行速度很快,提供了安全性和可移植性,这在 Serverless 的背景下是很重要的。
我们最后的技术方案是 Rust +WebAssembly,也是正在发展的社区。投资人问,要做开发者的生意,为什么不去搞JS、Python或者Java?那里人最多。我说我多年以前就是搞Java的,2005年第一次选Java Champion的时候我就是其中之一。但是今天要问一个开发者为什么用Java?这个开发者一定告诉你:是因为我老板让我用Java,我没有什么想法。但碰见一个 Rust 开发者,你要问他为什么用 Rust 。这句话还没有问出来,开发者早就问你,为什么你的软件不用 Rust 重新写?
我们去年12月份在深圳办中国第一次 Rust 大会,好多人是自费来的,这里面好多是学生。这个行业让我看到了当年Java的激动,就是大家自己花钱也要跟其他人说,你们的东西一定要用 Rust 重写,因为这个语言好。但我并没有看到Java、JS有这样的社区,这也是我们想做这件事的原因。
最关键的点,我们写了一个开源项目,WasmEdge,WebAssembly on the edge,目前是CNCF的沙箱项目。我们想做在服务端很好用,或者说在边缘端很好用的 WebAssembly runtime。我们在同行评议的杂志 IEEE Software 上发表了一篇文章,是跟大学一起合作的,我们比较了市场上所有比较前沿的 WebAssembly 项目的性能,至少在浏览器之外,我们的性能是最好的。这是为什么呢?因为我们用AOT,相比之下性能更强。
如果我想要把 WebAssembly 从浏览器变到服务端,要做些什么工作?一定需要在这里面进行某种改动,才能够实现。当年Java做了很多改动,刚放到服务端的时候什么都不能用,所以就出了JNI。今天 WebAssembly 在走一模一样的路,没有 API,没有 ecosystem,就搞个Native API。正好它又和下面的操作系统结合比较紧,在 Rust API 能够很好反映出来,因为它跟下面操作系统的语言,跟C++是一样的。我们通过 WasmEdge,通过CNCF,在WebAssembly 里面做了很多扩展,这些扩展基本上都是为了在服务端或者云端能够运行WebAssembly,包括进行 TensorFlow 的扩展、能够直接访问 TensorFlow 的 C 库以及TensorFlow下的硬件加速、存储的拓展、区块链的扩展等等。WebAssembly 今天在不同场景里有非常广泛的应用,我们都做了 API 的扩展。
我们来看下代码,这是用 Rust 写的 Serverless function。输入是一串二进字码,表达的是一个图片,输出的是一个字符串。所以这个 Rust 函数要做的事是用 AI 模型对图片进行推理识别,然后输出结果。
首先图片进来,要变成 TensorFlow model 需要的大小:192×192。因为输入应该是个张量,所以把里面的pixel重新arrange一下,变成张量需要的格式。
然后读取模型的数据,这里用的模型是see food(检查图像里的食物是什么,如果这个加上食物卡路里,那就是很有用的应用)。
当然还要加载一些跟这个模型有关的数据,比如label map,这是一个物体的list。因为输出的tensor全部是数字,把数字对应到训练集里物体的名字,比如一是猫,二是狗,三是汽车。然后再调用我们写的 Rust SDK,在SDK里把图像变成输入,从模型里找到output tensor,就是最有可能的 label 分别是什么。是这样一组数组:猫有50%的几率,狗有20%的几率。
接着,就进行推理了。推理之后,再用 Rust 函数把推理出的结果重新整理一遍,找出排名前几的概率分别是多少,最后把map的字符串输出。整个函数很简单。
如果用 JS,不做任何优化,一幅比较大的图需要要运行一分钟以上才能够结束。如果用 JIT 的 TensorFlow Lite ,需要几秒时间,就是在线等,勉强能接受。但如果用 Rust 和 WebAssembly 在腾讯云上,不用 GPU 加速,一秒钟能跑10—20幅。基本上简单的视频都可以做了。我们现在已经有合作的公司,使用腾讯云在短视频里识别人或者物品,这是一家电商公司,去识别视频里有多少人提包、这个包是什么样的,然后进行高性能的 AI 推理。这都是用 Rust 能够完成的功能。
其实真正的AI推理只有两行,其他用 Rust 写的东西都是预处理和后处理。AI 的95%工作都是在准备数据,结果出来后,把结果变成可读的形式。这种代码以前都是 Python 写的,但变成 Rust 和 WebAssembly 后,可以提速100倍以上。
我们的代码是开源的,有个网站,大家可以体验一下。在腾讯云 Serverless 已经有Docker的情况下为什么还要加一个容器 WebAssembly?主要想把 Rust 语言和TensorFlow相结合,能提高开发者效率。
四、WasmEdge 作为 Docker 的替代
最后,想讲一下,WasmEdge 作为Docker的替代。我们能不能有一天不用Docker了,直接用 WebAssembly?
Serverless Container 有三个层级:
1. Hypervisor Vm or MicroVMs(例如 AWS Firecracker,用 Rust 写的)。公有云上面需要有比较强的隔离,MicroVM 对 Serverless 环境进行隔离,这是最慢的做法,也是最安全的做法。
2. 容器应用(例如Docker)。但一般的公有云不会简单用Docker,比如谷歌云里边也是用Docker,但在Docker下面又再加了一层,把Docker的隔离安全性能提高。这种情况下,用Docker其实性能损失也是比较大的,但没有MicroVM 大。
3. 高级语言虚拟机(例如Jvm、Ruby/Python运行环境、V8、WebAssembly)。高级语言的虚拟机如果有内存管理,其实成本很高,不见得比Docker快多少。所以,WebAssembly 也许在未来是一个能够直接取代Docker的运行环境。WebAssembly 可以直接在process里起,也可以直接在thread里起。然后用inter process,几个机器之间也能够communicate。
来看 WebAssembly 与Docker的对比。最下面是冷启动的对比。WebAssembly 的冷启动是蓝颜色柱状条,大家能看见它是因为我乘以了50,50倍的慢动作显示在图片上,大家可以看出这个速度差异大概有好几百倍。WebAssembly 的启动速度根本看不见,很快;用Docker的话,经常情况下时间更长。启动时间的话,WebAssembly 与Docker有很大的区别。
WebAssembly 的好处主要是轻,软件在上面其实有很多置放可以被挤掉。轻量级跟性能有关,它最初是为浏览器设计的。另外是高性能的、可移植的。
回到第一点,安全。很多人认为 WebAssembly 的时间不长,所以安全性必然不好,我不这么认为。因为 WebAssembly 有两个非常大的优势。其一 capability based security 。因为它是一个新设计的虚拟环境,可以有新的安全模式。以前Linux下的安全模型都是用户有什么权限,东西就有什么权限。但是 WebAssembly 可以在启动的时候指定有什么权限,可以指定一系列的权限 所以,它有一整套自己的安全机制。
其二,WebAssembly 在区块链的应用场景里,出了很多骗子,但是区块链行业花大价钱做资产安全。这里面的代码、智能合约如果写得不好,就会面临钱被偷掉的问题。所以,区块链行业里大量的人用大量的时间做了一件事情叫做“形式化验证”——用数学的方法去证明一段程序是正确的。这个工作目前在 WebAssembly 里面做得最多,因为 WebAssembly 写出来的智能合约最多。包括 WebAssembly 虚拟机本身和 WebAssembly 虚拟机里面写出来的程序也可以进行虚拟化验证。
这也是为什么比如我们公司今天想把 WebAssembly 做到智能汽车中。进行过形式化验证的系统,比不进行形式化验证的系统安全级别要高很多。Wasm 在市场上的时间和踩到的坑,肯定没有Docker多,但是可以说它生来就是一个比较安全的技术。
最后介绍一下我们的 WasmEdge 开源项目到底在干什么?我们符合 WebAssembly 标准、支持所有提议的扩展、高性能、支持 AI 和其他的自定义扩展。标准不是靠二三十个博士放在五星酒店里制定出来的。这样制定出来的标准有Java EE、1.0 Java EE 2.0,但所有社区里面都怨声载道,太复杂。我们认为标准是在实战中打出来的。很多程序员不停实验,最后有人实验出来大家都接受的方法。所以,我们希望 WasmEdge 是在社区里面能够起到这样的作用,我们现在已经支持很多扩展。虽然大部分(扩展)会死掉,但是一小部分会被社区接受,成为 WebAssembly 这个行业里面的事实标准。
我们支持旧版的Linux和RTOS、支持OCI和K8s生态,比如可以 Wasm file 放到Docker image 里,用Docker工具起 Wasm 程序,可以让K8s调度 WasmEdge。我们在积极地探索 WasmEdge 跟其他生态的整合与扩展。
非常感谢大家的时间,希望跟大家多交流,谢谢!
讲师简介
Michael Yuan
WasmEdge 的创始人和核心开发者
WasmEdge 的创始人和核心开发者。WasmEdge 是一个由 CNCF 托管的开源 WebAssembly 虚拟机。其主要应用于边缘计算、Service Mesh 和嵌入式函数。Michael 撰写过6 本软件工程书籍,也是长期的开源贡献者。Michael 同时也是 Second State 的联合创始人。Second State 是一家开源基础软件初创公司,致力于商业化可持续地支持 WebAssembly 和 Rust 生态系统中的企业应用。
推荐阅读
如何优雅地把握 Serverless 和 Serverful 的平衡点?
Function Mesh:Serverless 在消息与流数据场景下的火花
???? 错过了直播懊悔不已?本次峰会所有嘉宾的演讲视频回顾上线啦,点击「阅读原文」即可观看~
???? 看视频不过瘾还想要干货PPT?关注本公众号,在后台回复关键词「serverless」即可获取!