搭建业务的性能优化指南
这是一篇搭建业务优化的心路历程,也是写给搭建业务的性能优化指南。
前言
直到今天,淘内的页面大多都迁移到了 SSR,从我们终端平台 - 搭建研发团队的视角看,业务大致可以分为两类 —— 搭建派 和 源码派。
这两者互不冲突,更多是基于业务灵活运营和开发维护成本的考量,大致遵循以下原则:
而且已知搭建页面性能较差,源码页面性能更好的情况下,我们又加入了“性能”这个维度,构成了一个性能优化的“不可能三角”,即:
对于采用源码开发的业务,自然不存在什么运营成本,性能优化起来就比较顺手;
对于采用模块搭建的业务,由于搭建体系天然不是性能最优的架构,性能优化就相对没那么自然。
笔者作为【搭建派】solution 的开发者,从一开始就注定要肩负着媲美源码派性能的重任。
下面来说说搭建派是如何打破这个不可能三角的,请收好你的搭建优化指南!
搭建优化指南
要想解决搭建的性能问题,我们就要先了解搭建慢在哪里?
▐ 模块搭建慢在哪里?
搭建体系依赖 feloader(模块加载器) + seed(依赖、版本声明文件),相比源码,不仅输出的主文档体积会大,而且服务端会有拉取文件、seed依赖计算等耗时。
服务端文件加载优化
经过一系列打点日志分析后发现,虽然我们已经尽可能并行处理运行时任务,但随着并行处理的资源数量增加,存在时间片抢占,导致单个任务 resolve 时间过长。
为了验证这个猜想,于是我们从扩展入手,将多个文件合并成一个单文件,果然渲染耗时显著降低约 60%,这也为我们后续其他优化打下了基础。
Seed缓存
服务端文件加载优化减少了运行时处理任务的数量,但是即使是单个任务也存在 seed 计算的耗时, 于是我们开始了针对 seed 部分的改造处理,重新 review 了代码进行了优化,并且在有了服务端文件加载优化的基础下,开启seed 缓存变为了可能。
无论是服务端文件加载优化还是 seed 缓存,这二者都是针对运行时做的优化,但是模块加载还是存在多个并行任务,相比于扩展的低复杂度以及单仓库,将模块打包成单文件不太现实,保持现状似乎就是最终的方案了?
但是毕竟还是存在一部分开销,而且每次主文档返回我们都要输出一大坨 seed 信息来让 hydrate 正常工作,始终达不到源码的效果。模块维度的运行时优化似乎没有什么改造空间了,那能不能干掉以 feloader + seed 的动态加载逻辑?Why Not!我们接着往下看。
搭建构建源码
搭建业务由于存在运行时动态拉取模块、计算依赖等操作,相比于源码项目存在着天然的性能劣势。
有句话说的好:打不过就加入!
好汉不吃眼前亏,外表上看虽然是搭建,但其实我也可以是源码。
于是为了帮助搭建业务更好的完成性能指标,我们推出了 搭建构建源码 这个方案,也就是 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,},
};
当然适配工作远没有这么简单,其他的就不在此过多展开。
技术层面的适配基本完成后,然后就是产品上的功能的实现,整个流程图如下:
▐ 调试
由于我们将搭建页改造成了“源码页”,模块代理规则不再有效,也就是本地的单模块是无法用于代理调试的即 模块调试转变成了源码项目调试。
但真实的源码项目又在云端生成,所以调试问题就转化成了——如何保存源码项目,并支持开发者下载获取指定版本。
设计
一开始想到借助 OSS,通过在构建器中压缩源代码然后调接口上传,后来想到项目上传不就是 git 托管平台所做的事情吗,所以问题又变成了如何把代码上传到 git 平台。
由于是云构建,机器不固定,好在我们的代码托管平台提供了通过域账号和 privateToken登录的方式,这样只需绑定一个公共账号即可将代码推送上去。
同时我们将时间戳(YYYY-MM-DD-mm)作为对应的分支名,现在开启构建后,开发者通过构建日志即可快速 clone 对应分值仓库,然后通过我们预设好的代理规则即可进行快速调试!
结语
通过 AOT Build + 模版的方式来实时生成源码项目,避免运行时动态获取模块的耗时,有效提升了服务端渲染的性能。当然也存在trade-off,如
每次发布前都要等待构建完成,以确保最终预览的是最新的代码内容
相信经过后期的不断使用,会将整个链路打磨的更加贴合用户体验!
团队介绍
我们是淘天集团—终端平台团队,专注打造业界领先的终端技术以及丝滑流畅的体验,通过持续的创新突破,赋能前台业务、连接数亿用户,提供极致高可靠的服务、极致高性能的架构和极致高效率的产品。
¤ 拓展阅读 ¤
3DXR技术 | 终端技术 | 音视频技术
服务端技术 | 技术质量 | 数据算法
相关文章:
搭建业务的性能优化指南
这是一篇搭建业务优化的心路历程,也是写给搭建业务的性能优化指南。 前言 直到今天,淘内的页面大多都迁移到了 SSR,从我们终端平台 - 搭建研发团队的视角看,业务大致可以分为两类 —— 搭建派 和 源码派。 这两者互不冲突…...
电脑提示报错“Directx error”怎么解决?是什么原因导致的?游戏软件提示“Directx error”错误的解决方案
DirectX Error(DX错误)通常指的是在使用基于DirectX技术的应用程序(尤其是游戏)时遇到的问题。这个问题可能由多种因素导致,以下是一些可能的原因及相应的解决方案: 可能的原因 DirectX版本不匹配&#x…...
Linux——自定义简单shell
shell 自定义shell目标普通命令和内建命令(补充) shell实现实现原理实现代码 自定义shell 目标 能处理普通命令能处理内建命令要能帮助我们理解内建命令/本地变量/环境变量这些概念理解shell的运行 普通命令和内建命令(补充) …...
基于matlab程序实现人脸识别
1.人脸识别流程 1.1.1基本原理 基于YCbCr颜色空间的肤色模型进行肤色分割。在YCbCr色彩空间内对肤色进行了建模发现,肤色聚类区域在Cb—Cr子平面上的投影将缩减,与中心区域显著不同。采用这种方法的图像分割已经能够较为精确的将人脸和非人脸分割开来。…...
Unity跨平台基本原理
Unity跨平台基本原理 Unity跨平台基本原理微软的.Net是什么微软做 .Net平台的目的如何实现的.Net跨语言?总结 .Net Framework.Net Framework的体系结构CLR总结 如何实现的跨平台?.Net Core.Net FrameWork 到 .Net CoreMonoMono如何实现跨平台总结如何实现…...
【前端开发】小程序无感登录验证
概述 封装的网络请求库,主要用于处理 API 请求并支持自动处理 token 过期 和 token 刷新,适用于需要身份验证的应用场景,特别是在移动端中。 主要功能 自动附加 Token 在每个请求中自动附加 Authorization 头部,使用存储的 acces…...
Flink常见面试题
1、Flink 的四大特征(基石) 2、Flink 中都有哪些 Source,哪些 Sink,哪些算子(方法) 预定义Source 基于本地集合的source(Collection-based-source) 基于文件的source(…...
spark同步mysql数据到sqlserver
使用Apache Spark将数据从MySQL同步到SQL Server是一个常见的ETL(Extract, Transform, Load)任务。这里提供一个基本的步骤指南,以及一些代码示例来帮助你完成这项工作。 ### 前提条件 1. **安装Spark**:确保你的环境中已经安装了…...
Python Web 开发:FastAPI 基本概念与应用
Python Web 开发:FastAPI 基本概念与应用 目录 ✨ 1. FastAPI 路由(定义请求路径)🚀 2. HTTP 请求方法(GET、POST、PUT、DELETE)🔑 3. 参数类型(路径参数、查询参数、请求体&#…...
Linux设置开启启动脚本
1.问题 每次启动虚拟机需要手动启动网络,不然没有enss33选项 需要启动 /mnt/hgfs/dft_shared/init_env/initaial_env.sh 文件 2.解决方案 2.1 修改/etc/rc.d/rc.local 文件 /etc/rc.d/rc.local 文件会在 Linux 系统各项服务都启动完毕之后再被运行。所以你想要…...
go并发设计模式runner模式
go并发设计模式runner模式 真正运行的程序不可能是单线程运行的,go语言中最值得骄傲的就是CSP模型了,可以说go语言是CSP模型的实现。 假设现在有一个程序需要实现,这个程序有以下要求: 程序可以在分配的时间内完成工作࿰…...
nn.RNN解析
以下是RNN的计算公式,t时刻的隐藏状态H(t)等于前一时刻隐藏状态H(t-1)乘以参数矩阵,再加t时刻的输入x(t)乘以参数矩阵,最后再通过激活函数,等到t时刻隐藏状态。 下图是输出input和初始化的隐藏状态,当参数batch_first True时候&…...
How to monitor Spring Boot apps with the AppDynamics Java Agent
本文介绍如何使用 AppDynamics Java 代理监视 Azure Spring Apps 中的 Spring Boot 应用程序。 使用 AppDynamics Java 代理可以: 监视应用程序使用环境变量配置 AppDynamics Java 代理 在 AppDynamics 仪表板中检查所有监视数据 How to monitor Spring Boot app…...
Linux学习笔记12 systemd的其他命令
前文已经介绍了systemd在系统初始化中起到的作用和服务的管理和配置。这里补充一下systemd的其他工具和系统进程的管理 前文 Linux学习笔记10 系统启动初始化,服务和进程管理(上)-CSDN博客 Linux学习笔记11 系统启动初始化,服务…...
NGO-CNN-BiGRU-Attention北方苍鹰算法优化卷积双向门控循环单元时间序列预测,含优化前后对比
NGO-CNN-BiGRU-Attention北方苍鹰算法优化卷积双向门控循环单元时间序列预测,含优化前后对比 目录 NGO-CNN-BiGRU-Attention北方苍鹰算法优化卷积双向门控循环单元时间序列预测,含优化前后对比预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介…...
【分布式】分布式缓存
一、什么是分布式缓存 分布式缓存是一种将缓存数据存储在多个节点上的缓存方案。它通过将数据分散存储在多个节点的内存中,以提高系统的读取性能、降低数据库压力和提高系统可扩展性。 二、分布式缓存的优点 优点明细提高性能:分布式缓存可以将数据缓…...
深度学习中的迁移学习:应用与实践
引言 在深度学习领域,迁移学习(Transfer Learning)是一个非常强大且日益流行的概念,它通过将从一个任务中学到的知识应用于另一个任务,能够显著加快模型训练速度并提高其泛化能力。迁移学习在许多实际应用中都得到了广…...
28.UE5实现对话系统
目录 1.对话结构的设计(重点) 2.NPC对话接口的实现 2.1创建类型为pawn的蓝图 2.2创建对话接口 3.对话组件的创建 4.对话的UI设计 4.1UI_对话内容 4.2UI_对话选项 4.3UI_对话选项框 5.对话组件的逻辑实现 通过组件蓝图,也就是下图中的…...
Redis中的分布式锁(步步为营)
分布式锁 概述 分布式锁指的是,所有服务中的所有线程都去获取同一把锁,但只有一个线程可以成功的获得锁,其他没有获得锁的线程必须全部等待,直到持有锁的线程释放锁。 分布式锁是可以跨越多个实例,多个进程的锁 分布…...
CentOS 7安装mysql+JDK+Tomcat完成流程
一.安装mysql 即使是新的linux服务器,也要先验证是否有mysql已经安装,如果有进行卸载原版本,一定要确认是否mysql已不再使用 原安装情况(直接执行命令即可) whereis mysql rpm -qa | grep -i mysql rpm -e perl-DBD-M…...
C++笔记之不同框架中事件循环的核心函数:io_run()、ros_spin()、app_exec()
C笔记之不同框架中事件循环的核心函数:io_run()、ros_spin()、app_exec() code review! 参考笔记 1.qt-C笔记之使用QtConcurrent异步地执行槽函数中的内容,使其不阻塞主界面 2.qt-C笔记之QThread使用 3.qt-C笔记之多线程架构模式:事件信号监…...
C++异常处理
目录 一、异常的概念 二、异常的使用 (1)异常的抛出和捕获 (2)异常的重新抛出 (3)异常安全 (4)异常规范 三、自定义异常体系 四、c标注异常体系 五、异常的优缺点 在之前我们…...
【数据结构】哈希 ---万字详解
unordered系列关联式容器 在C98中,STL提供了底层为红黑树结构的一系列关联式容器,在查询时效率可达到log_2 N,即最差情况下需要比较红黑树的高度次,当树中的节点非常多时,查询效率也不理想。最好 的查询是,…...
4399大数据面试题及参考答案(数据分析和数据开发)
对数据分析的理解 数据分析是一个从数据中提取有价值信息以支持决策的过程。它涵盖了数据收集、清洗、转换、建模和可视化等多个环节。 首先,数据收集是基础。这包括从各种数据源获取数据,例如数据库、文件系统、网络接口等。这些数据源可以是结构化的数据,如关系型数据库中…...
快速理解倒排索引在ElasticSearch中的作用
一.基础概念 定义: 倒排索引是一种数据结构,用来加速文本数据的搜索和检索,和传统的索引方式不同,倒排索引会被每个词汇项与包含该词汇项的文档关联起来,从而去实现快速的全文检索。 举例: 在传统的全文…...
C++趣味编程玩转物联网:基于树莓派Pico控制无源蜂鸣器-实现音符与旋律的结合
无源蜂鸣器是一种多功能的声音输出设备,与有源蜂鸣器相比,它能够通过不同频率的方波生成丰富多样的音调。本项目使用树莓派Pico开发板,通过编程控制无源蜂鸣器播放经典旋律《归来有风》。本文将详细介绍项目实现中的硬件连接、C++代码解析,以及无源蜂鸣器的工作原理。 一、…...
《RuoYi基于SpringBoot+Vue前后端分离的Java快速开发框架学习》系列博客_Part4_三模态融合
系列博客目录 文章目录 系列博客目录目标Step1:之前工作形成子组件Step2:弥补缺失的文本子组件,同时举例如何子组件向父组件传数据Step3:后端代码需要根据上传的文件传给python服务器Step4:python服务器进行分析 目标 实现三模态融合,将文本、图片、音频…...
springboot365高校疫情防控web系统(论文+源码)_kaic
毕 业 设 计(论 文) 题目:高校疫情防控的设计与实现 摘 要 互联网发展至今,无论是其理论还是技术都已经成熟,而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播,搭配信息管理工具可以很好地为…...
STM32 USART串口数据包
单片机学习! 目录 前言 一、数据包 二、HEX数据包 三、文本数据包 四、HEX数据包和文本数据包优缺点 4.1 HEX数据包 4.2 文本数据包 五、HEX数据包接收 六、文本数据包接收 总结 前言 本文介绍了串口数据包收发的思路和流程。 一、数据包 数据包的作用是把一个个单独…...
【LC】3232. 判断是否可以赢得数字游戏
题目描述: 给你一个 正整数 数组 nums。 Alice 和 Bob 正在玩游戏。在游戏中,Alice 可以从 nums 中选择所有个位数 或 所有两位数,剩余的数字归 Bob 所有。如果 Alice 所选数字之和 严格大于 Bob 的数字之和,则 Alice 获胜。如果…...
动态网站制作教稿/windows优化大师自动安装
Python 的字符串内建函数 Python 的字符串常用内建函数如下: 序号方法描述1capitalize()将字符串的第一个字符转换为大写2center(width, fillchar)返回一个指定的宽度 width 居中的字符串,fillchar 为填充的字符,默认为空格。3count(str, b…...
wordpress日志元代码/新东方考研培训机构官网
本系列文章是把作者刚接触和学习Linux时候的实操记录分享出来,内容主要包括Linux入门的一些理论概念知识、Web程序、mysql数据库的简单安装部署,希望能够帮到一些初学者,少走一些弯路。 注意: Linux下区分大小写; Linu…...
外贸网站建设制作公司/谷歌搜图
这篇文章是一系列文章的第三篇。 如果还没有阅读过第一篇请从这里开始。 第二篇文章介绍了域模型主要概念的定义。 这是第三篇, 中间因为过年隔的时间较长,见谅。 这里Persona和scenario部分的例子用英文给出,主要是为了AliExpress的域模型虚…...
网站建设显示危险/杨谦教授编的营销课程
#1,定义:#随着功能的增加会出现更多的视图,可能之前配置的正则表达式不够准确,于是就要修改正则表达式,但是正则表达式一旦修改了,之前所有对应的超链接都要修改,真是一件麻烦的事情,而且可能还…...
网站建设服务有哪些内容/百度云网页版入口
MySQL数据库优化处理实现千万级快速分页分析,来看下吧。数据表 collect ( id, title ,info ,vtype) 就这4个字段,其中 title 用定长,info 用text, id 是逐渐,vtype是tinyint,vtype是索引。这是一个基本的新闻系统的简单…...
哪个网站有收藏加购做积分任务/有哪些搜索引擎网站
Hard Disk Sentinel Pro(硬盘哨兵) 官方中文注册版是一个硬盘监控工具,可以用来鉴别可能的硬盘问题、性能退化或者硬盘错误。硬盘哨兵是一款硬盘/ SSD的监测和分析工具。它的目标是寻找,测试,诊断和修复磁盘驱动器的问题,报告和显…...