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

在现代 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)

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 镜像保证开发、测试、生产环境行为一致。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/966242.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

k8s网络插件及基础命令

一、k8s的cni网络插件 1.k8s的内部网络模式 pod内的容器与容器之间的通信。一个节点上的pod之间的通信,docker0网桥直接通信。不同节点上的pod之间的通信:通过物理网卡的ip地址和其他节点上的物理网卡的设备进行通信,然后把流量转发到指定的…

保姆级教程Docker部署KRaft模式的Kafka官方镜像

目录 一、安装Docker及可视化工具 二、单节点部署 1、创建挂载目录 2、运行Kafka容器 3、Compose运行Kafka容器 4、查看Kafka运行状态 三、集群部署 四、部署可视化工具 1、创建挂载目录 2、运行Kafka-ui容器 3、Compose运行Kafka-ui容器 4、查看Kafka-ui运行状态 …

【C语言】传值调用与传址调用详解

博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C语言 文章目录 💯前言💯传值调用1. 什么是传值调用?2. 示例代码:传值调用失败的情况执行结果: 3. 为什么传值调用无法修改外部变量? &#x1f4…

HarmonyOS 5.0应用开发——ContentSlot的使用

【高心星出品】 文章目录 ContentSlot的使用使用方法案例运行结果 完整代码 ContentSlot的使用 用于渲染并管理Native层使用C-API创建的组件同时也支持ArkTS创建的NodeContent对象。 支持混合模式开发,当容器是ArkTS组件,子组件在Native侧创建时&#…

Golang:Go 1.23 版本新特性介绍

流行的编程语言Go已经发布了1.23版本,带来了许多改进、优化和新特性。在Go 1.22发布六个月后,这次更新增强了工具链、运行时和库,同时保持了向后兼容性。 Go 1.23 的新增特性主要包括语言特性、工具链改进、标准库更新等方面,以下…

11.PPT:世界动物日【25】

目录 NO12​ NO34 NO56​ NO789视频音频​ NO10/11/12​ NO12 设计→幻灯片大小→ →全屏显示(16:9)确定调整标题占位符置于图片右侧:内容占位符与标题占位符左对齐单击右键“世界动物日1”→复制版式→大小→对齐 幻灯片大小…

力扣.623. 在二叉树中增加一行(链式结构的插入操作)

Problem: 623. 在二叉树中增加一行 文章目录 题目描述思路复杂度Code 题目描述 思路 1.首先要说明,对于数据结构无非两大类结构:顺序结构、链式结构,而二叉树实质上就可以等效看作为一个二叉链表,而对于链表插入一个节点的操作是应…

Office/WPS接入DS等多个AI工具,开启办公新模式!

在现代职场中,Office办公套件已成为工作和学习的必备工具,其功能强大但复杂,熟练掌握需要系统的学习。为了简化操作,使每个人都能轻松使用各种功能,市场上涌现出各类办公插件。这些插件不仅提升了用户体验,…

yolov11模型在Android设备上运行【踩坑记录】

0) 参考资料: https://github.com/Tencent/ncnn?tabreadme-ov-file https://github.com/pnnx/pnnx https://github.com/nihui/ncnn-android-yolov5 https://github.com/Tencent/ncnn?tabreadme-ov-file 1) :将xxx.pt模型转化成 xxx.onnx ONNX(Ope…

DeepSeek与llama本地部署(含WebUI)

DeepSeek从2025年1月起开始火爆,成为全球最炙手可热的大模型,各大媒体争相报道。我们可以和文心一言一样去官网进行DeepSeek的使用,那如果有读者希望将大模型部署在本地应该怎么做呢?本篇文章将会教你如何在本地傻瓜式的部署我们的…

arcgis for js范围内天地图高亮,其余底图灰暗

在GIS地图开发中,有时我们需要突出显示某个特定区域,而将其他区域灰暗处理,以达到视觉上的对比效果。本文将介绍如何使用ArcGIS for JavaScript实现这一功能,具体效果为:在指定范围内,天地图高亮显示&#…

基于微信小程序的医院预约挂号系统的设计与实现

hello hello~ ,这里是 code袁~💖💖 ,欢迎大家点赞🥳🥳关注💥💥收藏🌹🌹🌹 🦁作者简介:一名喜欢分享和记录学习的在校大学生…

Docker深度解析:安装各大环境

安装 Nginx 实现负载均衡: 挂载 nginx html 文件: 创建过载目录: mkdir -p /data/nginx/{conf,conf.d,html,logs} 注意:在挂载前需要对 conf/nginx.conf 文件进行编写 worker_processes 1;events {worker_connections 1024; …

Linux 源码编译安装httpd 2.4,提供系统服务管理脚本并测试

第一种方式 1. 下载 Apache HTTP Server 源代码 首先,从 Apache 官网 下载最新版本的 httpd 2.4 源码,或者直接使用 wget 下载: [rootlocalhost ~]# wget https://downloads.apache.org/httpd/httpd-2.4.36.tar.gz # 解压 [rootlocalhost ~…

ARM嵌入式学习--第十三天(I2C)

I2C --介绍 I2C(Inter-intergrated Circuit 集成电路)总线是Philips公司在八十年代初推出的一种串行、半双工的总线,主要用于近距离、低速的芯片之间的通信;I2C总线有俩根双向的信号线,一根数据线SDA用于收发数据&…

python爬虫--简单登录

1,使用flask框架搭建一个简易网站 后端代码app.py from flask import Flask, render_template, request, redirect, url_for, sessionapp Flask(__name__) app.secret_key 123456789 # 用于加密会话数据# 模拟用户数据库 users {user1: {password: password1}…

C# 解决“因为算法不同,客户端和服务器无法通信”的问题

目录 故障现象 开发运行环境 解决 实现携带证书的 API URL调用 其它 故障现象 实现微信退款功能,我们需要在微信支付商户后台申请安全证书,并调用退款API URL。在调试过程中为增添返回调试信息属性,重新对.net FrameWorkd 类库进行编译…

【大模型】Ubuntu下安装ollama,DeepSseek-R1:32b的本地部署和运行

1 ollama 的安装与设置 ollama官网链接:https://ollama.com/ 在左上角的【Models】中展示了ollama支持的模型在正中间的【Download】中课可以下载支持平台中的安装包。   其安装和模型路径配置操作流程如下: ollama的安装 这里选择命令安装curl -fsSL …

LLAMA-Factory安装教程(解决报错cannot allocate memory in static TLS block的问题)

步骤一: 下载基础镜像 # 配置docker DNS vi /etc/docker/daemon.json # daemon.json文件中 { "insecure-registries": ["https://swr.cn-east-317.qdrgznjszx.com"], "registry-mirrors": ["https://docker.mirrors.ustc.edu.c…

快速上手——.net封装使用DeekSeek-V3 模型

📢欢迎点赞 :👍 收藏 ⭐留言 📝 如有错误敬请指正,赐人玫瑰,手留余香!📢本文作者:由webmote 原创📢作者格言:新的征程,用爱发电,去丈量人心,是否能达到人机合一?开工大吉 新的一年就这么水灵灵的开始了,在这里,祝各位读者新春快乐,万事如意! 新年伊…