我们正在 AWS 上测试 Node.js 后端,但在使用某些需要较长时间的工具后,我们的应用程序不断崩溃。我们有实施人员,但我不知道他们是否导致了这次崩溃。我读到,对于异步 I/O 操作,工作线程的实现可能会使应用程序效率更低、速度更慢。我们有连接到 python 微服务的端点,它们执行一些 Web 抓取并返回一些 json。这比正常的请求要多一点,但不是这个世界之外的东西,我说的是毫秒,甚至是第二个差异。
这个问题自从我们部署后端以来已经有一周左右了。首先,我们认为这是子进程,因为我们通过子进程调用python脚本,所以我们决定将它们分开实现微服务。部署新的微服务后,我们注意到这些抓取功能得到了优化,但主要问题并没有解决。我们的应用程序有时仍然会崩溃。
我们使用 EC2 免费套餐,并且只能访问 2 个处理器核心(2 个工作线程)。帮助我看看我是否走在解决这个问题的正确道路上。如果我们只使用后端来处理异步请求(I/O 操作),则不需要工作人员,这将成为一个低效的解决方案。我认为作为团队,我们对这些工作人员的使用存在误解,他们并不代表对我们后端请求的任何类型的优化。
这是我们的app.js,主要微服务的核心:
require('dotenv').config(); // Environment variables.
const cluster = require('cluster');
const { availableParallelism } = require('os');
// If the current process is the master process
if (cluster.isMaster) {
// Get the number of available CPUs
const numCPUs = availableParallelism();
// Create workers according to the number of CPUs
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
// Handle exit events of workers
cluster.on('exit', (worker, code, signal) => {
console.log(`Worker ${worker.process.pid} exited with code: ${code} and signal: ${signal}`);
console.log('Creating a new worker...');
cluster.fork(); // Create a new worker to replace the exited one
});
// Get the number of workers
const numWorkers = Object.keys(cluster.workers).length;
console.log(`Number of workers: ${numWorkers}`);
} else {
// If the current process is a worker process
const morgan = require('morgan');
const express = require('express');
const session = require('express-session');
const compression = require('compression');
const cors = require('cors');
const hpp = require('hpp');
const lusca = require('lusca');
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');
const config = require('./src/config');
// ==== Route Imports ==== //
// Health checker
const healthRouter = require('./src/routes/healthCheck');
// Initialize the App.
const app = express();
// Configure session and cookies.
app.use(session(config.sessionConfig));
// Global Variables.
app.set('port', process.env.PORT || 3001);
// Global Configurations.
app.use(morgan('dev')); // Dev displays info in a semi-condensed manner.
app.use(cors(config.corsOptions)); // Implement and configure CORS.
app.use(express.urlencoded({ extended: false })); // Middleware to decode form data (application/x-www-form-urlencoded).
app.use(express.json()); // Middleware to parse JSON formatted request bodies.
// Add hpp middleware.
app.use(hpp());
// Add express-rate-limit middleware.
app.use(rateLimit(config.rateLimitConfig)); // Apply rate limit to all requests.
// Add Lusca middleware.
app.use(lusca(config.luscaOptions)); // Apply Lusca configurations.
// Add Helmet middleware.
app.use(helmet(config.helmetOptions)); // Apply Helmet configurations.
// Add compression middleware.
app.use(compression(config.compressionOptions.default));
// ==== Routes ==== //
// Enable proxy
if (process.env.ENABLE_TRUST_PROXY) {
app.enable('trust proxy');
}
// Check if the server is running.
app.listen(app.get('port'), () => {
console.log(`Worker ${process.pid} running on port: ${app.get('port')}`);
});
}
注意:当我的意思是我们的应用程序崩溃时,我的意思是我们的整个实例都崩溃了(不仅仅是我们的微服务的容器),所以这就是为什么我认为工作人员的实现是问题所在。在迁移到 docker compose 和微服务之前也是如此。
是的,如果没有有效实施,工作人员可能会导致您的 Node 应用程序崩溃,尤其是在资源有限的 EC2 免费套餐实例上。监控资源使用情况和优化工作策略至关重要。
使用流程管理器:
#install pm2
npm install -g pm2
#start cluster mode
pm2 start app.js -i max
检查系统限制:
Ulimit:确保您的实例未达到打开文件或进程的限制。您可以在 /etc/security/limits.conf 中检查并增加这些限制。
* soft nofile 1024
* hard nofile 4096