部署 Node.js 应用以完成服务器端渲染 Server Side Rendering 的性能调优

原文:Operationalizing Node.js for Server Side Rendering

在 Airbnb,我们花了数年时间将所有前端代码稳定地迁移到一致的架构中,在该架构中,整个网页都被编写为 React 组件的层次结构,其中包含来自我们 API 的数据。 Ruby on Rails 在将 Web 连接到浏览器方面所扮演的角色每天都在减少。事实上,很快我们将过渡到一项新服务,该服务将完全在 Node.js 中提供完全形成的、服务器呈现的网页。此服务将为所有 Airbnb 产品呈现大部分 HTML。这个渲染引擎不同于我们运行的大多数后端服务,因为它不是用 Ruby 或 Java 编写的。但它也不同于我们的心智模型和通用工具所围绕的那种常见的 I/O 密集型 Node.js 服务。

当您想到 Node.js 时,您会设想您的高度异步应用程序同时高效地为数百或数千个连接提供服务。您的服务正在从整个城镇提取数据,并进行应用轻量级处理,以使其适合众多客户。也许您正在处理一大堆长期存在的 WebSocket 连接。您对非常适合该任务的轻量级并发模型感到满意和自信。

服务器端渲染 (SSR) 打破了导致该愿景的假设。它是计算密集型的。 Node.js 中的用户代码在单个线程中运行,因此对于计算操作(与 I/O 相对),您可以并发执行它们,但不能并行执行。 Node.js 能够并行处理大量异步 I/O,但会遇到计算限制。随着请求的计算部分相对于 I/O 的增加,并发请求将对延迟产生越来越大的影响,因为 CPU 争用。

考虑 Promise.all([fn1, fn2])。如果 fn1 或 fn2 是由 I/O 解析的承诺,您可以像这样实现并行性:

如果 fn1 和 fn2 是计算的,它们将改为这样执行:

一个操作必须等待另一个完成才能运行,因为只有一个执行线程。

对于服务器端渲染,当服务器进程处理多个并发请求时会出现这种情况。 并发请求将被正在处理的其他请求延迟:

在实践中,请求通常由许多不同的异步阶段组成,即使仍然主要是计算。 这可能导致更糟糕的交织。 如果我们的请求由一个像 renderPromise().then(out => formatResponsePromise(out)).then(body => res.send(body)) 这样的链组成,我们可以有像这样的请求交错:

在这种情况下,两个请求最终都会花费两倍的时间。随着并发性的增加,这个问题变得更糟。

此外,SSR 的共同目标之一是能够在客户端和服务器上使用相同或相似的代码。这些环境之间的一个很大区别是客户端上下文本质上是单租户,而服务器上下文是多租户的。在客户端轻松工作的技术(如单例或其他全局状态)将导致服务器上并发请求负载下的错误、数据泄漏和一般混乱。 这两个问题只会成为并发问题。在较低的负载水平下或在您的开发环境的舒适单一租户中,一切通常都能正常工作。 这导致了与 Node 应用程序的规范示例完全不同的情况。我们使用 JavaScript 运行时是因为它的库支持和浏览器特性,而不是它的并发模型。在这个应用程序中,异步并发模型强加了它的所有成本,没有或只有很少的好处。

一些经验分享

用户发送请求到我们的主要 Rails 应用程序 Monorail,它将希望在任何给定页面上呈现的 React 组件的 props 拼凑在一起,并使用这些 props 和组件名称向 Hypernova 发出请求。 Hypernova 使用 props 渲染组件以生成 HTML 以返回到 Monorail,然后将其嵌入到页面模板中并将整个内容发送回客户端。

在 SSR 渲染失败(由于错误或超时)的情况下,回退是将组件及其道具嵌入页面而不渲染 HTML,允许它们(希望)被客户端成功渲染。 这导致我们将 SSR 视为一种可选的依赖项,并且我们能够容忍一定数量的超时和失败。 我们将调用超时设置为大约在我们调整值时观察到的值。不出所料,我们以略低于 5% 的超时基线运行。

在日常流量负载高峰期进行部署时,我们会看到高达 40% 的 SSR 请求发生超时。类似 BadRequestError: Request aborted on deploys 的这些错误,掩盖了所有其他应用程序/编码错误。

我们曾将延迟归咎于启动延迟,而延迟实际上是由并发请求相互等待以使用 CPU 造成的。 从我们的性能指标来看,由于其他正在运行的请求而等待执行所花费的时间与执行请求所花费的时间无法区分。 这也意味着并发导致的延迟增加看起来与新代码路径或功能导致的延迟增加相同——实际上增加了任何单个请求的成本。

BadRequestError: Request aborted 错误也变得越来越明显,不能用一般的慢启动性能来解释。 该错误来自正文解析器,特别是在客户端在服务器能够完全读取请求正文之前中止请求的情况下发生。 客户端放弃并关闭连接,带走我们继续处理请求所需的宝贵数据。 发生这种情况的可能性要大得多,因为我们开始处理一个请求,然后我们的事件循环被另一个请求的渲染阻塞,然后从我们被中断的地方返回完成,却发现客户端已经离开了。

我们决定通过使用我们拥有大量现有操作经验的两个现成组件来解决这个问题:反向代理 (nginx) 和负载均衡器 (haproxy)。

Reverse Proxying and Load Balancing

为了利用我们的 SSR 服务器上存在的多个 CPU 内核,我们通过内置的 Node.js 集群模块运行多个 SSR 进程。 由于这些是独立的进程,我们能够并行处理并发请求。

这里的问题是每个节点进程在请求的整个持续时间内都被有效占用,包括从客户端读取请求正文。

虽然我们可以在单个进程中并行读取多个请求,但这会导致在进行渲染时计算操作的交错。

节点进程的使用与客户端和网络的速度耦合。

解决方案是使用缓冲反向代理来处理与客户端的通信。 为此,我们使用 nginx。 Nginx 将来自客户端的请求读入缓冲区,并在完全读取后将完整请求传递给节点服务器。

这种传输通过环回或 unix 域套接字在机器上本地发生,这比机器之间的通信更快、更可靠。

通过 nginx 处理读取请求,我们能够实现节点进程的更高利用率。

总结

服务器端渲染代表与 Node.js 擅长的规范的、主要是 I/O 工作负载不同的工作负载。了解异常行为的原因使我们能够使用我们拥有现有操作经验的现成组件来解决它。

异步渲染仍然存在资源争用。异步渲染解决进程或浏览器的响应问题,但不解决并行性或延迟问题。 这篇翻译的博文重点介绍的是纯计算工作负载的简单模型。对于 IO 和计算的混合工作负载,请求并发会增加延迟,但具有允许更高吞吐量的好处。

(0)

相关推荐

  • 知名Node.js组件存在代码注入漏洞

    原创 Travis OSC开源社区 昨天 日前,一个被大量下载的 Node.js 组件被发现其含有一个高危的代码注入漏洞. 该漏洞被追踪为 CVE-2021-21315,影响了「systeminfor ...

  • NuxtJS快速入门

    服务器端渲染(SSR) 知识储备 ES6 Nodejs Vue React Angular 什么是服务器端渲染 前端渲染:html页面作为静态文件存在,前端请求时后端不对该文件做任何内容上的修改,直接 ...

  • ssr知识汇总

    查看是不是服务端渲染 右键查看源码 有值就是服务端渲染 没有就是客户端渲染 把react组件 变成字符串 放在浏览器 import . {renderToString} from 'react-dom ...

  • 狼叔:聊聊 Node.js

    前端技术优选 今天 以下文章来源于Alibaba F2E ,作者狼叔 前阵子我在知乎上回答了<2021前端会有什么新的变化?>,单篇33.8万的阅读量,还是不错的,说明大家非常关心前端的变 ...

  • docker 中运行的 jenkins 使用 npm 构建 Node.js 应用

    配置要求 最小 256MB 内存,推荐 512MB 以上 10GB硬盘空间,用于安装 Jenkins.Docker 镜像和容器 在 Docker 中运行 Jenkins 我们在服务器上面为 jenki ...

  • 关于 SAP UI5 对服务器端渲染 Server Sider Render 的支持问题

    之前 Jerry 的公众号文章介绍过 SAP 产品的渲染模式: SAP UI渲染模式:客户端渲染 VS 服务器端渲染 关于 SAP 产品 UI 的搜索引擎优化 SEO - Search Engine ...

  • 如何为部署到 SAP BTP 平台上的 Node.js 应用提供Authorization 和 Trust 管理 - 权限管控

    官方链接 本教程的目标是通过身份验证和授权来保护和部署产品列表应用程序,因此只有具有正确授权的用户才能获得身份验证应用程序中的产品.没有必要授权的用户可以登录应用程序,但看不到产品. 本教程的基础是一 ...

  • 快上车!使用 Node.js 搭建一个 API 网关

    编程微刊 1周前 以下文章来源于程序员成长指北 ,作者koala 程序员成长指北专注 Node.js 技术栈分享,从 前端 到 Node.js 再到 后端数据库,祝您成为优秀的高级 Node.js 全 ...

  • 简析 Node.js 特点与应用场景(让你更了解它)

    前端技术优选 今天 以下文章来源于程序员成长指北 ,作者koala 如果你有一定的前端基础,比如 HTML.CSS.JavaScript.jQuery:那么,Node.js 能让你以最低的成本快速过渡 ...

  • JavaScript 事件循环:从起源到浏览器再到 Node.js

    冰森 前端技术优选 今天 很多文章都在讨论事件循环 (Event Loop) 是什么,而几乎没有人讨论为什么 JavaScript 中会有事件循环.博主认为这是为什么很多人都不能很好理解事件循环的一个 ...

  • 看了就会的 Node.js 三大基础模块常用 API

    技术漫谈 4月11日 以下文章来源于前端试炼 ,作者小炼

  • 字节跳动最爱考的前端面试题:Node.js 基础

    前端技术优选 今天 前几天,跟我一朋友聊天,他现在是阿里的架构师,说:「他们根本不知道,现在的电商大促有多么依赖 Node.js.」 说真的,我倒并不意外.作为一个定位明确的高性能 Web 服务器,N ...

  • 成为自信的node.js开发者(一)

    原创 雾豹 前端技术优选 今天 作者:雾豹 原文地址:https://juejin.im/post/5c6a780451882561dd7b65d6 适合阅读的同学 想更进一步深入理解node的同学, ...

  • Angular 服务器端渲染的学习笔记(一)

    官网链接:https://angular.io/guide/universal Angular Universal, a technology that renders Angular applica ...