京东通天塔(京东通天塔怎么使用)

巴别塔是一个在JD.COM快速建立活动页面的平台。用户可以选择需要的模板,在可视化平台上配置相应的数据,生成相应的原生、H5和PC活动页面。模板以其丰富的样式和灵活的操作在JD.COM被广泛使用,用户流量也呈现出非常快速的增长。但是随着项目的迭代,功能越来越复杂,模板越来越多,前端和节点中间层的性能问题逐渐暴露出来。其中前端首屏加载时间TP75性能在2秒以上,而节点中间层单核QPS低于其他应用。为了提升用户体验,提高系统吞吐量,2019年下半年,我们对现有的巴别塔H5项目进行了全面分析,并进行了全方位的性能优化。

综合性能提高30%以上

巴别塔H5是基于反应SSR。第一页被请求并呈现在节点的中间层。在客户端的网关接口中请求和呈现分页和其他异步请求。静态资源托管在CDN中,如图1所示。

京东通天塔(京东通天塔怎么使用)

图1:H5巴别塔请求流程

基于上述架构,经过2019年下半年的优化,巴别塔H5前端首屏的加载性能和节点中间层的渲染性能均有大幅提升。

一个

首次屏幕加载性能

加载第一个屏幕需要时间。TP75由2.47秒降至1.58秒,性能提升约36.03%。图2示出了优化前后的第一屏幕TP75的加载时间,以周为单位。

京东通天塔(京东通天塔怎么使用)

图2:第一个屏幕TP75的加载时间

这里,第一屏幕的加载时间是指从用户打开页面到完成第一屏幕的第一个图片请求的时间。横坐标代表周,01代表今年的第一周(2020年1月6日~ 2020年1月12日),52代表去年的最后一周(2019年12月23日~ 2019年12月29日)。

2

服务器性能

通过对服务器的压力测试,在相同的QPS维度下,CPU从29.52%下降到20.5%,CPU利用率比之前下降了30.5%。

京东通天塔(京东通天塔怎么使用)

图3:相同QPS下的CPU利用率

在线性能分析

在优化之前,需要收集当前的在线数据,以了解服务的当前性能。我们主要通过以下方式分析和监控项目的绩效。

一个

性能API

性能API是ECMAscript5推出的,精度可以达到1毫秒的千分之一。目前大多数主流浏览器都已经支持性能对象。通过performance.timing对象,可以得到浏览器处理网页各个阶段所花费的时间。通过performance.getEntries方法,可以得到所有请求的耗时信息,包括js、css、图片、ajax。

基于Performance API,我们封装了一个前端测速模块,在页面加载后将所需的性能数据上报给服务器,然后这些数据就可以在可视化平台上显示和分析了。

2

调试工具

Chrometools是前端调试和性能分析的常用工具。通过这个工具,可以检查页面资源加载情况,加载的CSS、JS和图片的大小,还可以通过性能面板检查页面渲染和脚本执行情况。

v8-profiler

巴别塔H5基于React SSR架构,页面首屏请求数据并在Node中间层呈现。因此,除了单纯的前端监控和分析,还需要对节点层的性能进行分析和优化。在节点层的性能分析中,我们主要使用v8-profiler模块进行性能分析。

在本地或测试环境中添加两条新路线:

const profiler = require(& # 39;V8-profiler & # 39;);router . get(& # 39;/profiler/start & # 39;,(req,RES)= & gt;{//开始分析profiler . Start Profiling(& # 39;CPU配置文件& # 39;);RES . end(& # 39;个人资料开始& # 39;);});router . get(& # 39;profiler/end & # 39;,(req,RES)= & gt;{ const profile = profiler . stop profile()profile . export()。管道(res)。打开(& # 39;完成& # 39;,()= & gt{ profile . delete();RES . end();});});通过ab压力测量工具向服务器发出请求。

a b-c 10-n 1000 http://localhost:7001/mall/active/XXX/index . html

在压力测量过程中,可以通过http://localhost:7001/profiler/start启动性能统计,通过http://localhost:7001/profiler/end结束性能统计,并将结果保存为***。cpuprofile文件,并通过Chrome Devtools中的Javascript Profiler工具进行分析。

京东通天塔(京东通天塔怎么使用)

图4:执行4:节点服务器代码

常规优化+业务特性优化

我们主要从两个方面进行性能优化,一方面基于通用前端常规性能优化方案,另一方面基于通天塔的业务特点,对部分业务进行优化。

一个

常规前端优化

优化之初,根据《高性能网站建设指南》中提到的常规优化方案,我们检查了项目中需要改进或深度优化的地方,主要涉及以下几个方面:

尽可能的减少HTTP的请求数,减小HTTP请求大小将静态资源放在CDN,最大化利用CDN缓存能力减少CSS和JS请求个数,减小CSS和JS包大小启用gzip压缩

1)减小图片请求大小。

在巴别塔的页面中,图片请求一般占比最大。在早期的开发过程中,我们已经对图片请求进行了延迟加载优化。很难进一步减少图片请求的数量,但是我们可以针对图片的大小进行优化。

京东通天塔(京东通天塔怎么使用)

图5:显示图片的大小和实际大小

如图5,在页面中图片实际所展示坑位大小为115x115,即使在3倍屏上,所需图片尺寸也只是345x345,但实际请求中,图片的原始尺寸却是800x800,这对用户流量是一种浪费,同时也增加了图片加载耗时,而通天塔活动页中,这种类似的图片还有很多,而同时,京东图片服务器正好支持图片的裁剪,原来一张800x800的图片,可以按比例缩小到所需的高度,如一张800x800的原图 https://m.360buyimg.com/babel/jfs/t1/85209/24/15512/218570/5e7179d8E957c16c1/5fbcc42fad37fe94.jpg!q70.dpg ,通过修改URL,可以改成下发230x230尺寸的图 https://m.360buyimg.com/babel/s230x230_jfs/t1/85209/24/15512/218570/5e7179d8E957c16c1/5fbcc42fad37fe94.jpg!q70.dpg如图5所示,页面中显示的实际坑尺寸为115x115,即使在3x屏幕上,所需的图片尺寸也只有345x345。但在实际请求中,原图片大小为800x800,浪费了用户流量,增加了加载图片的时间。在巴别塔的活动页面有很多类似的图片,同时JD.COM图片服务器刚好支持图片的剪切。一张800x800的原图可以缩小到需要的高度,比如一张800x800的原图https://m . 360 buyimg . com/babel/jfs/t1/85209/24/15512/218570/5e 7179d 8 e 957 c 16 c 1/5。Q70.dpg,通过修改网址,可以改为发出230x230大小的图片https://m.360buyimg.com/Babel/S230x230 _ JFS/T1/85209/24/15512/218570/5e 7179 d8e 957 C16 C1/。q70.dpg

鉴于此,针对图片尺寸,我们可以根据实际显示尺寸,请求对相应尺寸的图片进行优化,以减小HTTP的大小。

const isJfsRegex = /360buyimg.com/.*/((s([d^_]+)x([d^_]+)_)?jfs)/i;export function resizeImg(url, rect) { const dpr = window.devicePixelRatio; if (!isJpegRegExp.test(url)) { return url; } const result = url.match(isJfsRegex); if (!result) { return url; } if (result[3] && result[4]) { if (!rect || (!rect.width && !rect.height)) { return url; } if (rect.width && !rect.height) { rect.height = rect.width / result[3] * result[4]; } if (rect.height && !rect.width) { rect.width = rect.height / result[4] * result[3]; } const t = 's' + Math.ceil(rect.width* dpr) + 'x' + Math.ceil(rect.height* dpr) + '_jfs'; return url.replace(result[1], t); } else { if (rect && rect.width && rect.height) { return url.replace('/jfs/', `/s${Math.ceil(rect.width * dpr)}x${Math.ceil(rect.height * dpr)}_jfs/`); } } return url;}

2)最大化利用CDN缓存const isJfsRegex = /360buyimgcom/。*/((s([d^_]+)x([d^_]+)_)?jfs)/I;导出函数resizeImg(url,rect){ const DPR = window . devicepixelrratio;如果(!isjpegrexp . test(URL)){返回URL;} const result = URL . match(isJfsRegex);如果(!结果){返回url} if (result[3] && result[4]) { if(!rect ||(!rect.width &&!rect.height)) {返回url} if (rect.width &&!rect . height){ rect . height = rect . width/result[3]* result[4];} if (rect.height &&!rect . width){ rect . width = rect . height/result[4]* result[3];} const t = & # 39s & # 39+math . ceil(rect . width * DPR)+& # 39;x & # 39+math . ceil(rect . height * DPR)+& # 39;_ jfs & # 39;返回url.replace(结果[1],t);} else { if(rect & rect . width & rect . height){ return URL . replace(& # 39;/jfs/& # 39;,`/s $ { math . ceil(rect . width * DPR)} x $ { math . ceil(rect . height * DPR)} _ jfs/`);} }返回网址;}2)最大化CDN缓存的利用率

性能优化之前,巴别塔的静态资源在上线之前都是开发者在自己的电脑上打包的,文件名会根据文件内容重新生成,格式为【文件名】。[内容哈希:8] .js。

这样在个人电脑上打包,即使有package-lock.json加锁包版本,node_module下的文件也可能由于个人电脑的操作系统和使用的npm包管理工具不同而不一致(有些包管理工具不读取package-lock.json),导致文件的contenthash不同。

为了解决这个问题,我们搭建了一个基于Jenkins的前端CI打包系统,然后将上线前的前端静态资源包全部迁移到CI中。这样就保证了文件名的一致性,从而充分利用CDN缓存。

3)调整webpack打包策略,根据需要加载CSS和JS。

性能优化前,巴别塔的CSS和JS资源按照以下策略打包:

vendor.[contenthash:8].js: 包含node_module下的代码common.[contenthash:8].js: 包含非node_modules下的代码[channel].[contenthash:8].js: 通天塔有很多渠道,每个渠道的专属代码打包到这个JS中template.[contenthash:8].css: 包含所有渠道通用CSS[channel].[contenthash:8].css: 包含渠道专有CSS

以这种方式包装有以下两个问题,

1.每个活动都会加载所有模板对应的CSS和JS,造成不必要的加载。

2.所有的系统模板代码都打包到公共包中,这就导致了巨大的公共包。模板代码的任何改动都会影响常用包的文件名,导致CDN缓存失效,客户端必须重新请求CDN。

针对两个问题,我们改进了包装策略,最终方案改为:

vendor.[contenthash:8].js: 包含node_module下的JS文件lowUsedTemp.[contenthash:8].js: 包含使用频率低的系统模板代码,页面会按照活动是否使用到低频模板按需请求mute.[contenthash:8].js: 包含剔除低频使用模板后,较为稳定,很少改动的系统模板template.[contenthash:8].js: 包含剩余非node_modules下的代码[channel].[contenthash:8].js: 包含渠道专属代码lowUsedTemp.[contenthash:8].css: 包含使用频率低的系统模板代码的CSS,页面会按照活动是否使用到低频模板按需请求template.[contenthash:8].css: 包含所有渠道通用CSS[channel].[contenthash:8].css: 包含渠道专有CSS

以这种方式打包,只有使用低频模板的活动才会加载lowusedtemp。【内容哈希:8】。CSS和lowUsedTemp。【内容哈希:8】。JS,其中按需加载的CSS占总CSS大小的25%,按需加载的JS占总大小的17%。但是,JS资源静音。【内容哈希:8】。js单独打包,因为里面包含的模板很少改变,所以打包上线的时候它的文件名也很少改变。这样可以利用CDN缓存,用户每次上线都不会再次请求这部分代码。

2

业务优化

常规的前端性能优化达到瓶颈后,我们开始尝试基于业务的性能优化。

1)首屏精度优化

巴别塔的页面是通过在可视化配置平台中选择模板和配置数据动态生成的,配置的材料数量也是由操作本身决定的,比如商品地板的材料地板。少的可能只有几个,多的也有几十个或者几百个,这就导致了巴别塔第一屏页面的以下特点。

1.页面灵活多变,页面结构难以预测。

2.在请求第一屏楼层的数据时,服务器很难计算出仅仅填充第一屏就需要分配多少楼层,所以根据材料楼层数进行分页。如果在第一页材料层配置了更多的材料,那么节点的数量将会非常大。

由于以上两个特点,很多活动页面的首屏内容要比客户端首屏的实际显示长度长很多,不仅增加了首屏的渲染时间,还浪费了节点服务器的CPU资源(渲染不必要的楼层)。

此外,在通过v8-profiler测试节点服务器的性能时,我们发现有三个地方节点服务器的开销最高。

通过JSON.parse解析后端下发的活动数据React.renderToString 进行首屏渲染JSON.stringify将首屏数据序列化后跟随HTML下发给客户端

综合考虑各种优化方法,最终决定计算节点楼层上各楼层的高度,并根据首屏高度渲染楼层数。

京东通天塔(京东通天塔怎么使用)

图6:第一个屏幕的精确渲染过程

1.当用户向节点中间层发出请求时,客户端会将设备宽度和高度信息嵌入到cookie中。

2.节点中间层从cookie中获取设备宽度和高度信息,如果获取失败,则使用默认值。

3.循环计算每层楼的高度。如果楼层的累积高度超过设备高度的2倍,则丢弃后续楼层的数据,并重置寻呼信息。

4.节点中间层根据计算出来的数据,渲染第一层,序列化数据,用HTNL发送给客户端。

5.前端检测页面是否满了两屏,如果没有,立即请求下一页数据。

地板维度的页面优化完成后,仍然可以精益求精,根据材料地板对地板中的材料进行优化。如果首页最后一个材质层有两屏以上的材质,可以将两屏以上的材质降级到客户端进行渲染。

以上结论中提到的服务器端性能优化,主要是通过首屏精度优化来实现的。

2)预载第一屏幕图片

由于巴别塔页面的灵活性,开发者不知道首屏会出现哪些楼层元素,所以页面中的所有图片资源都统一设置为懒加载模式。基于巴别塔H5 SSR的架构,服务器完成渲染后将首页发送到前端,前端只有在加载JS后才判断图片是否在首屏,然后才开始加载首屏的图片,这样会导致图片只有在JS加载完成后才加载,图片坑的白屏时间更长。

基于以上图片加载延迟的问题,我们在前期做了第一次优化,即在fold之上的floor之后插入一个inline JS,获得页面的加载图片元素。如果是在第一屏,我们设置第一屏图像的data-src为src来加载,但是发现了以下问题。这是一个测试演示。

ta charset="UTF-8"> docu<em></em>ment "test" />

我是测试代码

cript> (function() { var start = Date.now(); console.log('start', start) var img = document.getElementById('test'); img.onload = function() {console.log('end', Date.now(), Date.now() - start); // end - start > 2000ms } img.src = img.getAttribute('data-src'); })();cript>

我是测试代码22222

cript src=http://www.41120.com/skin/shenghuo/image/nopic.gif>

& lt!DOCTYPE html & gt& lthtml & gt& lthead & gt& ltmeta charset = & # 34UTF-8 & # 34;& gt& lttitle & gt文档& lt/title & gt;& lt/head & gt;& ltbody & gt& ltimg数据-src = & # 34;/img-size . png & # 34;id = & # 34测试& # 34;/& gt;& lth1 & gt我是测试代码

在test.js中非常简单

console . log(& # 39;开始& # 39;);var start = date . now();for(;;){ if(date . now()-start & gt;2000){ break;} } console . log(& # 39;end & # 39);

京东通天塔(京东通天塔怎么使用)

图7:演示页面加载和执行

从图中可以看出,在JS执行后,这个图像仍然被加载。但是我们发现performance-cpu.jpg的图片并没有因为浏览器预载了图片资源而被JS屏蔽。基于浏览器对图片的预加载和上面第一屏的精准渲染,我们又做了一次优化:在计算第一屏的层高时,我们在第一屏标记了一些图片元素,根据这个标记,在渲染时,我们没有偷懒加载被标记的图片。直接使用src,通过这个优化,画面不会被JS遮挡,提前了首屏画面开始加载的时间,减少了画面坑的白屏时间。

3)交互优化

在巴别塔活动中,有很多包含多个标签页的模板,比如商品模板。在之前的开发中,每次切换标签页的时候,我们都会破坏掉之前标签页下的内容,重新渲染新标签页下的内容,以至于再次切换回来的时候,仍然需要重新渲染,导致页面卡顿。基于此,我们将Tab渲染改为增量渲染,这样在切换回之前的Tab时,白屏和渲染时间会大大减少。

优化是持续的工作。

在巴别塔H5前端的性能优化过程中,很大一部分是在巨人的肩膀上进行的,但仅靠这些是远远不够的。当纯技术优化到一定程度,就更需要根据自身业务特点,从业务层面进行优化,这种优化的效果可能会更好。

巴别塔前端的优化到此告一段落,但优化之路还远未结束。后续我们会更进一步,基于自身业务和一些新技术继续做深度优化。同时希望这篇文章能给前端和后台开发者带来一些新的思路。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。系信息发布平台,仅提供信息存储空间服务。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。

本文来自网络,若有侵权,请联系删除,作者:何阳一,如若转载,请注明出处:

发表回复

登录后才能评论