Skip to main content

性能优化与高并发

限流算法(高频手写)

面试题:常见限流算法有哪些?区别是什么?

算法思想优点缺点
固定窗口单位时间内计数,超限拒绝简单窗口临界点会有 2 倍突发流量
滑动窗口把窗口细分,平滑统计解决临界问题实现略复杂
漏桶请求入桶,固定速率流出平滑流量、强制匀速无法应对正常突发
令牌桶固定速率发令牌,有令牌才放行允许一定突发-

令牌桶实现(最常用):

class TokenBucket {
constructor(capacity, rate) {
this.capacity = capacity; // 桶容量
this.rate = rate; // 每秒生成令牌数
this.tokens = capacity;
this.last = Date.now();
}

tryAcquire(n = 1) {
const now = Date.now();
// 按时间差补充令牌
this.tokens = Math.min(
this.capacity,
this.tokens + ((now - this.last) / 1000) * this.rate
);
this.last = now;
if (this.tokens >= n) {
this.tokens -= n;
return true;
}
return false;
}
}

分布式限流:用 Redis + Lua 脚本保证原子性(如 INCR + EXPIRE 实现固定窗口,或用 redis-cell)。

缓存策略

  • 多级缓存:浏览器缓存 → CDN → 网关缓存 → 应用本地缓存(如 LRU)→ Redis → DB。
  • 本地缓存 vs 分布式缓存:本地快但多实例不一致;Redis 一致但有网络开销。热点小数据可本地 + Redis 组合。
  • 缓存穿透/击穿/雪崩见 Redis 篇

CPU 密集 vs IO 密集

面试题:Node 适合什么场景?CPU 密集型任务怎么办?

  • Node 的事件循环 + 非阻塞 IO,擅长 IO 密集型(高并发接口、网关、BFF)。
  • 不擅长 CPU 密集型(大量计算会阻塞事件循环,拖垮所有请求)。解决:
    • worker_threads 工作线程池处理计算任务。
    • child_process / Cluster 多进程。
    • 把计算交给专门的服务(如 C++/Go/Python)。
    • 大任务分片,用 setImmediate 让出事件循环。

横向扩展

  • Cluster / PM2 cluster 模式:利用多核,多进程共享端口(原理见 Index 多进程章节)。
  • 负载均衡:Nginx / LVS / 云 LB 把流量分发到多个实例(轮询、加权、IP hash、最少连接)。
  • 无状态化:应用层不存会话状态(存 Redis),才能任意水平扩展。

连接池

数据库、Redis、HTTP 都应使用连接池复用连接,避免频繁建连销毁的开销(TCP 三次握手成本)。注意合理设置 connectionLimit,过大反而压垮 DB。

性能分析手段

  • 压测autocannonwrkab 测 QPS / 延迟分布(关注 P95/P99 而非平均值)。
  • 诊断clinic doctor(CPU/内存图)、clinic flame(火焰图定位热点)、--prof + --prof-process
  • APM 监控:Prometheus + Grafana、阿里 ARMS、Sentry(错误追踪)。
  • 链路追踪:OpenTelemetry,定位跨服务调用瓶颈。

常见优化清单

  1. 数据库加索引、消除慢查询、读写分离。
  2. 加缓存(Redis)减少 DB 压力。
  3. 接口聚合、减少请求往返;耗时操作异步化(消息队列)。
  4. Gzip/Brotli 压缩、静态资源走 CDN。
  5. 开启 HTTP keep-alive、连接池复用。
  6. 限流、降级、熔断保护系统(雪崩防护)。