嵌入式css-后端性能优化:当页面渲染满足边缘估计时

阿里妹导读:目前常见的几种后端性能优化方案仍然不可避免地存在一些缺陷。 基于ESI(EdgeSideInclude),本文提出了一种新的优化思路:边缘流式渲染解决方案(ESR),利用CDN的边缘估计能力,以流的方式返回静态内容和动态内容。 给用户。

文末福利:下载《覆盖全端业务的大后端技术》电子书。

背景

对于网页来说,第一跳场景(如SEO、付费引流)的性能普遍比第二跳场景差。 原因有很多,主要是首跳用户在连接复用和本地资源缓存方面有很大的劣势。 在第一个跳转的场景中,端部的很多优化方法(预加载、预执行、预渲染等)都未能实现。

在客户端缓存能力难以使用的情况下,利用CDN贴近用户的优势,可以结合缓存做一些性能优化。

思路

想法一:SSR

出于性能优化的考虑,我们通常通过服务器端渲染(SSR)将首屏动态内容直接输出到服务器。

这些方法的优点是页面的主要内容可以包含在一次html返回中,而不需要浏览器两次请求socket然后用js渲染。 然而,这些方法有明显的缺点。 对于服务器距离较远或服务器处理时间较长的场景,用户会听到较长时间的蓝屏声。 而且虽然html返回完成了,但是用户并不会立即看到内容,页面需要加载后加载的js、css等资源才能听到内容。

思路二:CSR+CDN

为了减少死时间,可以考虑利用CDN的边缘缓存能力,将页面HTML直接缓存在CDN节点上。 但对于大多数场景,页面的主要内容是动态的或个性化的。 将所有html内容缓存在CDN上对业务影响很大,很少有场景可以接受。 那么换一种思路,只在cdn上缓存html的静态部分? 虽然这个想法也是很常见的操作,即将HTML的静态帧部分缓存在CDN上,让用户可以快速听到部分内容,然后在客户端发起异步请求获取动态内容并渲染它(CSR)。 CSR+CDN模式下的渲染时序图如下:

这些方法的好处是,页面的静态框架缓存在CDN上,用户可以快速看到页面框架的内容,减少了等待崩溃的恐惧。 缺点是完整的页面内容需要再次执行js,将异步socket拉回来再渲染。 最终显示有意义的动态内容的时间晚于SSR。

想法3:ESI

CSR+CDN的方式很好地解决了死区时间问题,但带来了动态内容显示的延迟。 出现这个问题的原因是我们把页面的动态内容和静态内容分成了两个阶段,而且是串行的,但是js的下载和执行也是穿插在串行过程中的。 CDN上动态内容和静态内容的整合有哪些方式?

ESI(EdgeSideInclude)给了我们一个好主意。 ESI最初是CDN服务提供商提出的规范。 您可以在html标签中添加特定的动态标签,将页面的静态内容缓存在CDN上,动态内容可以自由组装。 ESI的渲染时序图如下:

嵌入式css_嵌入式css怎么写_嵌入式css语法结构

这个解决方案看起来非常好。 静态部分可以缓存在CDN上,动态部分会在用户请求时动态请求并拼接。 但最关键的问题是,在ESI模式下,最终返回给用户的第一个字节仍然要等到所有动态内容都已经在CDN上获取并拼接完毕。 也就是说,死区时间没有减少,但是CDN和服务器之间的内容传输量减少了,性能优化的利润很小。 最终的疗效和SSR没有太大区别。

虽然ESI的功效没有达到我们的预期,但它给了我们一个很好的思考方向。 如果可以改变ESI,使得静态内容先返回,动态内容被CDN节点获取后返回到页面,那么可以保证死区时间很短,但是动态的返回内容不会有延迟。 如果想要达到类似流式ESI的疗效,需要能够对CDN上的请求进行细粒度的操作,以及流式返回。 CDN节点能支持这么复杂的操作吗? 答案是肯定的:边缘估计。 我们可以在CDN上做类似浏览器的serviceworker的操作,并且可以灵活地对请求和响应进行编程。

基于边缘估计的能力,我们有了一个新的选择:边缘流式渲染解决方案(ESR)。 计划详情如下。

渲染过程

该方案的核心思想是利用边缘估计的能力,将静态内容和动态内容以流式的方式依次返回给用户。 与服务器相比,CDN节点距离用户更近,网络延迟更短。 在CDN节点上嵌入式css,先将页面可缓存的静态部分快速返回给用户,同时在CDN节点上发起动态部分内容请求,响应后将动态内容返回给用户静态部分的流动。 最终页面渲染的时序图如下:

从上图可以看出,CDN边缘节点可以快速返回第一个字节和页面的静态内容,然后动态内容由CDN发起到服务器并流回给用户。 该方案具有以下特点:

演示比较

目前在alicdn的搜索主页面已经做了一个demo()。 下面是不同网络下原页面的加载对比(通过charles的networkthrottle配置限速):

无限速度(无线网络)

限速4G

限速3g

从前面的结果可以看出,当网络速度较慢时,通过CDN流式传输的最终主元素比原始ssr更早下来。 这也与实际结论相符。 由于网络越慢,静态资源的加载时间越慢,相应的浏览器较早加载静态资源所带来的疗效就越显着。 另外,无论网络状况如何,cdn流式渲染方式的崩溃时间都要短得多。

嵌入式css_嵌入式css语法结构_嵌入式css怎么写

整体结构

架构图

边缘流式渲染

1 个模板

模板是类似于 ESI 块的句型。 基于模板,将需要动态请求的内容提取出来,将可以静态返回的内容分离出来并进行缓存。 所以模板本质上定义了页面的动态和静态内容。

在流式渲染过程中,页面模板会从上到下进行解析。 如果是静态内容,则直接返回给用户。 如果遇到动态内容,则会执行动态内容的获取逻辑。 整个过程中可能会有交替的静态和动态内容。

设计了以下类型的模板。

1) 原始 HTML

这些模板对现有业务的干扰最小。 您只需要在现有SSR页面的内容中添加某些标签即可声明页面的动态部分:

<html>  <head>    <linkrel="stylesheet"type="text/css"href="index.css">    <scriptsrc="index.js"></script><metaname="esr-version"content="0.0.1"/>  </head>  <body>    <div>staic content....</div>    <scripttype="esr/snippet/start"esr-id="111"content="SLICE"></script>    <div>dynamic content1....</div>    <scripttype="esr/snippet/end"></script>    <div>staic content....</div>    <scripttype="esr/snippet/start"esr-id="222"content="https://test.alibaba.com/snippet/222"></script>    <divid="222">              dynamic content2....    </div>    <scripttype="esr/snippet/end"></script>  </body></html>

2)静态模板(暂时无关联实际场景)

这些模板需要单独发送到cdn(如果以后渲染层连接了FASS网段和SSR,可以在这里将模板内容分享给他们,但是在发布模板时手动同步到cdn)工作流程,同时清除CDN上的缓存)。 动态内容有两种呈现方法。 一种是前端SSR下载的动态html片段,另一种是前端提供的动态数据,动态html片段由边缘节点渲染。

使用SSR动态html片段的好处是不需要在边缘渲染html模板,开发者也不需要编写两套模板逻辑。 缺点是前端需要具备SSR能力,动态内容传输量比较大。

使用边缘节点渲染动态html内容的优点是前端只需提供动态数据,不需要SSR能力(但后端必须有CSR能力才能降级),且传输的动态内容量小。 切入点是在边缘节点上流式透传动态内容比较困难,需要等待完整下载到边缘节点,处理完后再返回给用户。

<html>  <head>    <linkrel="stylesheet"type="text/css"href="index.css">    <scriptsrc="index.js"></script>  </head>  <body>    <div>staic content....</div>    <scripttype="esr/block"esr-id="111"content="https://test.alibaba.com/snippet/111"></script>    <div>staic content....</div>    <scripttype="esr/template"esr-id="222"content="https://test.alibaba.com/api/data">      <div>        {$data.name}      </div>    </script>  </body></html>

2 静态内容解读

静态内容来自模板。 对于不同的模板类型,获取静态内容的形式是不同的。 对于“原始HTML”类型的模板,会根据html注释标签从第一次动态请求返回的完整HTML中提取静态内容,并存储在边缘缓存中。 对于“静态模板”,模板文件将从 CDN 中拉取并存储在边缘缓存中。 静态内容具有缓存过期时间和版本号。

模板开头的静态内容直接返回给用户作为响应。 后续的静态内容(如html、body的结束标签)有两种形式:

3 动态内容

动态内容是在渲染过程中,当解析到需要动态获取的区域时,就会在边缘发起动态内容请求。 动态内容支持以动态加速的方式到达服务器(源服务器)。 连续节点与前端动态内容交互嵌入式css,可分为三种形式:

用户与边缘节点之间的动态内容交互可以分为两种方式:

边缘路由

路由配置:

{  version'0.0.1'//配置版本号  origin: 'us-proxy.alibaba.com',  host: 'edge.alibaba.com'  pages: [  {    pageName: 'seo', //页面名称标识    match: '/abc/efg/.*', //页面path匹配正则字符串    renderConf: {       //渲染配置      renderType: 'ESR', //边缘渲染      templateType: 'FULL_HTML', //模板类型:将SSR出的完整html作为模板      dynamicMode: 'WATER_FALL|ASYNC_INSERT', // 动态内容append返回方式:瀑布流返回|异步填坑(innerHTML)      templateUrl: ''// 模板url           }   },   {     pageName: 'seo',     match: '/abc/efg/.*',     renderConf: {         renderType: 'ESR'        templateType: 'STATIC', // 静态模板,可通过cdn url获取        dynamicMode: 'WATER_FALL|ASYNC_INSERT', // 动态内容append返回方式:瀑布流返回|异步填坑(innerHTML)        templateUrl: 'https://g.alicdn.com/@g/xxx.html'          }   },   {     pageName: 'jump',     match: '/jump/.*',     renderConf: {        renderType: 'REDIRECT_302', // 302跳转        rewriteUrl: 'https://jump'             }     },    {      pageName: 'proxy',      match: '/proxy/.*',      renderConf: {         renderType: 'PROXY_PASS', // 301跳转         rewriteUrl: 'https://proxypassurl'             }    }  ]}

路由可以被认为是边缘估计的入口点。 只有路由配置中的页面才能经过相应的渲染过程。 否则,页面将直接返回源以获取页面的完整内容。 里面的json就是当前设计的路由配置文件。 配置文件最终会通过叠加发布的方式,以静态资源的方式发送到assetscdn。 同时为了支持灰度配置发布,上线会有灰度版和完整版两种配置,在路由代码中配置固定比例一栏,加载灰度版或完整版的配置。

目前路由中设计了三种渲染模式,分别是流式渲染、重定向和反向代理。 重定向和反向代理的配置比较简单,与nginx配置类似,只需要提及目标url即可。

稳定

势力范围控制

异常处理

灰度

1)边缘估计代码灰度

平台本身支持边缘估计代码的灰度发布。

2)路由配置灰度

嵌入式css语法结构_嵌入式css_嵌入式css怎么写

在边缘估计代码中,按照固定比例加载灰度版本和即将发布的版本的两个配置url。 灰度发布时只发布灰度配置,全量发布时发布全量配置。 发布时清除 CDN 缓存。

3)页面内容灰度

为灰度页面指定一个特殊的模板版本号。 如果遇到这个版本号,则不会进行边缘渲染。

顺利释放

在前后端分离的开发模式下,有一个通病:发布不顺畅。 当页面的静态资源(js、css)没有与前端一起释放时,可能会导致前端返回的HTML内容与后端的js、css内容不匹配。 如果三者之间的不匹配没有以兼容的方式处理,可能会出现样式混乱或者文档选择器找不到元素的问题。

解决平滑发布的一种方法是在前后端需求同时发生变化时使代码兼容。 这样,连续发帖就不会影响页面的可用性。

另一种形式是按版本号。 前端页面自动配置版本号。 当出现不兼容发布时,先释放后端资源,然后前端自动更改版本号,保证只有已经成功发布的前端机器才会引用新版本的静态资源在 HTML 中。

在批量发布和测试发布场景中,发布顺利的问题似乎仍然存在。 只是在ESR场景下,我们将静态部分缓存在CDN上,这样会导致前后端不一致的可能性更大。 为了解决这个问题,需要相应业务的开发者在发布时进行风险识别。 如果已经做好兼容,则无需做特殊处理。 但如果不兼容,则需要更改页面模板的版本号。 新版本的动态内容在遇到与版本号不匹配的静态内容时会放弃这种流式渲染,从而保证页面不显示动态内容和静态内容。 兼容性问题。

边缘CDN服务提供商

目前主要CDN服务商支持边缘估计如下:

阿利克丁

阿卡迈

云票价

登陆计划

我们将在典型的第一跳场景中进行实验。 目前已经推出灰度版。 通过新加坡的pagetest测试,有程序和无程序的对比可以看出优化效果:

ttfb 降低 1s

死区时间减少1s

嵌入式css怎么写_嵌入式css语法结构_嵌入式css

核心内容显示时间减少500ms

网页测试对比结果:

18f13985a6403b911beb7f94d6d1a1940fc13

参考

[1] 云票价边缘工作者

()

[2] 2016年——网络流年

()

[3]ESI()

[4] AsyncFragments:重新发现ProgressiveHTMLRenderingwithMarko()

[5] 失落的渐进式 HTML 渲染艺术

()

福利来了

免费下载

“覆盖全端业务的大后端技术”

优酷后端业务场景众多,技术栈汹涌,对后端工程能力的要求越来越高。 阿里文娱详细阐述了团队遇到的技术挑战以及解决过程。 希望通过解决方案的推演揭茧,探究优酷后端团队在支撑业务过程中的技术思维和沉淀,给读者带来一些启发。