负载均衡
- 策略:使用负载均衡器将请求均匀分配到多个Node.js实例上,避免单个实例过载。常见的负载均衡算法有轮询、加权轮询、最少连接数等。
- 实现:
- 硬件负载均衡器:如F5 Big-IP等设备,配置将请求转发到多个Node.js服务器对应的IP和端口。
- 软件负载均衡器:
- Nginx:在Nginx配置文件中设置
upstream
块,指定多个Node.js实例的地址,例如:
upstream nodejs_servers {
server 192.168.1.10:3000;
server 192.168.1.11:3000;
}
server {
listen 80;
location / {
proxy_pass http://nodejs_servers;
}
}
- **Node.js 自带的 cluster 模块**:可以创建多个工作进程(worker processes)来共享服务器端口,实现负载均衡。主进程监听端口,接收到请求后将其分配给不同的工作进程处理。示例代码如下:
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
console.log(`Master ${process.pid} is running`);
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`worker ${worker.process.pid} died`);
cluster.fork();
});
} else {
http.createServer((req, res) => {
res.writeHead(200);
res.end('Hello World\n');
}).listen(3000);
console.log(`Worker ${process.pid} started`);
}
连接池
- 策略:对于需要与外部资源(如数据库)交互的场景,使用连接池来管理连接,避免频繁创建和销毁连接带来的开销。
- 实现:以MySQL数据库为例,使用
mysql2
模块实现连接池:
const mysql = require('mysql2');
const pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: 'password',
database: 'test',
connectionLimit: 10
});
const promisePool = pool.promise();
async function queryDatabase() {
try {
const [rows] = await promisePool.query('SELECT * FROM users');
return rows;
} catch (error) {
console.error('Database query error:', error);
}
}
缓存策略
- 策略:
- 内存缓存:对于频繁访问且不经常变化的数据,使用内存缓存,如
node-cache
模块。
- 分布式缓存:对于多实例部署的情况,使用分布式缓存(如Redis)来共享缓存数据。
- 实现:
const NodeCache = require('node-cache');
const myCache = new NodeCache();
function getFromCache(key) {
return myCache.get(key);
}
function setToCache(key, value, ttl = 60) {
myCache.set(key, value, ttl);
}
- **Redis**:使用`ioredis`模块:
const Redis = require('ioredis');
const redis = new Redis();
async function getFromRedis(key) {
return await redis.get(key);
}
async function setToRedis(key, value, ttl = 60) {
await redis.setex(key, ttl, value);
}
优化 Node.js HTTP 模块本身
- 策略:
- 事件驱动和非阻塞 I/O:Node.js 本身基于事件驱动和非阻塞 I/O 模型,要充分利用这一特性,确保代码中的 I/O 操作(如文件读取、网络请求等)不会阻塞事件循环。
- 高效的路由和中间件:合理设计路由和中间件,减少不必要的处理流程,提高请求处理效率。
- 实现:
- 事件驱动和非阻塞 I/O:编写代码时,使用异步函数和 Promise 来处理 I/O 操作。例如,读取文件:
const fs = require('fs').promises;
async function readFileContent() {
try {
const data = await fs.readFile('example.txt', 'utf8');
return data;
} catch (error) {
console.error('Error reading file:', error);
}
}
- **高效的路由和中间件**:使用 Express 等框架可以更方便地管理路由和中间件。例如:
const express = require('express');
const app = express();
app.get('/api/users', (req, res) => {
// 处理用户请求
res.json({ message: 'User list' });
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
监控与日志
- 策略:
- 性能监控:使用工具如
Node.js process metrics
、New Relic
等监控应用的性能指标,如 CPU 使用率、内存使用情况、请求响应时间等。
- 日志记录:记录详细的日志信息,包括请求信息、错误信息等,以便在出现问题时能够快速定位和排查。
- 实现:
- 性能监控:以
Node.js process metrics
为例,可使用以下代码获取基本性能指标:
const os = require('os');
const process = require('process');
function getPerformanceMetrics() {
const cpuUsage = os.loadavg()[0];
const memoryUsage = process.memoryUsage().rss;
return { cpuUsage, memoryUsage };
}
- **日志记录**:使用`winston`模块记录日志:
const winston = require('winston');
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transport.Console(),
new winston.transport.File({ filename: 'app.log' })
]
});
// 在请求处理中记录日志
app.get('/api/users', (req, res) => {
logger.info('Received request for /api/users');
// 处理请求
res.json({ message: 'User list' });
});