Day25 X ESR: Rendering On The Edge

https://ithelp.ithome.com.tw/upload/images/20211010/20113277e2qr4qq6qt.png

基本上 CDN 是现在的 Web 应用不可或缺的技术,当对被 CDN 加速过的域名发出请求时,CDN 会自动将 request 导到地理位置离使用者较近或是流量较不吃紧的 edge server 来处理,这在 Day20 时有详细介绍过。

我以前总是把 CDN 单纯看作是一种分散式的快取服务器,没有想过它还能做到什麽很酷炫的事情,直到之前研究了一下 AWS 的 Lambda@Edge 才开启了自己的视野。原来 CDN 的 edge server 还能用来执行 serverless 的 function,因此可以做到例如修改 request 与 response 的 header、动态产生内容或是在 edge server 这层做 access control 等等事情。有趣的是不只 AWS 的 Lambda@Edge,目前越来越多的 cloud provider 推出了可以在 edge server 进行运算或执行 serverless function 的服务,例如最近蛮红的 Cloudflare Workers 就是有名的 CDN provider Cloudflare 推出的服务。

如果对於 CDN edge server 可以跑 serverless function 或可以做到什麽事情一点概念也没有的朋友,可以参考我之前的文章 - Coding Your CDN ! 充满惊奇的 AWS Lambda@Edge

回过头看今天想要讨论的主题,谈到现阶段的前端开发架构,基本上都会得到这三个名词:CSR、SSR、SSG。尤其像是 Next.js 或是 Nuxt.js 这些最近很流行的 SSR 框架更提供我们可以做到根据 page level 将以上三种架构混合使用的方式,这些也正是昨天介绍过的。

等等,CDN edge server 跟前端架构又有什麽关系…?还有怎麽一直在讲前几天的内容,是不是想骗读者的时间?

在 CDN Edge Server 可以做的事越来越多後,一种新的架构观念被提出了 — Edge Side Rendering (ESR,也有一种说法是 Edge Slice Re-Rendering)。
ESR 这个概念老实说还不普及,虽然已经有一些 CDN Provider 或提供 SaaS 服务的企业有推出一些 ESR 的解决方案,但还是相对不成熟,或是没办法跟大多数开发者在使用的热门前端框架例如 Next.js 或 Nuxt.js 完美结合。不过我个人还是非常期待它的未来发展,也一直深信未来 serverless 相关技术会大大改变技术开发的生态系,因此才会在这个技术还不成熟的状况下就选择分享它的概念,如果看到这里你还有兴趣,就一起来探索这个新的概念吧!

So, what are the problems with the original architectures ?

一个架构概念的诞生照理来说就是为了解决原有架构存在的一些问题,所以在介绍 ESR 之前我们先来看看现有架构存在的一些问题。

Client Side Rendering (CSR)

CSR 最为人诟病的当然还是 SEO 的问题,不过这个问题随着搜寻引擎的演进也许在未来有机会被解决掉。从上面这张图可以看到 CSR 常常会搭配 CDN 来快取静态的 HTML 档案,当使用者发出请求时,如果 CDN Cache 里有资料就可以快速回传静态的 HTML 给使用者,再透过在 client 端发起非同步的请求来抓取动态的资料并渲染到页面上。先撇开 SEO 不谈,这个架构可能会有的问题是在渲染内容到页面之前需要先下载 JavaScript bundle 再发起 Ajax 请求,因此 First Meaningful Paint 在 CSR 上通常会比较久,如果 bundle size 很肥大又没有做好 code splitting,页面完成渲染的时间又会再加长。

SSR With Client Side Hydration

这边指的不是传统完全靠 server side 产生页面的 SSR,而是 Isomorphic JavaScript 这种在後端产生 HTML 并带入基本资料,再到前端做 Rehydrate ,由 CSR 接管页面後续渲染的混合式 SSR。我想会对这篇文章有兴趣的读者应该都了解这种 SSR 的基本概念了,所以就不再赘述。这种架构会产生哪些问题呢?虽然采用这种架构相对於 CSR 因为一开始页面就会有内容,所以会有比较好的 FCP (First Contentful Paint),但是因为要等到 JS bundle 加载完成并在 client side hydrate 过後页面才能够互动,因此 TTI (Time to Interactive)会被拉长,有可能导致使用者已经可以看到页面内容,却没办法与页面产生互动的状况。另外因为每次都要在 server 产生内容,SSR 的 Time To First Byte 也会稍微慢一点。

因为 SSR 是透过每次请求都到 origin sevrer 去动态生成一次内容,当流量一大也会对这个 renderer server 产生一定的负担。再者如果这个 renderer server 在地理位置上没有那麽接近使用者,也会对传输过程产生一些延迟。最後因为某些经过 SSR 动态产生的页面内容可能常常会需要改变,所以并没有那麽适合放到 CDN 快取里,也就没办法享受到 CDN 的好处。(依照专案需求,有时候还是可以把一些不常变动的页面的 SSR 执行结果存到 renderer server 的 cache 里或是加一层 caching layer 并设置很短的 TTL)

Static Site Generation (SSG)

SSG 是三者中效能最好的一种方式,透过在 build time 就产生静态页面的方式,SSG 可以达到最好的 Time To First Byte,并且可以将生成的静态网站 host 到像是 netlify 这种 static hosting 的平台或是 CDN 上。

SSG 看似美好,但它仍然有些限制 :

  • 没办法像 SSR 那样有动态内容的弹性
  • 当内容需要改变,就必须重新 build 页面
  • 如果网站很巨大,build time 会很长

後来也出现一些新的架构思想想要解决 SSG 的一些问题,例如 Incremental Static Regeneration (ISR,昨天有稍微做了基本介绍) 与 Distributed Persistent Rendering (DPR),有兴趣的读者可以再自行研究罗!

看完这三种架构各自可能会产生的问题,我们可能会想问

有没有办法在保持 SSG 效能的同时,又同时保持 SSR 对於动态内容的弹性?

Yes, ESR comes to the rescue.

ESR (Edge Side Rendering | Edge Slice Re-rendering)

关於 ESR,比较了一下现有的解决方案,有的人称它为 Edge Side Rendering,也有人称它为 Edge Slice Re-rendering。虽然实作方式可能有些许不同,不过底层概念都是利用 CDN edge server 的计算能力,把以往需要在 origin server 执行的操作拉到 CDN level 处理,除了离 end user 较近以外,还能充分运用 CDN 快取带来的优势。今天主要会聚焦在 Vercel YouTube 频道中其中一支影片介绍的 Edge Slice Re-rendering 架构。

假设你建立了一个线上技术分享会的网站

例如像上图这样子,在网页的下方会有一个 footer,在空闲时间显示下一场演讲的主题,如果有一场演讲正在进行,则会显示 Live 来表示正在进行哪场分享。

看到这种需要变动内容的需求,你可能会想到两种方式:

  • client side rendering
  • server side rendering

虽然两种方式照理来说都可以完成需求,但刚刚也提过它们各自带来了一些 trade off


(client side execution)

在 client side 执行很有可能延迟页面的载入时间并且导致页面闪烁,这些问题在某些类型的网站可能还可以接受,但如果是电商这种平台可能就要尽量避免了。


(server side execution)

再来看看 SSR,虽然这个页面会变动,但是改动的频率似乎也不会太高,况且改变的其实只是页面的小部分,为了这样的改变去做 SSR,带来的成本可能是没办法搭配 CDN 做快取或是重复的 re-render 页面中不会变动的部分,看起来也不是一个最佳解法。

也许这时候你也想到了 SSG,如过按照我们对 SSG 的认识,似乎每次更改一次 footer 的状态就得重新 build 一次页面,虽然像 Next.js 这种框架可以做到 page level 的 rebuild 而不用重新 build 整个网页,不过这样的更动频率对静态网站来说似乎还是有点太高了。

回想一下我们刚刚的问题

我们希望可以保有 SSR 的弹性,却可以达到 SSG 的效能。

让我们先看看这个 footer component 的程序码,既然是显示议程的资讯,姑且先叫它 Agenda 吧!

而它的使用方式大致上是这样

从这个 component 实作的方式我们大概可以归纳出一个观念,就是我们只想要 re-render 页面上的某些片段 (slice) 而已,以这个例子来说就是传入的 props 的部分 — linkURL、title、children,这个 component 的其他部分与页面上的其他元件因为没有改动,所以希望可以用 SSG 的方式 build 成静态内容。

不过要怎麽决定我们只想要 re-render 页面中的哪些部分呢?在 vercel 发布的这支影片中,作者提到他们是使用 compiler 的静态分析的方式做到的,这边因为比较 hard code 就不再这边多做讨论了,大家只要先 focus 在「我们希望页面改动时只 re-render 部分内容」这个重点就好。

至於只 re-render 部分内容这个操作又被定义出一个叫做 override 的行为,一个 override 的基本结构如下

在这个物件中,重点应该是 compute 这个 function,我们可以在这个 function 做一些计算或操作并返回新的 props。

看起来挺直观的,不过问题来了,这个 override 的行为应该要在哪里执行比较好?

client side 吗?前面已经讨论过它的问题,看起来不太适合。
server side 吗?看起来也没办法避免它自身会产生的问题,更没办法达到保有 SSR 的弹性,却可以达到 SSG 的效能这个期望。

Maybe…we can do it at the CDN edge.

到这里才算是真的带出 ESR 这个词,不过影片中的作者有提到,通常不会单独使用 Edge Slice Re-rendering,而是会搭配 SSR 或 SSG 使用。以前面分享会的例子来说,可以先使用 SSG build 出静态的页面,并把静态的页面放到 CDN Cache 上,当页面有变动需求时再对 CDN edge server 发出 override 请求,并在 edge server 完成计算得到新的 props 并渲染到页面上。

观察一下各种架构的 benchmark,SSG 加上 ESR 的方式非常有机会可以达到前面说的「希望可以达到 SSR 的动态弹性,又能维持 SSG 的效能」的期望。

其他的解决方案

Edge Slice Re-rendering 只是其中一个被提出来的解决方案,也有人提出的解决方案叫 Edge Side Rendering,实作细节可能稍微有些许不同,但是本质上都是利用 CDN edge server 的计算能力与更接近使用者的特性来提升网站的性能。

Flareact

Edge-rendered React framework built for Cloudflare Workers

在文章的开头有提到由 CDN provider Cloudflare 推出的 serverless 服务 — Cloudflare Workers,而 Flareact 则是一个利用 Cloudflare Workers 的 edge-rendered React framework,基本上它借镜了许多 Next.js 的开发方式与习惯,如果熟悉 Next.js 的人应该可以快速上手,想了解更多关於 Flareact 的读者可以参考这里

在过去,dynamic content 一般被认为是不太能被被快取的,不过最近 CDN serverless service 的发展,让这个限制也慢慢消失了,现在动态的内容也有机会可以透过快取来减少网站的 latency,有兴趣的读者可以看看 Cloudflare Workers 的这篇文章

Edge Side Rendering

这篇文章中,作者提出可以透过 ESI (Edge Side Includes) 这种 markup language (已向 w3c 提出成为 web 标准的申请,但一直没有得到正式批准)来区分出页面中的静态内容与动态内容并顺利组合在一起。

这种方式可以让静态内容被 cache 在 CDN 里,当使用者对页面发出请求时,就先回传被快取的静态内容版本,接着由 CDN layer 负责去集结动态内容,并采用 streaming 的方式回传给 end users。

有兴趣的读者可以到这篇文章看看。

本日小结

这应该是我第一次尝试用文章的形式分享一个尚未成熟的技术,过程中能参考的资料不多,比起以往介绍热门技术的文章更艰难了一点,如果有哪边有错误还请不吝指正。

像 AWS Lambda@Edge、Cloudflare Workers 这些 based on CDN 的 serverless 服务越来越成熟後,能透过 CDN edge server 做到的事情也越来越多了,这次得知还能在 edge side 做前端页面的渲染来提升效能时还蛮惊讶又兴奋的,虽然 ESR 是相对新又还不成熟的技术,但我个人还是很期待它未来能变出什麽新花样,或是能不能让页面效能再达到一个新高度。希望本篇文章可以激起你对 ESR 的兴趣,一起关注它的未来发展吧!

2021/10/27 完赛後更新

在昨天 10/26 Next.js 推出了第 12 版,其中一个功能是 middleware,其实跟 AWS Lambda@Edge 与 Cloudflare Workers 等运用 edge server 的 edge function 非常类似,开发 Next.JS 的公司 Vercel 的 CEO 也在 Conference 中说他们相信 web 的未来将会在云端上,看来前端开发者必须学习这些 Serverless 相关的技术并跨越原本单纯负责画面的职责似乎变成一种势在必行的趋势了呢。

References & 图片来源

https://www.cloudflare.com/zh-tw/learning/cdn/caching-static-and-dynamic-content/
https://blog.cloudflare.com/rendering-react-on-the-edge-with-flareact-and-cloudflare-workers/


<<:  Day-28 Virtual Memory

>>:  DAY28 - 在主机上建立WordPress网站与SSL设定

[Day19] CH10:排序大家族——实验

咦?怎麽还是排序呢?没错!经过前四天的学习,我们今天要来做一个小实验,比较各个排序演算法在相同巨量数...

故事与团队管理

我认为,一个管理者的工作,就是「长期能透过一群人达成目标」 — that's the what. 而...

初学者跪着学JavaScript Day9 : 让我困惑的Literals

一日客语:中文拜拜 客语:嘎子 Literal 是最近让我困惑的字,Literal到底是指? 之前对...

Day 30 完结

大家好~~欢迎来到完结的一篇 本篇呢,即将要结束了,对於AI 来说 可能我给予的知识不够多,但是我希...

SQL injection

SQL注入 当程序员连接字符串以汇编SQL指令时,就会发生SQL注入。字符串是纯数据,而SQL指令是...