[博客翻译]预渲染的Next.js网站可以处理多少流量?


原文地址:https://martijnhols.nl/blog/how-much-traffic-can-a-pre-rendered-nextjs-site-handle


一个预渲染的Next.js网站到底能承受多少流量?

我经常说“一个预渲染的网站可以轻松应对数百个并发用户”,因为,嗯,我从未见过它失败。
但它真正能承受多少呢?我的网站能否应对来自像Hacker News首页这样的流量激增?它与服务器端渲染相比如何?是否值得为了避免SSR而大费周章?

我四处寻找Next.js性能的硬数据,但令人惊讶的是,很难找到可靠的数据。于是,我在自己的网站上运行了一些测试,结果出乎意料。就在此时,我关于Google Translate干扰React的文章登上了Hacker News的首页。
就在我发现(剧透警告)我的网站可能无法应对这种情况之后。

预渲染网站与VPS

我首先想知道的是,如果我的网站因为登上Hacker News首页而迎来大量访问,它能否应对。
为了测试这一点,我写了一个基本的k6负载测试脚本,以测量我的服务器每秒能处理的最大请求数。脚本尽可能简单;它会尽可能多次请求一个页面,同时等待每个请求完成。你可以在附录中找到完整的测试设置。

图片:
标识牌:减速 - 限速 - 193 RPS

运行这个脚本,在TransIP的X4 BladeVPS上,一个单独的Next.js实例为我的完全预渲染的首页每秒可以处理193个请求,但只有63%的请求在500毫秒内响应
需要强调的是:测试中的每个请求只是对预渲染的Next.js页面的一次调用。没有请求任何资源。一个真实的访问者需要60多个额外的请求。这意味着仅仅三个同时访问的用户就可能将服务器推向极限。
这比我预期的要低得多。

访问的解剖

为了理解为什么这个网站需要60多个请求,让我们看看当有人访问我的首页时发生的所有请求:

  1. DNS查找和SSL握手。
  2. 初始请求(1: 20.3 kB):浏览器请求HTML文档。
  3. CSS(1: 1.6 kB):浏览器解析HTML并请求必要的CSS文件。

此时页面已经完全样式化并可见,用户可以在JavaScript加载之前与大多数元素交互。 主要缺少的是:

  1. 首屏图片(5: 6.8 kB):浏览器请求首屏图片。

通常只有几张首屏图片,此时的总大小通常在50 kB到100 kB之间。这时访问者开始看到一个完整的页面。 由于大多数交互元素是原生实现的(使用平台),用户也可以开始与页面交互(例如导航)。
其余的请求是“延迟的”;它们是低优先级的,不会阻塞渲染。这包括大多数请求:

  1. 分析(1: 2.5 kB):浏览器请求Plausible脚本。
  2. JavaScript(13: 176.8 kB):浏览器请求主页面所需的JavaScript。
  3. 懒加载图片(1: 22.8 kB):浏览器请求首屏部分懒加载的图片。
  4. 占位符数据(17: 11.9 kB):浏览器请求首屏下方图片的占位符数据。
  5. 图标(2: 52.2 kB):浏览器请求各种尺寸的图标。
  6. 预加载资源(22: 136.1 kB):浏览器预加载潜在导航的资源(以使它们即时加载)。

最终总共有63个请求和434.5 kB
这表明Next.js引入了许多额外的请求和流量,相比于更标准的服务器渲染网站或非Next.js的静态网站。虽然这让我作为开发者可以完全控制用户体验(UX)和出色的开发者体验(DX),但也意味着用户和服务器必须处理更多的流量。话又说回来,我不认为<500 kB对于现代网站来说太多,尤其是页面在加载前100 kB后已经可用。
React Server Components(RSC)可以通过移除部分客户端JavaScript来略微改善这一点。不幸的是,该平台还不太成熟,仍然存在许多问题。我愿意为了最佳性能而处理这些问题,但主要障碍仍然是它缺乏CSS-in-JS支持。一旦这个问题解决(即PigmentCSS发布),我会立即采用。

扩展

在看到我的VPS表现不佳后,我尝试扩展我的Docker容器(docker compose up -d --scale main=2 main)。现在,每个CPU核心(总共2个核心)都有一个Node.js进程处理请求,而不是一个容器处理所有请求。
图片:
CLI显示Docker容器的扩展,之后有两个相同的容器在运行
标题:扩展网站的容器

旁注:

旁注:
我在Docker容器前使用nginx-proxy。它很棒。如果有多个容器监听同一个域名,它会自动[负载均衡](https://github.com/nginx-proxy/nginx-proxy/tree/main/