Node.js 应用层需用 async-mutex 或 p-limit 控制 handler 并发数,Go 需结合系统文件描述符限制与 ConnState 回调主动断连,nginx 应用 limit_conn 按 IP 限连接,云 SLB 仅作四层兜底,须分层防护。
Node.js 用 http.Server 时如何限制并发连接数
node.js 默认不限制同时处理的请求数,单个实例可能被大量轻量请求打满事件循环或内存。这不是靠“加机器”能解决的,得在应用层设闸。
最直接的方式是用 server.maxConnections,但它只对底层 TCP 连接生效,且仅在服务器已知总连接数时才起作用(比如监听后手动计数),实际不可靠。真正可控的是中间件层限流。
-
express-rate-limit是最常用方案,但它限制的是「单位时间请求数」,不是「同时并发数」 - 要控并发,得用
async-mutex或p-limit包住关键 handler,例如数据库查询前加一个最多 50 个并发的队列 - 注意:别在
req/res生命周期外释放锁,否则会漏计数;建议用Promise.finally()确保释放
Go 的 net/http.Server 怎么防连接耗尽
Go 默认也没硬性并发上限,但比 Node 更容易误判——因为 goroutine 轻量,开发者常以为“开一万也不怕”,结果是文件描述符(EMFILE)先崩,而不是 CPU 或内存。
必须做两件事:调操作系统限制 + 应用层拒绝新连接。
- 启动前用
syscall.Setrlimit(syscall.RLIMIT_NOFILE, &syscall.Rlimit{Max: 8192})设软限(需 root 权限) - 在
http.Server中设置ConnState回调,统计http.StateNew和http.StateClosed,超阈值时主动conn.Close() - 别依赖
ReadTimeout或WriteTimeout防慢速攻击,它们不防建连洪水;得用SetKeepAlivePeriod缩短空闲连接存活时间
nginx 作为反向代理时怎么挡住上游并发风暴
很多团队把限流全压给后端,其实 nginx 是第一道更高效的防线。它不解析请求体,只看连接和 header,开销极小。
重点不是 limit_req(那是防 QPS),而是 limit_conn —— 它按 key 统计当前活跃连接数。
- 在
http块定义:limit_conn_zone $binary_remote_addr zone=addr:10m,然后在location里写limit_conn addr 100 - 如果按用户限(比如 JWT 中的
sub),得用map提取,但注意:map不支持嵌套 JSON,需前端把 user_id 放 header 里传过来 - 常见坑:
limit_conn对 HTTPS 的 SNI 连接、HTTP/2 多路复用都有效,但若 upstream 是长连接池(如 keepalive 32),它只算 nginx 到 client 的连接,不算到 backend 的
为什么不能只靠负载均衡器的连接数限制
云厂商 SLB(如 AWS ALB、阿里云 CLB)确实提供「每秒新建连接数」和「最大并发连接数」配置,但它们通常只监控四层(TCP),不感知七层语义。
这意味着:一个恶意客户端用 HTTP/1.1 发起 1000 个长轮询连接,SLB 认为“合法”,但后端每个连接都在等响应,线程/协程卡死。
- SLB 的并发限制是全局的,无法按路径、用户、设备指纹区分,容易误伤正常流量
- 它不识别 Upgrade 请求(如 WebSocket),这类连接一旦建立就长期占用,SLB 不会主动踢出空闲连接
- 真实攻击往往混合行为:一部分连上就发大 body 消耗内存,一部分连上就停住(slowloris),纯四层限流对此无感
真正的防护必须分层:SLB 做总量兜底 → nginx 做连接粒度隔离 → 应用内做 handler 级并发控制。少一层,就可能被绕过。










