使用 Docker 扩展 Node.js Web 应用程序
本文探讨了如何使用 Docker 将 Node.js Web 应用程序扩展到多个 CPU 核心甚至多台机器上。
介绍
借助云计算和无服务器技术,部署和扩展 Node.js Web 应用程序(例如 Next.js 应用程序)比以往任何时候都更加容易!
但如果您仍然希望掌控自己的服务器架构呢?或者您只想为服务器资源付费,而不是为流量或执行时间付费呢?
在这种情况下,将您的 Web 应用程序部署在 VPS(虚拟专用服务器)上是完美的选择!
Node.js 和单线程的问题
Node.js 本质上是单线程的。这意味着它通常只能利用一个 CPU 核心/线程,并且只能通过在该单个线程上切换任务(即所谓的“事件循环”)来实现“并发”。
但如果你的服务器有多个CPU核心呢?如何利用这些核心来处理更多的传入流量?
利用 Node.js 的多个 CPU 核心
尽管Node.js是单线程的,但它仍然允许你利用多个CPU核心。
Node.js 引入了“集群模式”来实现一定程度的“多线程”。然而,由于 Node.js 仍然是单线程运行时,集群模式所做的只是运行应用程序的多个实例,每个实例都有自己的解释器/运行时。
还有一些非常流行的第三方库,例如“ pm2 ”,也实现了这个概念。pm2 还内置了负载均衡功能,所以绝对值得一试!
使用 Docker Compose 构建多个 Node.js 实例
如果您已经在设置中使用 Docker 和 Docker Compose,那么完全跳过实现集群模式或 pm2 就是一个很好的替代方案。
你可以使用 Docker Compose 创建 Node.js 应用(在我的例子中是 Next.js 应用)的多个副本。
这docker-compose.yml
Docker Compose 让创建运行同一服务的多个容器(“副本”)变得异常简单。它们都可以利用不同的 CPU 核心,而无需任何工具或在应用程序中编写额外的代码。
只需要稍微修改一下docker-compose.yml:
version: '3.7'
services:
your-web-app:
image: registry/.../your-website-image:latest
...
deploy:
replicas: 3
...
只需将密钥添加deploy到要复制的服务中,并指定所需的副本数量(就像上面的示例一样)。
负载均衡
现在你需要考虑的最后一件事是负载均衡。启动 Docker Compose 堆栈后,会有三个容器运行同一个应用程序。你的反向代理或负载均衡器需要将请求均匀地发送到其中一个副本。
有关示例设置,请参见下面的示例。
一个真实案例:这个网站
让我们以我的网站fabiancdng.com为例来看一下:
主机要求
我的网站是一个基于 Next.js 的应用程序,部分页面使用了服务器端渲染 (SSR)。因此,它需要 Node.js 运行时环境,不能直接部署为静态资源。
我将网站部署在 Docker 容器中(使用 Docker Compose),该容器位于一台配备 6 个虚拟 CPU 核心的廉价 VPS 上。
已配置 Docker Compose 以运行三个 Next.js 应用程序副本(全部在各自的容器中)。
为了将传入流量均匀地路由和分配到各个副本上,我需要一个反向代理,它还可以充当负载均衡器。
反向代理和负载均衡器
我使用Traefik作为反向代理,它接收所有传入流量http(s)://*.fabiancdng.com/*并将其路由到内部 Docker 网络中相应的 Docker 容器。
NGINX是另一个用于此目的的常用解决方案。NGINX和Traefik都支持负载均衡。
就我而言,Traefik 开箱即用,支持同一服务的不同副本之间的负载均衡,因此无需额外配置。
一旦在各个副本之间实现了负载均衡,流量就会被分配到不同的 CPU 核心上,从而使您的服务能够处理更多的传入请求。🥳 🎉
展望未来:跨机器横向扩展
如果使用Kubernetes或Docker Swarm等容器编排工具运行此配置,甚至可以实现应用程序的水平扩展。您不仅可以将负载分配到单个服务器上的多个副本,还可以让大量副本运行在大量不同的服务器上。
Docker Swarm 内置了节点间的负载均衡功能。所以如果你打算这样做,不妨了解一下。
但是,如果您的应用程序流量已经达到值得分配到多台机器上的程度,那么您不妨考虑迁移到云端和托管基础设施。
结论
很难说这是否是比直接迁移到Vercel或AWS Amplify等托管服务(例如,在部署 Next.js 应用程序时)或托管容器编排服务更好的替代方案……
尽管这些服务对于高流量网站来说可能相当昂贵,但它们通常会提供慷慨的免费套餐和按需付费模式。此外,借助边缘路由和内容分发网络 (CDN) ,它们能够保证全球范围内的可用性。
然而,即使只使用一台价格低廉的VPS,你也能实现极大的扩展,并且可以避免因流量或执行时间而产生的意外费用。此外,你还可以在一台机器上部署多种不同的服务(或许你还需要一个数据库或一个免费的开源分析工具?),并且可以深入了解服务器管理、Docker以及Web应用程序及其架构背后的复杂性。
我的建议:如果您计划构建一个全栈式副业项目或小型 SaaS,并且需要部署前端、后端、数据库、缓存层等,并且您可以接受额外的配置工作,那么请使用 VPS。
如果你需要扩展规模,而且你刚开始接触网络和后端工程……那就别费劲去用 Kubernetes 之类的工具了。为了维持服务运行,不断增加的复杂性和维护工作量可能根本不值得你投入时间。你应该专注于构建应用本身,而不是围绕应用的架构,直接使用云服务即可。
干杯。
📣 本文最初于 2023 年 5 月 6 日发布在我的网站上。
文章来源:https://dev.to/fabiancdng/scaling-nodejs-web-apps-with-docker-mep



