eBay实战WebAssembly:50倍性能提升

eBay实战WebAssembly:50倍性能提升


Ending定律:一切可编译为WebAssembly的,终将会被编译WebAssembly。


原文:https://www.ebayinc.com/stories/blogs/tech/webassembly-at-ebay-a-real-world-use-case/

WebAssembly完全是含着金汤勺出生,2018年发布1.0正式版本更是彻底引爆了整个软件行业——这是要彻底革大家的命啊!被大家期望主要的原因还是JS是烂泥扶不上墙(听说V8已经对JS放弃治疗,改玩各种语法糖的方向),各种性能低下的JS库都指望WebAssembly来续命呢。eBay当然也是白金钻石粉丝之一。

eBay的码农们整天兴奋的失眠,只能靠刷WebAssembly各种八卦来划水摸鱼。终于WebAssembly 1.0的发布让eBay的码农们彻底高潮了——放开手就是干,俗话就是壳,干就完了、干就完了……

但是遇到的第一个技术问题是没有现成的代码和方案可抄啊!虽然开源社区中已经有很多和WebAssembly相关的新奇小玩意,但是没有完整淘宝店店开源实现,怎么抄呢?同时,还有很多JS遗老遗少强烈要求继续使用JavaScript,否则后果自负。在eBay有个传统,每当政治斗争变得胶着状态的时候,我们都会找一个冠冕堂皇的理由:能给我们的客户带来什么价值?必须提前找到一个甩锅的理由,否则如果最后搞崩了都不知道怎么死的。再次强调:用户上帝、是亲爹,用户的体验是第一位的。找到了背锅侠,下面就是编故事了,这难不倒eBay的天才码农们。

条形码扫描器

eBay的iOS和Android都内置条形码扫描器以我们的客户最好的体验。条形码扫描器可以扫描各种数据,简化输入体验。这虽然是一个纯粹的功能,但是在图像处理过程之中需要进行大量的纯运算。因此在iOS和Android应用中,都采用原生的C++库实现图像扫描和解码功能。

条形码扫描器为卖家提供了直观无缝的购物体验。但是比较悲催的是Web用户,他们没有此项特权(实在是因为JS的运算力弱爆了)。Web购物每次需要苦逼地手工输入诸多信息,这让eBay的码农充满了内疚,没有给Web用户最完美的体验,这绝对是在犯罪。

故事的另一个版本:Web版条形码扫描器

实际上我们之前认真的考虑过提供Web版本的条形码扫描器。而且我们曾经给予JS版本的BarcodeReader 条形码扫描器实现了一个版本。这些是2年前的故事了。当时最大的问题是它只在20%的时间能凑活工作,剩下的时间则非常缓慢,已经彻底超过了客户能够忍受的极限。这就是所谓的JS高性能,因为它只能依赖JIT提前猜测热点代码并提前进行编译为机器码优化。JS引擎虽然内置了很多查表的手段来选择哪些需要JIT,但是它始终无法很好预测表格之外的热点代码。Web平台和手机平台巨大的贫富差距会让Web用户彻底愤怒,因为当时我们的明智地禁用了Web版本的扫描器功能。随着这2年Web平台的巨大发展,我们的码农又要开始搞事了:美其名曰,为客户提供一致的条码扫描器体验?

还有一个9号方案:就是等待Shape Detection API成熟。这个提案可以让Web应用使用很多本地图像处理的特性,条形码检测就是其中一个功能。但是这个玩意还太初级,离最终可用估计至少还有十万八千里。而且每个浏览器这个提案API支持差异又是一个巨大的坑。我们码农对跳这种坑是比较谨慎的,因此需要换一个方向忽悠。

这正好是WebAssembly雪中送炭的地方。如果以WebAssembly方式提供条形码扫描器,自然可以做到不同平台一致的体验。而且WebAssembly的设计目标之一就是性能,最最重要的是我们的C++库刚好可以直接编译到WebAssembly平台。面对如此的康庄大道还犹豫什么呢?

架构

得益于我们代码的优雅设计,实现一个WebAssembly非常简单。

  • 使用Emscripten编译C++版本的库,它不仅仅生成wasm文件,同时还会生成傻瓜时的JS胶水代码。

  • 从主线程创建一个WebWorker线程。在Worker线程导入并执行生成的JS胶水代码,最终会执行wasm中的代码。

  • 主线程会将相机拍到的数据流异步发送给Worker线程。Worker线程通过胶水JS代码调用wasm中对应的函数。最终结果再返回给主线程,如果没有数据的话就返回一个空字符串。

  • 如果没有条形码,则重复上述检测操作。重复的时间可以通过配置调整。如果超过一定时间依然没有检测到条形码,则输出一个友好的提示。没有结果可能预示着用户无意触发了该功能,或者是条码解码器性能没有达标。

eBay实战WebAssembly:50倍性能提升

WebAssembly工作流

汇总

WebAssembly项目的第一步是搭建编译环境,而Emscripten则是C++代码的事实上的编译工具标准。下面的一个问题就是确定输出的目标平台环境。我们的前端码农使用的是Node.js环境,因此我们希望一个基于npm的构建流程。比较幸运的是刚好有一篇 “Emscripten and npm”文章给我们提供了参考。它是基于Docker环境适应Emscripten来编译,这样可以省去很多开发环境配置的文件。我们使用的是文章推荐的trzeci Docker镜像。当然,我们对C++代码稍作了一些调整,以便于适应WebAssembly平台。这样我们就轻松搞定了WebAssembly的编译流程。

速度是很快,但是跑偏了……

我们统计扫描器性能的一个指标是每秒钟处理的帧数。Wasm版本的API接收帧数据流,这样可以近乎实时处理相机的结果。这样循环不停检测,知道成功得到条码的数据。

在我们的测试中,WebAssembly版本性能可以飙到50FPS。但是只有60%的情况才会这样烧CPU,其它剩余的情况最终得到了检测失败的提示信息。作为对比,之前的JS版本性能只能达到可怜的1FPS,所以可以说WebAssembly的性能是JS的50倍!但是比较悲催的是,虽然快了50倍,但是有近一半的情况下依然无法在期望的时间内检查到结果。当然被我们黑的很惨的JavaScript偶尔确有出色的表现,某些情况甚至JS可以马上得到结果。一个粗暴的解决手段是继续增加检查的超时时间,但是这并没有真正解决实时性和成功率的问题。长征刚开始,我们还需要继续努力💪。

最初我们不明白为何C++版本还不如JS版本,并且快被这个结果搞奔溃了。经过海量的测试和DEBUG,最终发现相机的自动聚焦影响了检测结果。因为在原生的手机APP中,系统可以自动对焦相机,这样解码时的图像是比较清晰的。避免了模糊的图像情况,所以手机本地APP解码的时间比较稳定。

既然找到了导致解码时间不稳定的原因是相机聚焦问题导致的,那么我们自然希望尝试用不同的解码库来处理不同的焦点参数拍摄的图像。刚好开源的ZBar也可以实现条码解码功能,而且它对模糊的图像表现更好。因为我们已经配置好了编译环境,因此切换到ZBar的工作非常简单。经过测试发现ZBar性能大约在15FPS(比我们的C++库要慢),最重要的是它的成功率达到了80%。ZBar对于我们自己实现的C++库绝对是一大改进,但是依然没有做到100%扫描成功率。

虽然结果还没有彻底满意,但我们注意到了一些意想不到的事情。 在ZBar超时的情况下,我们自己的C++库通常能够非常快速地完成工作。 这种互补性绝对是一个意外之喜,因此我们又有了一个绝妙的改进思路。

赢者为王

机智如你,肯定已经想到了这个绝妙的改进思路。我们创建两个线程:一个用于ZBar,另一个用于自己实现的C++库。两个线程相互竞争赢者为王。第一个向主线程发送结果的线程获胜,同时终止所有其它线程。我们通过内部测试发现这个改进将成功率提高到了90%。虽然进步显著,但是依然没有达到100%。

然后有一个比较狂野大胆的建议是将JS库也放到赛道中,最终将有三个线程参与竞争。虽然我们开始不太相信JS库能够带来的收益,但是测试的成本很低。让人跌掉大牙的是三条线程相互竞争之后成功率居然提高到了接近100%!正如前文说到的,JS在某些情况下表现异常优异,正是这类情形弥补了短板。所以我们开玩笑说:即使JS再烂,也一定要押宝JS。下图是我们最终的框架图:

eBay实战WebAssembly:50倍性能提升

下图显示了一个高级抽象的流程图:

eBay实战WebAssembly:50倍性能提升

资源加载

为了快速加载主页面,我们没有马上启动条码扫描线程,而是通过异步的当时预取依赖的资源。使用XMLHttpRequest在页面的加载事件之后预取和缓存WebAssembly和JS相关的库。这些代码被获取之后并不会马上执行,这样可以尽量避免影响主线程的工作。只有当用户点击条形码图标时才会执行,或者 如果用户在加载资产之前已经点击锅条形码图标,会根据需要加载它们并立即执行。 条形码事件处理程序作为Worker线程初始化代码一部分,它们的代码比较小。

最终效果

经过全面内部测试,该功能终于进行到A/B测试环节。下面是效果图:

eBay实战WebAssembly:50倍性能提升

AB测试一个衡量的标准是订单完成速率。它表示从订单开始到最终提交完成的速率。是订单完成速率可以提升用户的购买体验,完成更多的购物订单。经过几周的测试效果比较明显。简言之,在启用条形码扫描器的情况下,订单完成的效率提高了30%。

eBay实战WebAssembly:50倍性能提升

同时我们也增加了性能分析,主要是观察不同类型的线程的表现差异。结果和预期差不多:ZBar占成功扫描的53%,其次是自定义C++占34%,最后是JS版占13%。

eBay实战WebAssembly:50倍性能提升

结论

整个WebAssembly之旅是一个很棒的学习经历。码农们对新技术总是非常兴奋,必须尝试一波。如果测试新技术同时可以改善客户体验将是一个完美的事情。我们的观点是新技术日新月异,但是只有少数的技术产生了真正的价值,而WebAssembly就是其中之一。

目前我们在考虑是否要将条形码扫描仪扩展到移动网络,这将允许买家扫描物品进行搜索和购买。 同时我们还将继续研究Shape Detection API和其他浏览器内摄像头功能来增强此功能。最后,我们很高兴WebAssembly在eBay找到了正确的使用场景。

特别感谢Surma Das和Lin Clark在WebAssembly方面的众多文章。 它确实帮助我们解决了诸多问题。

译注:《WebAssembly标准入门》中文版已经上市,赶紧上车吧!


eBay实战WebAssembly:50倍性能提升

原创文章,作者:酷毙编辑,如若转载,请注明出处:https://www.dailybtc.cn/ebay%e5%ae%9e%e6%88%98webassembly%ef%bc%9a50%e5%80%8d%e6%80%a7%e8%83%bd%e6%8f%90%e5%8d%87/

发表评论

电子邮件地址不会被公开。 必填项已用*标注

联系我们

在线咨询:点击这里给我发消息

邮件:[email protected]

工作时间:周一至周五,9:30-18:30,节假日休息

QR code