搭建业务的性能优化指南

news/2024/12/2 10:29:01/

8d6063515d1397516831b918c233b1dc.gif

这是一篇搭建业务优化的心路历程,也是写给搭建业务的性能优化指南。

63de7cb107e36c403205762fa1ef5b13.png

前言

直到今天,淘内的页面大多都迁移到了 SSR,从我们终端平台 - 搭建研发团队的视角看,业务大致可以分为两类 —— 搭建派 和 源码派。

这两者互不冲突,更多是基于业务灵活运营和开发维护成本的考量,大致遵循以下原则:

f73a594ebd767213f3da657f368bcb10.jpeg

而且已知搭建页面性能较差,源码页面性能更好的情况下,我们又加入了“性能”这个维度,构成了一个性能优化“不可能三角”,即:

  • 对于采用源码开发的业务,自然不存在什么运营成本,性能优化起来就比较顺手;

  • 对于采用模块搭建的业务,由于搭建体系天然不是性能最优的架构,性能优化就相对没那么自然。

f91da47e47ec6de205226ce371868942.jpeg

笔者作为【搭建派】solution 的开发者,从一开始就注定要肩负着媲美源码派性能的重任。

下面来说说搭建派是如何打破这个不可能三角的,请收好你的搭建优化指南!

搭建优化指南

要想解决搭建的性能问题,我们就要先了解搭建慢在哪里?

  模块搭建慢在哪里?

搭建体系依赖 feloader(模块加载器) + seed(依赖、版本声明文件),相比源码,不仅输出的主文档体积会大,而且服务端会有拉取文件、seed依赖计算等耗时。

015207fbdcdd4c1bd83260bc519ecd55.jpeg

服务端文件加载优化

经过一系列打点日志分析后发现,虽然我们已经尽可能并行处理运行时任务,但随着并行处理的资源数量增加,存在时间片抢占,导致单个任务 resolve 时间过长。

为了验证这个猜想,于是我们从扩展入手,将多个文件合并成一个单文件,果然渲染耗时显著降低约 60%,这也为我们后续其他优化打下了基础。

01f10265280fb189055b6b645630a4fd.png

Seed缓存

服务端文件加载优化减少了运行时处理任务的数量,但是即使是单个任务也存在 seed 计算的耗时, 于是我们开始了针对 seed 部分的改造处理,重新 review 了代码进行了优化,并且在有了服务端文件加载优化的基础下,开启seed 缓存变为了可能。

无论是服务端文件加载优化还是 seed 缓存,这二者都是针对运行时做的优化,但是模块加载还是存在多个并行任务,相比于扩展的低复杂度以及单仓库,将模块打包成单文件不太现实,保持现状似乎就是最终的方案了?

但是毕竟还是存在一部分开销,而且每次主文档返回我们都要输出一大坨 seed 信息来让 hydrate 正常工作,始终达不到源码的效果。模块维度的运行时优化似乎没有什么改造空间了,那能不能干掉以 feloader + seed 的动态加载逻辑?Why Not!我们接着往下看。

53d05f4f561080b8d17c89a3f79690ce.png

搭建构建源码

搭建业务由于存在运行时动态拉取模块、计算依赖等操作,相比于源码项目存在着天然的性能劣势。

有句话说的好:打不过就加入!

好汉不吃眼前亏,外表上看虽然是搭建,但其实我也可以是源码。

24a4ab6dfb2f4f5242fe057067297310.png

于是为了帮助搭建业务更好的完成性能指标,我们推出了 搭建构建源码 这个方案,也就是 AOT (Ahead Of Time) 构建,简单说就是提前收集页面搭建模块然后生成源码项目进行构建。

  模块规范

说起搭建就离不开 feloader + seed 体系,这里就不再过多介绍,ATA 也有很多相关文章介绍,感兴趣可以自行搜素阅读。

社区开发中,主流的模块规范是 commonjs(CJS) 和 esmodule(ESM),也有诸如 AMD、CMD 等规范,feloader 是基于 CMD 规范的模块加载器, web 开发中我们以 ESM 为主,去掉 feloader 可以约等于从 CMD 迁移到 ESM,它们之前的映射关系大致如下:

步骤

CMD

ESM

定义模块

使用 define() 函数定义模块

使用 export 导出模块

加载模块

使用 require() 函数加载模块

使用 import 导入模块

模块解析

使用模块加载器解析依赖关系并加载模块

使用 JavaScript 引擎内置的模块解析机制

依赖管理

通过定义依赖列表(Seed)来管理模块依赖

通过模块引入语句来管理模块依赖

模块执行顺序

异步加载模块,按照依赖顺序执行

同步加载模块,按照调用顺序执行

导出模块

使用返回值或导出对象来导出模块

使用 export 关键字导出模块

导入模块

使用回调函数参数或全局变量来导入模块

使用 import 关键字导入模块

浏览器支持情况

需要使用 CMD 模块加载器支持

部分现代浏览器原生支持 ES 模块

搞清楚各个环节做了什么事情之后,我们的适配工作就逐渐清晰。

  模块适配

回归到源码的方案中,我们只需要按照标准的 npm 依赖管理进行适配即可。

搭建平台可以很容易从页面获取到所有模块的 npm 包名 和 版本号,有了这两个信息,在脚手架直接生成到package.json即可,另外模块的版本号根据搭建页面是正式还是测试页进行了区分,当在测试页调试的时候,会通过 semver 取到 beta 版本,确保依赖正确

以下述依赖为例:

{"@ali/foo":">4.1.0-beta <4.1.0""@ali/bar":">4.1.0-beta <4.1.0"
}

脚手架会将其编译为如下文件,也就是 solution 内部消费的模块的数据结构,在最小改动的前提下保证功能的正常运行:

import * as Mod0Instance from '@ali/foo';
const { default: defaultExport0, ...nameExports0 } = Mod0Instance;import * as Mod1Instance from '@ali/bar';
const { default: defaultExport1, ...nameExports1 } = Mod1Instance;export default {'@ali/foo': {defaultExport: defaultExport0,nameExports: nameExports0,},'@ali/bar': {defaultExport: defaultExport1,nameExports: nameExports1,},
};

当然适配工作远没有这么简单,其他的就不在此过多展开。

技术层面的适配基本完成后,然后就是产品上的功能的实现,整个流程图如下:

8eb4320e30e1a9b3631d827f93ce3145.jpeg

  调试

由于我们将搭建页改造成了“源码页”,模块代理规则不再有效,也就是本地的单模块是无法用于代理调试的即 模块调试转变成了源码项目调试

但真实的源码项目又在云端生成,所以调试问题就转化成了——如何保存源码项目,并支持开发者下载获取指定版本。

  • 设计

一开始想到借助 OSS,通过在构建器中压缩源代码然后调接口上传,后来想到项目上传不就是 git 托管平台所做的事情吗,所以问题又变成了如何把代码上传到 git 平台。

由于是云构建,机器不固定,好在我们的代码托管平台提供了通过域账号和 privateToken登录的方式,这样只需绑定一个公共账号即可将代码推送上去。

同时我们将时间戳(YYYY-MM-DD-mm)作为对应的分支名,现在开启构建后,开发者通过构建日志即可快速 clone 对应分值仓库,然后通过我们预设好的代理规则即可进行快速调试!

dd6f180b536233961f31da0f85b59188.png

结语

通过 AOT Build + 模版的方式来实时生成源码项目,避免运行时动态获取模块的耗时,有效提升了服务端渲染的性能。当然也存在trade-off,如

  • 每次发布前都要等待构建完成,以确保最终预览的是最新的代码内容

相信经过后期的不断使用,会将整个链路打磨的更加贴合用户体验!

团队介绍

我们是淘天集团—终端平台团队,专注打造业界领先的终端技术以及丝滑流畅的体验,通过持续的创新突破,赋能前台业务、连接数亿用户,提供极致高可靠的服务、极致高性能的架构和极致高效率的产品。

¤ 拓展阅读 ¤

3DXR技术 | 终端技术 | 音视频技术

服务端技术 | 技术质量 | 数据算法


http://www.ppmy.cn/news/1551729.html

相关文章

【UG\NX二次开发-Block UI】指定方位 VisibleManipulatorHandles 设置控制器手柄可见

特定于块属性 VisibleManipulatorHandles 值 Origin 0x1 原点 Ratate X 0x10 旋转 Ratate Y 0x20 Ratate Z 0x40 Translate X 0x2 平移 Translate Y 0x4 Translate Z 0…

基于.NET调用WebService服务

基于.NET调用WebService服务 上一篇文章用java的Spring Boot框架搭建了一个WebService服务端&#xff0c;这篇文章通过.NET进行调用&#xff0c;下文基于Visual Studio 2022 引入WebService服务 项目右键 -> 添加 -> 服务引用 选择WCF Web Service&#xff0c;点击下一…

有效判断住宅IP与机房IP的方法

一、住宅IP与机房IP的定义 1. 住宅IP 是指由互联网服务提供商&#xff08;ISP&#xff09;分配给个人用户家庭网络的IP地址。这类IP地址通常是自然分布的&#xff0c;通常来自家庭宽带用户&#xff0c;具有如下特点&#xff1a; 用户身份真实性高&#xff1a;住宅IP通常与真…

论文笔记-WWW2024-ClickPrompt

论文笔记-WWW2024-ClickPrompt: CTR Models are Strong Prompt Generators for Adapting Language Models to CTR Prediction ClickPrompt: CTR模型是大模型适配CTR预测任务的强大提示生成器摘要1.引言2.预备知识2.1传统CTR预测2.2基于PLM的CTR预测 3.方法3.1概述3.2模态转换3.…

学习ASP.NET Core的身份认证(基于Session的身份认证2)

基于Session的身份认证通过后&#xff0c;后续访问控制器的函数时该如何控制访问权限&#xff1f;虽然可以按上篇文章方式在需要做控制的函数开头检查Session的用户标识&#xff0c;可以写个全局通用检查类供所需函数调用&#xff0c;但还是有更简便的方法&#xff0c;本文学习…

基于Java Springboot美食分享系统

一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue、Element-ui 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 数据…

AI/ML 基础知识与常用术语全解析

目录 一.引言 二.AI/ML 基础知识 1.人工智能&#xff08;Artificial Intelligence&#xff0c;AI&#xff09; (1).定义 (2).发展历程 (3).应用领域 2.机器学习&#xff08;Machine Learning&#xff0c;ML&#xff09; (1).定义 (2).学习方式 ①.监督学习 ②.无监督…

使用vcpkg自动链接tinyxml2时莫名链接其他库(例如boost)

使用vcpkg自动链接tinyxml2时莫名链接其他库&#xff08;例如boost&#xff09; vcpkg的自动链接功能非常方便&#xff0c;但在某些情况下会出现过度链接的问题。 链接错误症状 以tinyxml2为例&#xff0c;程序中调用tinyxml2的函数后&#xff0c;若vcpkg中同时存在opencv和…