使用 Docker 和 PM2 构建高并发 Node.js API 网关

news/2025/2/9 7:48:33 标签: docker, node.js, 容器

在现代 Web 开发中,构建高并发、高可用的 API 网关是一个常见的需求。本文将介绍如何结合 Docker 和 PM2 构建一个高性能的 Node.js API 网关,并深入探讨分布式限流器的原理与实现。


1. 背景与需求

1.1 高并发 API 网关的挑战

在高并发场景下,API 网关需要具备以下能力:

  • 高可用性:服务崩溃时能自动恢复。
  • 高性能:充分利用多核 CPU 处理请求。
  • 限流与防护:防止恶意请求压垮服务。
  • 环境一致性:开发、测试、生产环境行为一致。

1.2 技术选型

  • Node.js:轻量、高效,适合 I/O 密集型任务。
  • PM2:Node.js 进程管理工具,支持集群模式和自动重启。
  • Docker容器化部署,确保环境一致性。
  • Redis:分布式限流器的共享存储。

2. 实现步骤

2.1 项目结构

api-gateway/
├── src/
│   ├── server.js         # 主入口
│   ├── auth.js           # 鉴权逻辑
│   ├── rate-limiter.js   # 限流逻辑
│   └── routes/           # 路由配置
├── ecosystem.config.js   # PM2 配置文件
├── Dockerfile            # Docker 构建文件
└── package.json

2.2 核心代码实现

2.2.1 高性能服务器 (server.js)
const express = require('express');
const auth = require('./auth');
const rateLimiter = require('./rate-limiter');

const app = express();
app.use(express.json());

// 全局中间件
app.use(rateLimiter); // 限流
app.use(auth);        // 鉴权

// 路由配置
app.use('/user', require('./routes/user'));
app.use('/order', require('./routes/order'));

// 健康检查端点
app.get('/health', (req, res) => {
  res.status(200).json({ status: 'ok', pid: process.pid });
});

const PORT = process.env.PORT || 3000;
const server = app.listen(PORT, () => {
  console.log(`API Gateway running on port ${PORT} (PID: ${process.pid})`);
});

// 优雅关闭
process.on('SIGTERM', () => {
  server.close(() => {
    console.log('Process terminated');
  });
});
2.2.2 分布式限流器 (rate-limiter.js)
const rateLimit = require('express-rate-limit');
const RedisStore = require('rate-limit-redis');
const redis = require('redis');

// 创建 Redis 客户端
const redisClient = redis.createClient({
  host: 'localhost', // Redis 地址
  port: 6379         // Redis 端口
});

// 限流配置
const limiter = rateLimit({
  windowMs: 1000, // 时间窗口:1秒
  max: 100,       // 每个客户端在窗口内最多允许100次请求
  message: 'Too many requests, please try again later.', // 超限时的响应消息
  standardHeaders: true, // 返回标准 HTTP 限流头(X-RateLimit-*)
  store: new RedisStore({
    client: redisClient, // 使用 Redis 存储计数
    expiry: 60,          // 计数器的过期时间(秒)
    prefix: 'rate-limit:' // Redis 键前缀
  })
});

module.exports = limiter;

2.3 PM2 集群配置 (ecosystem.config.js)

module.exports = {
  apps: [{
    name: 'api-gateway',
    script: './src/server.js',
    instances: 'max',        // 根据 CPU 核心数启动进程
    exec_mode: 'cluster',    // 集群模式
    max_memory_restart: '1G',// 内存超限自动重启
    env: {
      NODE_ENV: 'production',
      REDIS_HOST: 'redis-host' // Redis 地址
    },
    log_date_format: 'YYYY-MM-DD HH:mm Z',
    error_file: '/dev/stdout', // 日志输出到标准输出
    out_file: '/dev/stdout'
  }]
};

2.4 Docker 容器化配置 (Dockerfile)

dockerfile">FROM node:18-alpine

# 安装构建依赖
RUN apk add --no-cache python3 make g++

WORKDIR /app
COPY package*.json ./

# 生产依赖安装(包含PM2)
RUN npm install --production && \
    npm install pm2 -g

COPY . .

# 使用 PM2 专属容器运行时
CMD ["pm2-runtime", "start", "ecosystem.config.js"]

3. 部署与扩展

3.1 构建并启动容器

# 构建镜像
docker build -t api-gateway .

# 运行容器(限制资源)
docker run -d \
  --name gateway \
  -p 3000:3000 \
  --cpus 4 \          # 限制使用4核 CPU
  --memory 4g \       # 限制4GB内存
  --network my-network \
  api-gateway

3.2 水平扩展(Kubernetes 示例)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-gateway
spec:
  replicas: 8        # 启动8个Pod
  selector:
    matchLabels:
      app: gateway
  template:
    metadata:
      labels:
        app: gateway
    spec:
      containers:
      - name: gateway
        image: api-gateway:latest
        resources:
          limits:
            cpu: "2" # 每个Pod限制2核
            memory: 2Gi
        ports:
        - containerPort: 3000

4. 分布式限流器的原理

4.1 核心原理

分布式限流器通过共享存储(如 Redis)在多个服务实例之间同步请求计数,从而实现对请求的全局限流。其核心思想是:

  1. 共享存储:使用 Redis 记录请求计数。
  2. 全局计数:所有服务实例共享同一个计数器。
  3. 时间窗口:基于时间窗口(如每秒、每分钟)统计请求数。

4.2 工作流程

  1. 客户端发起请求。
  2. 服务端检查 Redis 中该客户端的请求计数:
    • 如果计数未超限,允许请求并通过 Redis 增加计数。
    • 如果计数超限,拒绝请求并返回 429 Too Many Requests
  3. Redis 自动清理过期计数(基于 TTL)。

5. 总结

通过结合 Docker 和 PM2,我们可以构建一个高性能、高可用的 Node.js API 网关,并利用分布式限流器保护服务不被过多请求压垮。这种架构不仅适用于高并发场景,还能显著提升服务的可维护性和可扩展性。

关键优势

  • 高可用性:PM2 自动重启崩溃的进程,Docker 提供容器级恢复。
  • 高性能:PM2 集群模式充分利用多核 CPU。
  • 全局一致性:分布式限流器确保限流策略全局一致。
  • 环境一致性:Docker 镜像保证开发、测试、生产环境行为一致。

http://www.niftyadmin.cn/n/5845790.html

相关文章

Kafka中的KRaft算法

我们之前的Kafka值依赖于Zookeeper注册中心来启动的,往里面注册我们节点信息 Kafka是什么时候不依赖Zookeeper节点了 在Kafka2.8.0开始就可以不依赖Zookeeper了 可以用KRaft模式代替Zookeeper管理Kafka集群 KRaft Controller和KRaft Leader的关系 两者关系 Lea…

驱动开发系列34 - Linux Graphics Intel 动态显存技术的实现

一:概述 动态显存技术(Dynamic Video Memory Technology, DVMT)是一种由 Intel 提出的内存分配技术,主要用于整合显卡(集成显卡)系统中,以便动态地调整显存大小,从而在不同的负载场景下优化内存使用和系统性能。 动态显存技术的核心在于共享系统内存。集成显卡没有独立…

【python】matplotlib(animation)

文章目录 1、matplotlib.animation1.1、FuncAnimation1.2、修改 matplotlib 背景 2、matplotlib imageio2.1、折线图2.2、条形图2.3、散点图 3、参考 1、matplotlib.animation 1.1、FuncAnimation matplotlib.animation.FuncAnimation 是 Matplotlib 库中用于创建动画的一个…

微信小程序地图开发总结-规划路线

在现代移动应用中,地图导航功能已成为必不可少的一部分。通过地图 API,我们可以轻松地在应用中集成位置服务和路径规划功能。本篇文章将带大家一起实现一个简单的路径导航功能,使用腾讯地图 API结合微信小程序,实现从当前位置到目…

GitHub Pages + Jekyll 博客搭建指南(静态网站)

目录 🚀 静态网站及其生成工具指南🌍 什么是静态网站?📌 静态网站的优势⚖️ 静态网站 VS 动态网站 🚀 常见的静态网站生成器对比🛠️ 使用 GitHub Pages Jekyll 搭建个人博客📌 1. 创建 GitHu…

什么是网络安全审计?网络安全审计的作用...

网络安全审计通过对网络数据的采集、分析、识别,实时动态监测通信内容、网络行为和网络流量,发现和捕获各种敏感信息、违规行为,实时报警响应,全面记录网络系统中的各种会话和事件,实现对网络信息的智能关联分析、评估…

element-plus el-tree-select 修改 value 字段

element-plus el-tree-select 修改 value 字段 &#xff0c;不显示label 需要注意两个地方&#xff1a; <el-tree-select v-model"value" :data"data" multiple :render-after-expand"false" show-checkbox style"width: 240px" …

FPGA高端项目:实时视频缩放+UltraScale GTH光编码+UDP图传架构,高速接口转网络视频传输,提供工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐我已有的所有工程源码总目录----方便你快速找到自己喜欢的项目我这里已有的 GT 高速接口解决方案我这里已有的以太网方案我这里已有的FPGA图像缩放方案 3、工程详细设计方案工程设计原理框图输入视频之-->ADV7611芯片解码HDMI动…