Weex 在双十一会场的大规模应用

jiedengye 8年前
   <h3><strong>1.前言</strong></h3>    <p>Native 开发的诸多亮点中,流畅体验和系统调用是最多被提及的。流畅体验体现在页面滚动/动画的流畅性,背后是更好的内存管理和更接近原生的性能;同时又是Web 的痛点:资源首次下载、长页面内存溢出和滚动性能、动画性能、传统 web 性能(如JS执行效率)。Native 有丰富的系统调用能力,而 Web 痛点在于:W3C标准太慢,有限的设备访问能力,API 兼容性问题较严重,如 Geolocation 在 Android Webview 中可用性很差。</p>    <p>Web 开发同样有诸多亮点,其中最耀眼的当属发布能力和规模协作。NativeApp 商店审核周期长(尤指 iOS);应用更新周期长,iOS 稍快大概能达到一周更新率 60%-80%,Android 同样的更新率要2周甚至更长。而Web 在合适的缓存机制下一分钟可达到 99%+。浏览器内核 webkit 提供了相对一致的底层运行环境,html/js/css 控制页面的结构/行为/样式,uri连接不同的页面,有了这些基础设施,大规模的业务复用和人与人的分工协作变得相对轻松。</p>    <p>同时今天阿里诸多客户端已经面临包大小接近临界值,大促活动页面(H5)体验较差等一系列问题。结合Native 和 Web 技术亮点,同时又能解决阿里遇到的业务问题,这就是 Weex 诞生的客观环境。</p>    <p>2016.11.11,在 1754 张双11会场页面中(统计了天猫和淘宝),Weex页面数为 1747 占比 <strong> <em> 99.6% </em> </strong> 。手 淘 iOS/Android 分别有 83.5%/78.3% 版本(UV)启用了Weex 会场,手猫 iOS/Android 分别为 91.7%/87.9% 版本(UV)。Weex 覆盖了包括主会场、分会场、分分会场、人群会场 等在内几乎所有的双11会场业务。</p>    <p>在这样的应用规模下,工作和目标是:</p>    <ol>     <li> <p>业务支撑,支撑住双11需求,这是最基本的要求,详见下文“业务支撑”一节</p> </li>     <li> <p>稳定性保障,Weex 引发的问题第一时间响应并处理,不留到双11当天,详见下文“稳定性数据”一节</p> </li>     <li> <p>秒开实战,稳定当先力争高性能,双11正式主会场秒开率冲到 97%,所有会场秒开率冲到 93%,详见下文“秒开数据”</p> </li>    </ol>    <p>2016 双11会场的感受可查看原始录屏文件: | | | | 。录屏时主会场已经是 预加载 版本,其中WIFI 和 4G 效果接近,2G 效果取决于数据的网络请求速度(录屏时数据请求约3.9s),无网络情况下打底数据来自前一次成功请求。流畅性可查看 ,左起为 H5、iOS Weex、Android Weex。</p>    <p>展开 Weex 双11细分目标:</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/1c0db96f9e5bc2873b548d1ebd3ebe54.jpg"></p>    <p style="text-align: center;">图 - Weex 双11细分目标</p>    <h3><strong>2.业务支撑</strong></h3>    <p>支撑住双11的业务需求,是 Weex 必须要迈过的坎。</p>    <p>双11的会场结构大致为:会场框架(框架 + 主会场、全部会场、必抢、清单、我的双11)、分会场、其他会场(分分会场、人群会场等)。</p>    <p>2.1 <strong> 会场框架 </strong></p>    <p>Weex 支撑双11业务首要解决的是会场框架及其交互形式:</p>    <p>1. 交互主流程:</p>    <p>1.非 push 方式(框架Tab 切换):主会场 - 全部会场- 必抢 - 清单 - 我的双11</p>    <p>2.push 方式:主会场 - 分会场- 主会场</p>    <p>2. iOS 考虑到内存开销,需严控打开的主分会场weex页面,定为 n 级可配,默认为5;同时 iOS 会场框架为单实例,也是出于内存的考虑;Android 连续打开 30 级以上 Weex 页面,未见内存异常增长,无需特殊方案</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/2d282ed20020f4b7e7fcb045130eb875.jpg">   </p>    <p style="text-align: center;">图 - 会场框架交互</p>    <p>Weex 会场框架很好支撑住了双11的复杂交互需求并提供了更好的内存管理。除了会场框架,更多的Component 和 Module 支撑住了各色各样的双11需求,这里仅列出几个代表:</p>    <p>1. List 组件是几乎所有会场页面的标配,流畅的滚动帧率、高性能的内存复用机制和渲染机制是页面流畅体验的重要基础</p>    <p>2. Animation 尽管是实验版需求,却支撑住了会场的垂直弹幕、坑位显隐等动画效果,动画效果细腻</p>    <p>3. Weex 点播/直播组件 和 全景图组件支撑住了更为垂直个性化的业务需求</p>    <p>2.2 <strong> 组织结构 </strong></p>    <p>上节内容也可以看出,参与 Weex 双11会场涉及多个团队和平台系统:</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/cf6930d07b752362982f645a924141fc.jpg"></p>    <p style="text-align: center;">图 - Weex 双11中组织结构</p>    <ol>     <li> <p>天猫业务:通过斑马(活动页面搭建和发布平台)发布会场页面</p> </li>     <li> <p>淘宝业务:通过斑马和 AWP (产品页面发布平台)发布会场页面,上层DSL 使用 Rx(即将开源)</p> </li>     <li> <p>预加载:提前将会场js-bundle 下载到客户端,客户端访问 Weex 会场时网络 IO 被拦截到本地文件  IO,从而极大加快了网络加载速度,预加载是这次秒开实战的抓手(注:最核心的工作)</p> </li>     <li> <p>手淘、手猫客户端,Weex 是客户端的一部分,客户端中其实是 Weex、Native、H5并存的</p> </li>     <li> <p>Weex SDK、业务模块:Weex容器和基础的 Components、Modules,业务模块包括直播/点播组件、全景图组件</p> </li>    </ol>    <p>以上也仅涉及到客户端和发布端,背后还有无数的业务后台系统,就不一一列出了。</p>    <p>将 Weex 架构自上而下地展开:</p>    <ol>     <li> <p>Business,Weex 业务层,Weex 双11主战场是手淘和手猫,此外还有大量客户端已经启用或接入了Weex</p> </li>     <li> <p>Middleware,Weex 中间件层,包括为 Weex 页面提供发布(斑马、AWP)、预加载(AWP)、客户端接入支持(AliWeex)、组件库(SUI)、游戏引擎、图表库等模块;其中斑马、AWP、预加载都直接参与了双11</p> </li>     <li> <p>Tool,工具层</p> </li>    </ol>    <p>1 . DevTools , 界面和交互复用了 Webkit Devtools , 支持 elements 、netwo rk、断点、console 等</p>    <p>2. Playground ,方便开发者调试Weex 页面,同时也是 Weex example 的聚集地</p>    <p>3. Cli ,Weex 命令行工具集</p>    <p>4. 目前仍在建设更多的工具,如 weex-pack 支持一键打包成 App</p>    <p>4. DSL</p>    <p>1. JS Framework,Weex 最初的 DSL 是基于 Vuejs 1.0 语法子集;目前在社区中在推进基于Vuejs 2.0 的版本</p>    <p>2. Rx,基于reactjs 语法的 Weex DSL</p>    <p>5. Engine,渲染引擎,从架构设计上,Android/iOS/H5 RenderEngine 是相互独立和平等地位的渲染端,这是保持三端一致的基础,当然在协议实现层面需要更多的设计、质量保证</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/9771cd9d71acfd8b502b570cadd12f70.jpg"></p>    <p style="text-align:center">图 - Weex 架构</p>    <p>以上就是 Weex 在双11中的架构和业务支撑的范围了。</p>    <h2><strong>3.稳定性保障</strong></h2>    <p>Weex 的首要挑战就是稳定性,或者说保障 Weex 会场最大限度不降级。</p>    <p>3.1 iOS JSCore <strong> 内存治理 </strong> <strong>   </strong></p>    <p>8月初(同期双11启动)奥运大促时,手淘 iPhone 中反复进出会场20+ (手猫 15+),会出现 crash 。奥运大促当天,手淘 iOS 1.59% crash 次数来自该问题( top 6 ),手猫 1.94%( top 8 )。发现问题的当天成立了攻坚小组,从 JS业务代码、 JSFM (框架)、 iOS 渲染、 iOS JSCore 几个方向同时排查,一周内各方向排查到逐步收敛到:根本原因是 Weex 页面实例被全局持有(weex runtime 只有一份),进而导致页面退出时内存不被释放,反复进出直至内存爆掉。因而任何可能导致页面实例被全局持有的因素都会触发这个问题:</p>    <ol>     <li> <p>业务代码中的问题,意外导致的,给出 Lint 工具扫描业务代码,引入了“全局污染治理”(见下一节)</p> </li>     <li> <p>JSFM 框架中的问题,如在 destroyInstance 时清理 commonModules 和所有dependency target;iOS7下的 Set Polyfill 内存飙升问题</p> </li>     <li> <p>iOS 中的问题,通过下发配置控制 VC Push层级控制;内存警告时的非当前实例销毁策略,加入开关控制;iOS 9.x JSCore 原生 Promise 和 Polyfill 并存时的内存问题</p> </li>    </ol>    <p>除了建立攻坚团队推进解决该问题,也在造势期前就展开双11会场压测,反复验证该问题,自双11造势期会场开测之后,该问题未再出现。</p>    <p>3.2 <strong> 全局污染治理 </strong></p>    <p>在治理 JSCore 内存的过程中,逐步意识到对全局变量管控的必要性。Weex 中多个页面共用 1 个 runtime,单个页面如果写法不规范不仅可能导致内存泄露,更有可能污染全局环境,进而导致所有Weex 页面无法正常工作。全局污染治理的核心抓手:</p>    <ol>     <li> <p>严格模式,即 `use strict`,使用严格模式可以将较多常见的JS 陷阱转化为错误,如:无法再意外创建全局变量、将拼写错转成异常、限制了 eval 的能力 等</p> </li>     <li> <p>冰冻对象,利用 ES5 的 `Object.freeze()`,将 Weex 核心对象和 JS 原生对象“冰冻”住。尝试修改被“冰冻”的对象会抛出错误,一旦“冰冻”无法“解冻”。</p> </li>    </ol>    <p>3.3 <strong> 跨端依赖梳理 </strong></p>    <p>Weex 通过 Adapter 来适配不同客户端的具体实现,诸多通用库,如:网络库、图片库、API库、 H5 容器 (Web 组件)、埋点库、 配置库 等在不同客户端上版本不一致,因此导致的线上问题将会成为双11会场的隐患。为此展开的依赖梳理和同步机制是双11稳定性的保障之一。这件事情可能将会长期出现在Weex 问题清单之中,如何做到上层 Weex SDK</p>    <p>3.4 会场压测</p>    <p>* 压测场景</p>    <p>1. 5 个 200 坑位的普通会场页面,1 全景图会场页面,1 UT Expose 压测页面,1 直播会场页面</p>    <p>2. 页面中提供链接,能够按顺序进行 push 跳转</p>    <p>* 压测方案 </p>    <p>1. 主链路(首页->店铺->详情->购物车)做一遍操作,让内存缓存占满,记下内存值M0</p>    <p>2. 进入 Weex 页面,滑动到底部,滑动到顶部,记下 M1;点击跳转按钮,跳转到下一个页面</p>    <p>3. 重复步骤 2,让所有的页面进行压栈;全景图->p1p2p3p4->直播->p1p2p3p4->UT</p>    <p>* <strong>压测结果:</strong> iOS 通过,Android 通过</p>    <p>1. 测试过程手淘手猫均未出现因为压栈导致的 Crash,稳定性可以保证;</p>    <p>2. Android低端机压栈过多会导致体验较差,之后也会引入类似 iOS VC 层级控制;</p>    <p>压测在造势期会场测试阶段展开,在超出真实会场压力的情况下(真实会场150坑位上限),尽可能提前嗅探出潜在的iOS JSCore 内存问题、iOS/Android异常闪退等细节问题。</p>    <p>3.5 <strong> 稳定性数据 </strong></p>    <p>2016.11.11,Weex 在手淘中的 Crash 占比情况:</p>    <p>* iOS1.46%(TOP7)</p>    <p>* AndroidJava Crash 0.85%(TOP13)</p>    <p>* NativeCrash 1.72%(TOP8)</p>    <p>考虑到会场的业务量级,Weex 的稳定性仍然是不错的。注:单独计算的Weex Crash 率太小,参考价值不大。</p>    <h3><strong>4. 秒开实战</strong></h3>    <p><img src="https://simg.open-open.com/show/ad8f1bacaf4225fac5c0eef17879f458.png"></p>    <p>其中:加载时间指 Weex js-bundle 的加载时间(从网络下载或本地加载);首屏渲染时间指Weex 页面开始渲染到第 1 个元素bottom 超出首屏范围的时间。下文提到的“首屏网络时间”为加载时间与首屏渲染时间的和。</p>    <p>从双11结果看预加载大幅度提升加载时间,对秒开率的贡献尤其突出;但性能优化是个长期迭代的过程,回头来看优化的抓手是:预加载和首屏渲染优化。</p>    <p>4.1 <strong> 预加载 </strong></p>    <p>预加载解决了 1 个问题:</p>    <p>用户访问页面(H5/Weex)之前,将页面静态资源(HTML/JS/CSS/IMG...)打包提前下载到客户端;用户访问页面时,将网络IO 拦截并替换为本地文件 IO;从而实现加载性能的大幅度提升。</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/9c46c2c1b16c296118d95db7cd0a5226.png"> <img src="https://simg.open-open.com/show/57fe8f39a6b0c5082c53b6795e26e2dd.png"></p>    <p>启用预加载后加载时间的变化,粗算一下:手淘 iOS,走网络平均 296ms,走预加载 18ms,网络性能提升约 15 倍;手淘 Android,走网络平均是 696ms,走预加载是 54ms,网络性能提升约 12 倍,但绝对值更大,对Android 会场秒开贡献更为突出。</p>    <p>2015年预加载已经在双11 H5 会场中有较多应用,2016 年预加载升级为一项基础服务,不仅为WindVane 提供预加载能力,也成为Weex 秒开的最强外援。</p>    <p>此次双11会场共启用 30 个预加载包,总容量超过 20MB,业务需求相对稳定且流量较大的几个页面(会场框架+主会场等)是独立的包,保证了对整体秒开的贡献,其他分会场均分在剩余的包中。同时主要采用强制更新的策略,即新的资源包(服务端有新发布)未下载到本地就直接读取线上,可以保证业务的实时性。2016.11.11,双11会场中Android 走预加载占比为59.4%,iOS 为 62.5%,高于平均水平(但还可以更高)。</p>    <p>4.2 <strong> 首屏渲染优化 </strong></p>    <p>首屏渲染优化的目标就是尽力缩短首屏的渲染时间,为此在一系列的优化过程中,可以粗分为:DOM 解析优化、UI 渲染优化、分段懒加载。</p>    <p>4.2.1 DOM 解析优化</p>    <p>* Component append 属性定义了 `node` 和 `tree` 2 种渲染模式,`node` 就是逐个节点渲染,`tree` 就是整棵树一起渲染。直观的对比: node | tree 。</p>    <p>* `node` 模式,节点逐个从 js 提交到 native 的, native 侧有个 16ms 间隔的 layout 保证渲染的正确性,这是更接近于WebKit 的一种解析渲染模式。优势是每一个被解析完的节点都可以立刻显示,同时保证不会长时间阻塞主线程,劣势是可能会造成多次冗余 layout,拉低流畅性。</p>    <p>* `tree` 模式,整棵树(以当前节点为 root 的整棵树)从 js 提交到 native。优势是只需布局一次,渲染更高效;劣势是如果 tree 过大,就可能会阻塞主线程甚至阻塞渲染。</p>    <p>* `node` 和 `tree` 可以精细化地控制页面展示的逻辑和颗粒度,典型的实践为首屏以内按 tree 解析,首屏以外按 node 解析。</p>    <p>4.2 .2 UI 渲染优化</p>    <p>* List 组件在 native 分别对应 iOS UITableView 和 Android RecyclerView,这两种 View 构建了 App 的半壁江山,使用它们来封装 list 的好处:</p>    <p>* 只会渲染可见区域,减少首屏的渲染消耗</p>    <p>* 内存复用,所有滑动到不可见区域的 cell 都会被系统回收,用于渲染下一个 cell</p>    <p>* cell 之间天然互相隔离, 可以默认以 cell 维度划分并用 tree 的模式解析,提高渲染效率</p>    <p>* 拥有原生的交互体验,在 cell 上点击、左滑、右滑、移动排序等交互方式后续可以更方便地支持</p>    <p>* 想要达到 60FPS 的体验,一次主线程渲染必须少于 16ms。Weex 中一次渲染需要经过 6 个主要步骤(Build Tree、Compute Style、CSSLayout、Create View、Update Frame、Set View Props),所以必须在 16ms 内完成这 6 个步骤,现实是任何一步在主线程中都可能超过16ms,这块。</p>    <p>4.2 .3分段懒加载</p>    <p>* 除了底层的优化,业务上也通过分段懒加载进一步降低整体渲染时间,对首屏渲染有间接帮助(减少调度)</p>    <p>* 方案为:会场页面使用 List 进行布局,一个 cell 对应一个模块;页面启动默认加载 6 个模块(少数页面因为首屏模块过多因此特殊处理);默认往下滑到底触发loadmore 后再加载 5 个模块;若加载过程中遇到电梯则电梯以下模块全部加载</p>    <p>除了底层的保障,我们也坚持每天产出“性能优化建议”,推进业务性能优化,接下来会有更加方便的工具提供给业务方直接性能调优;如双11期间devtool 中增加了层级检测和告警,可以帮助排查深层级导致的 android 低端机 stackoverflow。</p>    <p>4.3 秒开数据</p>    <p>由于主会场流量占据了总流量的大部分,对其秒开率单列统计。2016.11.11数据为:</p>    <p><strong>主会场</strong></p>    <p>l   秒开率峰值(00:00):</p>    <p>整体 96.9%(278.8ms)</p>    <p>ios99.4% (146.4ms)</p>    <p>Android93.4%(411.1ms)</p>    <p>l   秒开率均值:</p>    <p>整体 94.4%(367.6ms)</p>    <p>ios99.0% ( 177.0ms )</p>    <p>Android 91.8% (473.3ms)</p>    <p>l   帧率( FPS ):</p>    <p>红米 Note1s 53 、小米 5s 58.5;</p>    <p>iPhone5c53.1 、</p>    <p>iPhone6p56.9 、</p>    <p>iPhone7 5 ,</p>    <p>帧率数据来自线下采集,见 视频 (左起为 H5、iOS Weex、Android Weex)。</p>    <p>所有会场</p>    <p>l   秒开率峰值(00:49):</p>    <p>整体 92.4%(490.7ms)</p>    <p>iOS97.4% (291.6ms)</p>    <p>Android87.5% (689.8ms)</p>    <p>l   秒开率均值:</p>    <p>整体 83.9%(651.9ms)</p>    <p>iOS94.5% ( 368.0ms )</p>    <p>Android 78.6%(797.4ms)</p>    <h3><strong>5.新的起点</strong></h3>    <p>Weex 技术委员会在十月中成立了,核心解决 Weex 开发过程中的标准化和协同问题。并于10.26进行了第一次会议,审议的 4 个话题(Input focus/blur、750px实现方案、weex analyze后续发展、标准化流程草案)经过充分讨论,均获得全员投票通过。</p>    <p>鬼道作为第一任组长,接下来半年带领各方推进 Weex 在集团和社区的深度建设,欢迎大家参与Weex 的共建之中。对于参与 Weex 的各方而言,最直接的影响就是:需要作为 Weex 官方推荐,向集团或(和)外部社区贡献的 Module、Component、工具、平台 等成果 需要通过 Weex 技术委员会检视标准性。要求在 方案设计出来后实现之前和(或) 实现出来后 这 2 个时间点向 Weex 技术委员会汇报标准性相关细节;这个要求是强制的,目的是保持 Weex 社区的标准化推进。如果你只是为局部业务开发定制化的Weex 扩展,不涉及标准性,并不会被要求到 Weex 技术委员会汇报。</p>    <p>Weex 任重道远:</p>    <ol>     <li> <p>Weex 不只是 Weex 容器,Weex 业务背后是发布、预加载、AB、线上监控、质量效能度量、数据埋点、业务开发技能转变/升级 等一系列行为的交织,如何减少业务从H5/Native 转向 Weex 时的“阵痛”,是接下来的攻坚重点</p> </li>     <li> <p>双11中遇到的典型案例或问题,会成为下一阶段的工作重点之一</p> </li>     <li> <p>仍有大量业务需求需要开发,为此我们已经启动了 Weex BigBang 项目,按照 WindVane  API 的调用频度和业务反馈情况,分批实现 30+ Weex Module/Component,包括常用的 schema 唤起支持、网络类型判断、geolocation、audio、cookie、大图预览、通讯录等</p> </li>     <li> <p>减少新客户端接入 Weex 的成本,目前在尝试的 AliWeex 项目会扩大应用范围并成为客户端接入的标配</p> </li>     <li> <p>跨客户端的底层依赖不同步问题会一直存在下去,需要更好的解法</p> </li>    </ol>    <p>不一一列举了,之后会有 Weex Roadmap 的讨论并且会及时公布出来,欢迎关注。</p>    <p>从“ Native 和 Web 融合 ”开始,先后经历的 Hybrid、React Native、WVC再到 Weex,这段经历也算挺戏剧性的;未来会是 Weex 吗?答案并不重要,唯有沉醉其中。</p>    <p><strong>One More Thing</strong></p>    <p>Weex 不仅在双十一中会场覆盖率达到99.6%(1700+页面),同时还在支撑大促以外更多的业务,有大量Weex内核性能/稳定性工作、大量新功能、配套的工具、社区需要建设</p>    <p> </p>    <p>来自:http://mp.weixin.qq.com/s/2ZdTFGHOT0MDgxsmpLustw</p>    <p> </p>