有时我想知道我是否一无所知。
就在几周前,我正在和一个朋友聊天,后者提到了“您永远不会在生产环境中直接针对Node运行应用程序”。我大力点头表示我也永远不会在生产中与Node发生冲突,因为……哈哈哈……大家都知道。但是我不知道!我应该知道吗?我仍然可以参加程序吗?
如果我要绘制一个维恩图,说明我所知道的vs其他人都知道的感觉,它将看起来像这样……
顺便说一下,这个小点随着我年龄的增长而变小。
刘慧卿(Alicia Liu)创建的更好的图表改变了我的生活。她说这更像是……
我非常喜欢这个图,因为我希望它是真实的。我不想把我的余生都花在一个微小的,逐渐缩小的无意义的蓝点上。
如此戏剧性。怪潘多拉。在撰写本文时,我无法控制接下来要播放的内容,而Dashboard Confessional就是一种毒品。
好吧,假设Alicia的图表是正确的,我想与大家分享我现在对在生产环境中运行Node应用程序的了解。也许我们相对的维恩图在这个问题上并不重叠。
首先,让我们解决“永远不要在生产环境中直接针对Node运行应用程序”这一说法。
切勿在生产中直接针对Node运行
也许。但也许不是。让我们讨论一下此语句背后的原因。首先,让我们看看为什么不这样做。
假设我们有一台简单的Express服务器。我能想到的最简单的Express服务器…
const express = require("express");
const app = express();
const port = process.env.PORT || 3000;
// viewed at http://localhost:3000
app.get("/", function(req, res) {
res.send("Again I Go Unnoticed");
});
app.listen(port, () => console.log(`Example app listening on port ${port}!`));
我们将使用package.json
文件中的启动脚本来运行它。
"scripts": {
"dev": "npx supervisor index.js",
"start": "node index.js"
}
这里有两个问题。第一个是发展问题,第二个是生产问题。
开发的问题是,当我们更改代码时,我们必须停止并启动应用程序以获取我们的更改。
为了解决这个问题,我们通常使用某种Node进程管理器,例如supervisor
或nodemon
。每当我们进行更改时,这些软件包将监视我们的项目并重新启动服务器。我通常这样做
"scripts": { "dev": "npx supervisor index.js", "start": "node index.js"}
然后我跑npm run dev
。请注意,我在npx supervisor
这里运行,这使我supervisor
无需安装即可使用软件包。我❤️2019.主要是。
我们的另一个问题是我们仍然直接针对Node运行,我们已经说过这很糟糕,现在我们将找出原因。
我将在此处添加另一条尝试从不存在的磁盘读取文件的路由。这是一个错误,很容易在任何实际应用程序中出现。
const express = require("express");
const app = express();
const fs = require("fs");
const port = process.env.PORT || 3000;
// viewed at http://localhost:3000
app.get("/", function(req, res) {
res.send("Again I Go Unnoticed");
});
app.get("/read", function(req, res) {
// this does not exist
fs.createReadStream("my-self-esteem.txt");
});
app.listen(port, () => console.log(`Example app listening on port ${port}!`));
如果直接使用Node对Node运行此操作npm start
并导航到read
端点,则会收到错误消息,因为该文件不存在。
哪个-没什么大不了的吗?这是一个错误。它发生了。
没有。大事了 如果返回到终端,您将看到该应用程序已完全关闭。
Js中文网 – 前端进阶资源教程 www.javascriptC.com,typescript 中文手册
专注分享前端知识,你想要的,在这里都能找到
这意味着,如果您返回浏览器并尝试转到该站点的根URL,则会得到相同的错误页面。一种方法的一个错误使每个人都无法使用该应用程序。
那很糟。真的很糟糕。这是人们说“从不直接与生产中的Node对抗”的主要原因之一。
好。因此,如果我们不能在生产中与Node竞争,那么在生产中运行Node的正确方法是什么?
生产节点的选项
我们有一些选择。
其中之一就是简单地使用类似产品supervisor
或nodemon
在生产中使用的方式,就像在开发人员中使用它们的方式一样。可以,但是这些工具在轻量级方面有点不足。更好的选择是称为pm2的东西。
pm2救援
pm2是一个Node进程管理器,它有很多麻烦。就像其他所有“ JavaScript”一样,npm
您可以从(全局)安装它,也可以npx
再次使用。我不想告诉你如何过自己的生活。
有很多方法可以在pm2上运行您的应用程序。最简单的方法是仅调用pm2 start
您的入口点。
"scripts": {
"start": "pm2 start index.js",
"dev": "npx supervisor index.js"
},
然后您会在终端中看到类似的内容……
那就是我们的过程在pm2监视下在后台运行。如果您访问read
端点并使应用程序崩溃,则pm2将自动重新启动它。您不会在终端中看到任何内容,因为它在后台运行。如果您想观看pm2的工作,则必须运行pm2 log 0
。该0
是我们希望看到日志的进程的ID。
好了!您会看到pm2由于我们未处理的错误而在应用程序关闭时重新启动了它。
我们还可以拉出dev命令并为我们提供pm2监视文件,并在进行任何更改时重新启动。
"scripts": {
"start": "pm2 start index.js --watch",
"dev": "npx supervisor index.js"
},
请注意,因为pm2在后台运行,所以您不能仅仅ctrl+c
退出正在运行的pm2进程。您必须通过传递ID或名称来停止它。
pm2 stop 0
pm2 stop index
另外,请注意pm2保留了对该过程的引用,因此您可以重新启动它。
如果要删除该流程引用,则需要运行pm2 delete
。您可以使用来在一个命令中停止和删除进程delete
。
pm2 delete index
我们还可以使用pm2来运行应用程序的多个进程。pm2将自动在这些实例之间平衡负载。
pm2 fork模式下的多个进程
pm2具有大量的配置选项,这些选项包含在“生态系统”文件中。要创建一个,请运行pm2 init
。你会得到这样的东西…
module.exports = {
apps: [
{
name: "Express App",
script: "index.js",
instances: 4,
autorestart: true,
watch: true,
max_memory_restart: "1G",
env: {
NODE_ENV: "development"
},
env_production: {
NODE_ENV: "production"
}
}
]
};
我将忽略本文的“部署”部分,因为我不知道它的作用。
在“应用程序”部分中,您可以定义要让pm2运行和监视的应用程序。您可以运行多个。这些配置设置中有许多可能是不言自明的。我想在这里重点介绍的是实例设置。
pm2可以运行您的应用程序的多个实例。您可以传入许多要运行的实例,而pm2会增加很多实例。因此,如果我们要运行4个实例,我们可以拥有以下配置文件。
module.exports = {
apps: [
{
name: "Express App",
script: "index.js",
instances: 4,
autorestart: true,
watch: true,
max_memory_restart: "1G",
env: {
NODE_ENV: "development"
},
env_production: {
NODE_ENV: "production"
}
}
]
};
然后我们用运行它pm2 start
。
pm2现在以“群集”模式运行。这些进程中的每个进程都在我计算机上的不同CPU上运行,具体取决于我拥有多少个内核。如果我们想为每个内核运行一个进程而又不知道我们有多少个内核,我们可以将max
参数传递给instances
值。
{
...
instances: "max",
...
}
Js中文网 – 前端进阶资源教程 www.javascriptC.com,typescript 中文手册
专注分享前端知识,你想要的,在这里都能找到
让我们找出这台机器上有多少个内核。
8码!哇靠。我要在Microsoft发行的计算机上安装Subnautica。别跟他们说
在单独的CPU上运行进程的好处是,如果您有一个运行amok并占用100%CPU的进程,其他进程仍然可以运行。如果传递的实例数多于核心数,则pm2将在必要时使CPU上的进程加倍。
您可以使用pm2做更多的事情,包括监视和处理那些讨厌的环境变量。
需要注意的另一项内容:如果由于某种原因希望pm2运行npm start
脚本,则可以通过将npm作为进程并传递来实现-- start
。在这里,“开始”之前的空间非常重要。
pm2 start npm -- start
在Azure AppService中,默认情况下在后台包含pm2。如果要在Azure中使用pm2,则无需在package.json
文件中包含它。您只需添加一个生态系统文件就可以了。
好!既然我们已经了解了pm2的全部知识,那么让我们谈谈为什么您可能不想使用它,并且直接针对Node运行确实可以。
直接在生产中针对Node运行
我对此有一些疑问,所以我联系了蒂尔尼·赛伦(Tierney Cyren),他是庞大的橙色知识圈的一部分,尤其是在涉及Node时。
Tierney指出了使用基于节点的流程管理器(例如pm2)的一些缺点。
主要原因是您不应该使用Node来监视Node。您不想使用要监视的事物来监视该事物。这有点像您在星期五晚上要求我的十几岁的儿子监督自己:结局会很糟糕吗?可能会,也可能不会。但是您将发现困难的方法。
Tierney建议您不要让Node进程管理器完全运行您的应用程序。取而代之的是,在更高级别上监视某些应用程序的单独实例。例如,如果您有一个Kubernetes集群,并且您的应用程序在单独的容器上运行,则是理想的设置。然后,Kubernetes可以监视这些容器,如果其中任何一个发生故障,它可以将其带回并报告其健康状况。
在这种情况下,您可以直接在Node上运行,因为您需要进行更高级别的监视。
事实证明,Azure已经在这样做。如果我们不将pm2生态系统文件推送到Azure,它将使用我们的package.json
文件启动脚本启动应用程序,我们可以直接在Node上运行。
"scripts": {
"start": "node index.js"
}
在这种情况下,我们直接针对Node运行,没关系。如果应用程序崩溃了,您会注意到它又回来了。这是因为在Azure中,您的应用程序在容器中运行。Azure正在协调您的应用程序在其中运行的容器,并知道它何时面世。
但是您在这里仍然只有一个实例。崩溃后,该容器需要一秒钟才能恢复在线状态,这意味着您的用户可能会有几秒钟的停机时间。
理想情况下,您需要运行多个容器。解决方案是将应用程序的多个实例部署到多个Azure AppService站点,然后使用Azure Front Door在单个IP地址后面对应用程序进行负载平衡。前门将知道何时容器发生故障,并将流量路由到应用程序的其他正常实例。
Azure前门服务| Microsoft Azure 使用Azure前门交付,保护和跟踪全球分布式微服务应用程序的性能… azure.microsoft.com
Js中文网 – 前端进阶资源教程 www.javascriptC.com,typescript 中文手册
专注分享前端知识,你想要的,在这里都能找到
系统的
Tierney的另一个建议是使用来运行Node systemd
。我不太了解(或一点也不了解)systemd
,我已经把这个措辞弄乱了,所以让蒂尔尼用他自己的话说……
仅当您可以在部署中访问Linux并在服务级别上控制Node的启动方式时,此选项才可用。如果您在运行时间较长的Linux VM(例如Azure VM)中运行Node.js进程,那么您将是在systemd上运行Node.js的好地方。如果您只是将文件部署到诸如Azure AppService或Heroku之类的服务,或者在诸如Azure容器实例之类的容器化环境中运行,则应该避免使用此选项。
使用Systemd运行Node.js应用程序-第1部分 您已经在Node中编写了下一个出色的应用程序,并准备将其释放给全世界。这意味着您可以… nodesource.com
Node.js工作线程
Tierney还希望您知道Node中即将出现工作线程。这将使您可以在多个“工作者”(线程)上启动您的应用程序,从而不需要pm2之类的东西。也许。我不知道。我没有真正读过这篇文章。
Node.js v11.14.0文档 利用worker_threads模块可以使用并行执行JavaScript的线程。要访问它:const worker =… nodejs.org
成年
Tierney的最后建议是仅处理错误并像成年人一样编写一些测试。但是谁有时间呢?
小圆圈
现在,您知道了蓝色小圆圈中的大部分内容。剩下的只是关于情绪乐队和啤酒的无用事实。
有关pm2,Node和Azure的更多信息,请查看以下资源…
看完两件小事
如果你觉得这篇文章对你挺有启发,我想请你帮我两个小忙:
- 把这篇文章分享给你的朋友 / 交流群,让更多的人看到,一起进步,一起成长!
- 关注公众号 「画漫画的程序员」,公众号后台回复「资源」 免费领取我精心整理的前端进阶资源教程
本文著作权归作者所有,如若转载,请注明出处
转载请注明:文章转载自「 Js中文网 · 前端进阶资源教程 」https://www.javascriptc.com