找手机游戏就上绿色软吧 专业手游媒体门户网站!

游戏更新 | 安卓游戏 | 苹果游戏 | 推荐游戏 | 软件更新 | 文章更新 | 热门文章 | 推荐文章

ssg(ssg输卵管手术)

时间:2024-08-08 09:42:36    编辑:azu

背景

所以针对业务的变化,运营侧迫切希望目前软广外投的页面打开速度得到优化,以及解决会场失效等一些高频问题,同时与现有的投放广告系统做充分的融合,减少中间无意义的 Gap。

项目收益

ssg

Lighthouse 跑分对比:慢速的情况下从之前的 56 分提高到 79 分,网速较快的情况下,从之前的 87 分 提高到 98 分。

真实数据收益:老版的 FCP_Rate 平均在 35% 左右,新版上线以来,FCP_Rate 平均在 80% 左右。提高了 45pp 左右。

技术选型

左右滑动查看外投软广的C端页面

目前外投模板都是采用 SSR 去做服务端渲染的,但是 SSR 渲染的整个流程如下图所示:

SSR 把数据拉取放到了服务端,因为离数据源比较近,数据拉取的速度会快一点。但这也不是完全没有副作用,因为需要在服务端等待数据就绪,TTFB(Time to First Byte) 相比 CSR 会长一点。

SSR 只是给我们准备好了初始的数据和 HTML,实际上和 CSR 一样,我们还是需要加载完整的客户端程序,然后在浏览器端重新渲染一遍(更专业的说是 Hydration 水合/注水),才能让 DOM 有交互能力。

也就是说,FCP(First Contentful Paint) 相比 CSR 提前了,但是 TTI(Time to Interactive) 并没有太多差别。只是用户可以更快地看到内容了。

我们生成环境 SSR 生成的 HTML 资源会被 CDN 缓存,也就是说当 CDN 有缓存的,上述图片中的流程是不会再走一遍的。

通过分析了目前得物外投的 C 端页面,有下列几点:重玩法和体验,而且本身就是投在短视频平台上的广告,大部分都是拉新,所以对于站外新用户可能就点击一次,后续再也不会点了,所以优化第一次的秒开体验还是很有必要的。运营对于模板配置的改动频率较低,不是高频操作。如果模板是高频改动,那么 SSG 的技术方案可能就不是特别适合。因为模板需要一直重新构建,这时候不如采用 SSR,保持新鲜度。外投页面对于接口请求的依赖十分弱。

根据这三点判断外投软广十分符合 SSG 的技术体系,可以节约第一次服务端拉取数据的时间,其实这部分的时间,反正也是生成 HTML,返回给客户端。其实在运营投出广告之前,模板已经构建完成了,而在构建的时候就直接生成好了所谓的静态外投模板页面。这种方式其实就做 SSG (静态生成)。

看下面这张图或许你就能明白 SSG 和 SSR 的区别:

从图中能明显看出来 HTML 是在构建的时候生成的,而不是在访问这个 HTML,服务器在动态生成。这就是两者之间的差距。所以对于第一次访问的,可以看下面这张图:

SSG 等待服务响应的时间是明显低于 SSR 的。看下面视频就可以明显感觉到差距。

,时长00:02

ssg(ssg输卵管手术)

从生成的内容来说都是 HTML,这一点没什么区别。但是从投放的业务来说,我们要静态化的页面较多,所以我们需要一个专门的服务帮我们根据模板 ID 生成各种静态 HTML。

ssg(ssg输卵管手术)

在静态资源更新上,假设这么一个场景,线上预渲染的 HTML 有问题我们需要更新,如果 1-2 个页面没啥问题,我们可以重新构建一下,更新 HTML 缓存,如果有几千或者是上万个,SPA 预渲染估计也不太适合。而且频繁的发版、构建对于线上的稳定性也是一个不小的挑战。

在增量更新上,SPA 预渲染骨架是没法支持的,目前社区的一些插件实现原理都类似,都是根据特定 SPA 指定的路由通过 WebPack 或者是 Vite 去进行预构建然后生成对应的 HTML,还需要在nginx上配置特定路由转发, 不然走index.html 不够纯粹,这一点也 pass 掉。

基于上面的一些原因,选择了 Next 去做 SSG 框架支持。生态完善又可以持续更新,可以简化一部分开发工作。

优点的话不用多说,相比 SSR,因为不需要服务端运行时进行数据拉取,TTFB/FCP 等都会提前。

在实际过程中还遇到下面几个问题:针对模板更新的时候,如何去进行静态页面缓存更新?对于没有静态生成的页面,我们还能访问吗?

针对上述问题我们在技术方案里引入 ISR (增量静态生成)。

如下图所示:

ISR 是 SSG 的升级版,解决 SSG 内容变更的问题。

ISR 依旧会在构建时预渲染页面,但是这里多出了一个服务端运行时,运行时会按照一定的过期/刷新策略(通常会使用 stale-while-revalidate )来重新生成页面。

关于这部分内容,本篇文章不做详细介绍,只是引出关键概念,看到这里如果觉得写的不错的,可以给作者点个赞哟!

页面性能优化

关于性能优化市面上有很多文章,这里不做过多叙述,本篇文章只针对得物外投广告业务,探索符合外投广告优化的性能最佳实践。

自定义文档行为

CSS 内联

这里我们做的第一个行为就是 CSS 内联 通过继承 Head 组件,重对应的子方法。

背景大图优化

这里的话由于背景图是默认静态生成的时候已经是内联了,这时候是没有 Webp 的,如果通过 React State 去控制背景图的 Webp 展示的话,会导致页面闪一下,用户体验不好,但我们又想优化背景图的体积,于是我们在自定义 Doucument 里面加了一个原生 Dom 操作如图所示,支持 Webp 的优化成 Webp,不支持的优化成 jpeg 格式。

足足差了 100KB 左右。

打包优化

SWC

Nezha 是采用 Next 12 版本系列,我们新的轻量级落地页采用 Next 13,有一个很重要的特点使用了 SWC 而不是 Babel。

我们选择使用 SWC 进行开发有以下几个原因:可扩展性:使用 SWC 可以作为 Next.js 中的 Crate,而不必分叉库或绕过设计限制。性能:通过切换到 SWC,我们在 Next.js 中实现了大约 3 倍更快的快速刷新和 5 倍更快的构建速度,还有更多的优化空间正在进行中。WebAssembly:Rust 对 WASM 的支持对于支持所有可能的平台并将 Next.js 开发带到任何地方至关重要。社区:Rust 的社区和生态系统是惊人的,而且还在不断壮大。这里还有一个很重要的原因就是后续我们会新增 ISR,也就是服务端不存在的静态模板 ID 资源的时候,我们通过接口触发 Node 层进行构建,构建的速度越快,用户等待的时间也越少。所以更换语法转换还是有很有必要的,对于后期 ISR 是非常有必要的。

具体了解 SWC 可以看这个网站:https://swc.rs/

组件库按需加载

Babel 情况下的按需构建我们都是通过安装 babel-plugin-import 通过如下配置:

但是新版本已经内置了这种能力。

可以在 next.config.js 中这样配置,具体的详细配置可以看这个链接:https://nextjs.org/docs/architecture/nextjs-compiler#modularize-imports

首屏资源动态化

抽取外投模板通用的组件,比如投放 Banner 五要素、唤端组件。不在首屏资源的组件,延迟加载。

抽取了动态组件,Webpack 打包的时候,对于动态组件相关的资源会打包到一起,不会打包到主 JS 里面,可以很好地提高 CDN 缓存利用率,防止因为一些简单的改动,影响整个 JS 的 Hash。

这里用到了 next/dynamic ,具体的链接可以看这个: https://nextjs.org/docs/app/building-your-application/optimizing/lazy-loading#nextdynamic

但是无论是那种方式,我们线上最终访问的资源都是在 OSS 上的。

所以我们需要在 Webpack 配置下 PublicPath:

通过上面这个步骤首屏资源减少几十 KB。

图片资源优化

造成部分图片资源没有应用到 Webp 所以这里重新梳理了这块逻辑,重新封装了。

Http2.0下更优雅的拆包针对 node_modules 资源:可以将 node_modules 模块打包成单独文件(通过 cacheGroups 实现),防止业务代码的变更影响 NPM 包缓存,同时建议通过 maxSize 设定阈值,防止 Vendor 包体过大。由于我们的资源有专门的静态加速域名且支持 Http2.0,这里将每一个 NPM 包都打包成单独文件。针对业务代码:设置 common 分组,通过 minChunks 配置项将使用率较高的资源合并为 Common 资源。首屏用不上的代码,尽量以异步方式引入,这里上面 Dynamic 已经做了拆包。设置 optimization.runtimeChunk 为 True,将运行时代码拆分为独立资源,这里 Next 也已经内置了。

所以我们的一个优化策略就是将 @du @growth 的 NPM 包进行拆分。

第三方包体积优化

由于唤端 App 和落地页都会进行埋点上报,原有的逻辑是 Call-App 内部也会再去加载神策埋点 JS,但是在外投落地页展示的时候其实已经加载过,导致神策包体积重复加载。

代码如下:

统一请求库:统一去掉 Axios 统一用 Fetch 去做请求,减少了 JS 体积 20KB+。保持项目请求库技术栈统一,这里不需要担心 Fetch 的兼容性问题,Next 13 默认做了 Fecth 的 JS 垫片。

上线前的准备

一共收集了如下几个问题:

其中运营侧有一个很强烈的需求,就是强烈要求新版落地转盘速度变快,觉得用户的耐心值比较低,本身就是广告了,点进去运转的慢的话,用户会直接流失。

,时长00:03

ssg(ssg输卵管手术)

得物页面级别的灰度AB

轻量版本的落地页做出来了,贸然去投外投广告本身是不合适的。所以这里针对同一个外投软广链接,去做 AB 测试,排除用户的群体、包括投放的策略、以及达人的量级等等这些外在因素的影响,去分析 AB 情况下的新版和老版的性能指标。我们验证了新的轻量落地页,无论是在业务还是性能上都有显著提升,那么我们肯定需要大规模灰度,对于线上已经投放的广告,如何进行无缝灰度?针对这一点,运营对我们前端提出的要求很简单,由于线上已经创建了大量的广告计划,运营不可能手动一个个去改链接,工作量很大。所以核心点就是在不改线上链接的前提下,线上用户访问的是我们的新的落地页资源。

全量的灰度收益

性能前后对比

业务前后对比

ssg(ssg输卵管手术)

推全之后的数据:CVR 和真实唤端成功率均显著正向,预计提高 CVR 转换 2pp 左右。

灰度方案

条件源站

结合具体的规则引擎配置比如我们配置的是参数中含有 _launch_ 就会回源到B.dewu.com。

ES

目前条件源站配置好了,线上的所有 CDN-A.com 的链接如何自动的大批量都加上 _launch_ 参数呢?那就需要 ES 登场了。

边缘脚本(EdgeScript,简称 ES)。CDN 节点网关会根据你在控制台上设置的标准配置、边缘脚本规则对请求进行处理。ES 规则的执行位置可以是请求处理开始或者请求处理结尾。所以 ES 的执行配置,可以在请求前,也可以在请求后。这里的配置顺讯会决定条件源站和 ES 的应用顺讯。如下图所示:

结合上面的图,整体的流程已经很明显了,客户端请求先回到 ES ,ES 里面我们会写下灰度匹配脚本。

代码这里就不放了,感兴趣的可以去阿里云 ES 脚本去学习一下。

大体的意思就是匹配 URL 含有某些会场 ID,匹配上了加上 &_launch_=1&esab=1 这两个参数。

然后在经过条件源站,就可以回源到我们新的轻量落地页了。这里解释一下参数上加 Esab 其实主要是一个锁,防止请求在 ES 死循环。

rand_hit(20) 是 ES 语法提供的随机函数,可以进行站外简单的 AB 分流,也就是线上的链接是有概率进入 ES 并且触发条件源站回源。 这里做的比较简单,其实还可以配上 Cooike,达到命中过灰度了,就一直是灰度的链接。站外软广这里不存在登录态,和产品们讨论,问题不是很大。

架构图

流程图上有一块兜底的考虑:万一有配错的会场,回源到 B.com ,我们会进行反向代理,会直接代理到 A.com 确保会场的正确显示。

灰度节奏白名单生产测试,ES 脚本匹配 ID 符合上面 7 个模板 ID,然后再加一个白名单测试参数,先真实广告测试唤端对应的场景是否正确。白名单测试完毕之后,去掉白名单测试参数之后 ES 分设备进行灰度,先 iOS 后再安卓(iOS 的流量比安卓的小 )还是先预发验证,预发验证结束在应用生产正式的 ES。这里灰度的会场 ID 还是逐步灰度观察数据,每一次灰度的会场 ID 都是先 iOS 再安卓进行测试,避免小流量发现不了问题。

灰度时间安排DAY1 上午 10 点 iOS 灰度百分比 50%。DAY2 早上灰度当前模板,安卓 10点。DAY4 上午 10 点 iOS 灰度 10% ,观察 2 小时有问题随时切走。 DAY4 晚上 9 点灰度 30% 。DAY5 上午 10 点灰度安卓 10%,晚上 9 点灰度 30%。Day 6 上午 10 点 iOS 灰度 10%,观察 2 小时有问题随时切走。DAY6 晚上9点灰度30%。DAY7 上午 10 点灰度安卓 10%,晚上 9 点 灰度安卓 30%。

推全的灰度安排就是上面所有会场 ID 不分渠道进行灰度按照 10% 20% 50% 65% 80% 100% 逐渐切入。

十一

稳定性

我们做了下面这几件事:SLS 监控告警监控实时唤端成功率,有没有出现同比大幅度下跌。

代理失败兜底监控。

拉新大盘监控。Error 监控报错。

十二

总结

作者:Fly

来源:微信公众号:得物技术

出处:https://mp.weixin.qq.com/s/zX_dJRMrKtjOZASgSSPKXA

相关游戏
最新游戏

玩家评论