版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、 React同构与极致的性能优化架构文摘 微信号 ArchDigest功能介绍 每天一篇架构领域重磅好文,涉及一线互联网公司的互联网应用架构、大数据、机器学习等各个热门领域。前言随着React的兴起, 结合Node直出的性能优势和React的组件化,React同构已然成为趋势之一。享受技术福利的同时,直面技术挑战,在复杂场景下,挑战10倍以上极致的性能优化。什么是同构?一套代码既可以在服务端运行又可以在客户端运行,这就是同构应用。简而言之, 就是服务端直出和客户端渲染的组合, 能够充分结合两者的优势,并有效避免两者的不足。为什么同构?性能: 通过Node直出, 将传统的三次串行http请求简化
2、成一次http请求,降低首屏渲染时间SEO: 服务端渲染对搜索引擎的爬取有着天然的优势,虽然阿里电商体系对SEO需求并不强,但随着国际化的推进, 越来越多的国际业务加入阿里大家庭,很多的业务依赖Google等搜索引擎的流量导入,比如Lazada.兼容性: 部分展示类页面能够有效规避客户端兼容性问题,比如白屏。性能数据性能是一个综合性的问题, 不能简单地断言同构应用一定比非同构应用性能好,只能说合适的场景加上合理的运用,同构应用确实能带来一定的性能提升, 先来看一个线上的案例。通常来说,网络状况越差,同构的优势越明显,下图是在不同网络状况下首屏渲染时间的一组对比:线上案例近两年,无论是业界还是阿
3、里内部都涌现了大量同构实践, 业界比较有影响力的包括Facebook, Quora, Medium, Twitter, Airbnb, Walmart、手Q以及QQ兴趣部落等阿里内部也有大量的应用,仅列举部分beidou开发组做过技术支持的项目阿里云 - 大数据地产钉钉 - 企业主页钉钉 - 钉钉日志和审批模板市场菜鸟 - 物流大市场云零售 - 店掌柜Lazada - PDP国际事业部 - AGLAAILab - 行业解决方案AILab - 智能硬件平台AILab - AliGenie开放平台AILab - AR官网ICBU - ICBU店铺业务平台 - 门店评价国际UED - 数据运营国际U
4、ED - 知之国际UED - 探花国际UED - Nuke官网及过程管理国际UED - 会议记录,实时翻译国际UED - LBS数据地图国际UED - 数探国际UED - 微策国际UED - shuttle国际UED - fie portal.业界生态react-server: React服务端渲染框架next.js: 轻量级的同构框架beidou: 阿里自己的同构框架,基于eggjs, 定位是企业级同构框架除了开源框架,底层方面React16重构了SSR, react-router提供了更加友好的SSR支持等等, 从某种程度上来说,同构也是一种趋势,至少是方向之一。思考 与 实现同构的出发点
5、不是 “为了做同构,所以做了”, 而是回归业务,去解决业务场景中SEO、首屏性能、用户体验 等问题,驱动我们去寻找可用的解决方案。在这样的场景下,除了同构本身,我们还需要考虑的是:高性能的 Node Server可靠的 同构渲染服务可控的 运维成本可复用的 解决方案.简单归纳就是, 我们需要一个 企业级的同构渲染解决方案。我们是怎么做的?基于 eggjs 加入可拔插的同构能力beidou-plugin-react 作为原有MVC架构中, view 层的替换, 使用 React 组件作为视图层模板, 可以直接渲染 React Component 并输出给客户端beidou-plugin-webp
6、ack集成 Webpack 到框架中, 在开发阶段, 提供代码的编译和打包服务beidou-plugin-isomorphic服务端的 React 运行时: babel-register polyfill 注入: 环境变量, BOM等 非js文件解析: css, images, fonts.服务端支持css modules自动路由: 纯静态页面无需编写任何服务端代码,像写纯前端页面一样简单.这里不再赘述具体如何实现,有兴趣的读者可以阅读我们的开源同构框架beidou - /alibaba/beidou热点问题任何一种技术都有其适用场景和局限性, 同构也不例外,以下试举一二,以做抛砖引玉。内存泄
7、漏性能瓶颈.内存泄漏不是同构应用所特有的,理论上所有服务端应用都可能内存泄漏,但同构应用是“高危群体”, 具体如何解决请参考本人的Node应用内存泄漏分析方法论与实战(/alibaba/beidou/blob/master/packages/beidou-docs/articles/node-memory-leak.md),接下来重点剖析下性能优化。极致的性能优化前面也提到了,同构应用并不一定就比非同构应用性能好,影响性能的因素实在太多了,再来看一组数据:上图是基于Node v8.9.1 和 React15.5.4, 开4个进程采集到的数据, X轴是最终生成页面节点数量,Y轴红色的线表示RT(
8、包括渲染时间和网络时间), 绿色的柱子表示QPS. 可以看出来:随着页面节点的增多渲染时间可能变得很长,QPS下降非常迅速。在页面节点超过3000左右的时候,QPS接近个位数了,而且实际页面中可能包含较复杂的逻辑以及不友好的写法,情况可能会更糟。顺带提一下, 笔者采样了淘宝首页 和淘宝某详情页以及Lazada某详情页,页面节点数分别是2620、2467和3701. 大部分情况下,页面节点数低于1000, 比如菜鸟物流市场首页看起来内容不少,其实节点数是775。那针对3000节点以上的页面,我们该怎么做呢?笔者总结了以下策略并重点阐述其中一两点:采用编译后的React版本: 根据Sasha Ai
9、ckin的博客,React15在Node4、Node6、Node8下,采用编译后的版本性能相比未编译版本分别提升了2.36倍、3倍、3.85倍模块拆分: 模块拆分有利于并发渲染,目前ICBU店铺装修采用的就是这种方式模块级别缓存: 页面中某些模块其实是很适合缓存的,比如Lazada详情页中节点数虽然高达3701, 但其实页头部分就占比55.5%,页尾占比3.5%,而页头页尾是常年不变的.组件级缓存: 最小粒度的缓存单位了,性能提升依赖于缓存的范围和命中率,运用得当,可能带来非常大的性能提升。参考walmartlabs(/walmartlabs/reactjs-ssr-profiling-and
10、-caching-5d8e9e49240c)采用hsf代替http对外提供服务: hsf的网络消耗远低于http, 在店铺同构实践中,改用hsf, java端调用Node端的耗时缩短了一半。部分模块客户端渲染(对SEO无用的部分): 直接降低SSR部分的复杂度智能降级: 当流量暴增,接近或超过阈值时,会直接导致服务的RT快速上升。可以实时监测CPU和内存的使用率,超过一定的比例自动降级为客户端渲染,降低服务端压力,CPU和内存恢复常态时,自动切回服务端渲染。采用Node8: 同样在店铺实践中,采用Node8相比Node6, 渲染时间从28ms降低到了18ms, 提升幅度为36%.采用最新版Re
11、act16: facebook官方数据(/blog/2017/09/26/react-v16.0.html#better-server-side-rendering),在Node8下,React16相比编译后的react15仍有3.8倍提升,相比未编译的React15更是有数量级的提升。组件级缓存如果说性能优化有万能的招式,那一定是缓存, 从Nigix缓存到模块级缓存到组件级缓存,其中最让人兴奋的就是组件级缓存,让我们一起来看看如何实现。拦截React的渲染逻辑,业界主要有三种实现方式Fork一份React, 暴力加入缓存逻辑, 代表库是react-dom-stream, 虽然这个库的人气很高
12、,但笔者还是反对这种实现方式的。通过require hook拦截instantiateReactComponent的载入并注入缓存逻辑,参考react-ssr-optimization(/aickin/react-dom-stream)扩展ReactCompositeComponent的mountComponent方法,参考electrode-react-ssr-cachin(/electrode-io/electrode-react-ssr-caching/blob/master/lib/ssr-caching.js#L148-L161)注入缓存逻辑, 代码如下const ReactComp
13、ositeComponent = require(react/lib/ReactCompositeComponent);ReactCompositeComponent.Mixin._mountComponent = ReactCompositeComponent.Mixin.mountComponent;ReactCompositeComponent.Mixin.mountComponent = function(rootID, transaction, context) const hashKey = generateHashKey(this._currentEps); if (cacheS
14、torage.hasEntry(hashKey) / 命中缓存则直接返回缓存结果 return cacheStorage.getEntry(hashKey); else / 若未命中,则调用react的mountComponent渲染组件,并缓存结果 const html = this._mountComponent(rootID, transaction, context); cacheStorage.addEntry(hashKey, html); return html; ;设置最大缓存和缓存更新策略lruCacheSettings: max: 500, / The maximum si
15、ze of the cache maxAge: 1000 * 5 / The maximum age in milliseconds 上述缓存逻辑是基于属性的,能覆盖大部分的应用场景,但有一个要求,属性值必须可枚举且可选项很少. 请看下面的场景。淘宝某页面上有大量的商品,而淘宝的商品又何止百万,就算某个被缓存,下次被命中的可能性依然微乎其微。那如何解决这个问题?聪明的读者可能已经看出来了,虽然每个商品最终渲染的结果千变万化,但结构始终是一致的,因此结构是可以缓存的。要实现结构的缓存,需要在上述逻辑上额外新增三步。生成中间结构:以组件$price为例,将变量price以占位符$price代替se
16、t(price, $price), 再调用react原生的mountComponent方法则可以生成中间结构$price/div缓存中间结构生成最终组件以上就是组件级缓存的实现方式, 特别要提醒的是缓存是把双刃剑,运用不当可能会引发内存泄漏以及数据的不一致。React16 SSRFB在9.26发布了React16正式版,之前万众期待的SSR性能提升(/whats-new-with-server-side-rendering-in-react-16-9b0d78585d67)没有让大家失望, 引用React核心开发Sasha Aickin的对比图:笔者拿之前的应用升级到React16, 对比下3
17、909节点,RT从295ms降到了51ms, QPS从9提升到了44, 提升非常明显。实战接下来通过一个例子,展示如何一步步地提升性能。代码仓库(/alibaba/beidou/tree/master/examples/performance) - /alibaba/beidou/10倍以上性能提升首先构造一个非常复杂的页面, 页面节点数是3342, 对比之下,淘宝首页首屏的页面节点数是831, 异步充分加载之后(懒加载完成),整个页面节点数为3049. 注: 淘宝页面为动态页面,每次采样可能会有差异。初始平均渲染时间为295.75ms(Node6.92, React15.6.2), 注: 图
18、中有296.50ms,317.25ms,297.25ms,295.75ms四个平均值,是因为开启了四个进程,采样最后一个,下同。启用babel性能加速插件, 平均渲染时间为219.00ms采用Node8.9.1(或更新版本)平均渲染时间为207ms采用production模式平均渲染时间为81.75ms部分内容客户端渲染,平均渲染时间为44.63ms部分内容组件级别cache,平均渲染时间为22.65ms采用React16(或更新版本),平均渲染时间为5.17ms结合React16和部分客户端渲染,平均渲染时间为2.68ms至此,服务端渲染时间已经最初的295.75ms降低到了2.68ms,提升了超过100倍。更多性能策略其实除了上述应用的策略,还有其它的策略,比如:采用Async, 有数据称性能提升30%, 笔者试了下,未见明显提升。应该是经过了babel的编译,最终没有发挥出Async的优势,这是因为beidou框架在服务端要支持import等ES6的写法以及支持React的JSX语法。其实也非常简单,直接缩小babel的编译范围,在beidou框架中是可以自己定义的。降低React组件的嵌套层级。试验数据,同样的页面节点数,服务端渲染
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 外购材料采购制度
- 原材料采购风险制度
- 采购类项目管理制度
- 传统印刷厂采购管理制度
- 如何编写采购制度
- 企业工会采购相关制度
- 乡镇卫生院基药采购制度
- 政府采购学校内控制度
- 采购食品溯源制度
- 重大物资采购管理制度
- 2026广东深圳医学科学院科研职能岗位招聘笔试备考试题及答案解析
- 山东大众报业集团有限公司招聘笔试题库2026
- 2026年国网江苏省电力有限公司高校毕业生招聘约825人(第二批)笔试模拟试题及答案解析
- 2026上半年新疆维吾尔自治区招聘事业单位工作人员分类考试4474人笔试备考题库及答案解析
- GB/T 20151-2026光度学CIE物理光度系统
- GB/T 18570.9-2025涂覆涂料前钢材表面处理表面清洁度的评定试验第9部分:水溶性盐的现场电导率测定法
- 高中实验室安全教育课件
- 安徽省合肥市2025-2026学年上学期期末八年级数学试卷(含答案)
- 2026年甘肃省交通运输厅所属事业单位招聘笔试易考易错模拟试题(共500题)试卷后附参考答案
- 电信公司客户服务部门员工绩效考评表
- 安徽合肥市人力资源服务有限公司招聘笔试题库2026
评论
0/150
提交评论