bullmq是如何针对流量峰值的时候做调度的,比如我的qps最大限制是10,但是请求并不能知道qps是否达到峰值。是如何跟网管的qps限制结合来实现任务队列调控的?
BullMQ 流量控制的工作原理
1. BullMQ 限流机制(Worker 端控制)
ts
const worker = new Worker('api-calls', async (job) => {
// 调用第三方 API
const result = await fetch('https://third-party-api.com/data');
return result.json();
}, {
connection,
limiter: {
max: 10, // 每个时间窗口最多处理 10 个任务
duration: 1000 // 时间窗口 1 秒
}
});
关键理解 :BullMQ 的限流是在任务消费端(Worker)进行的,不是在任务生产端。
2. 实际的流量控制流程
// 场景:调用第三方 API,对方限制 QPS = 10
// Step 1: 请求进入时不做限制,全部加入队列
ts
app.post('/process-data', async (req, res) => {
// 🔴 这里不管有多少请求,都会加入队列
await apiQueue.add('call-third-party', req.body);
res.json({ message: 'Task queued' });
});
// Step 2: Worker 按限流规则处理任务
ts
const worker = new Worker('api-calls', async (job) => {
// ✅ 这里才会按 QPS 限制执行
// BullMQ 确保每秒最多执行 10 个任务
const result = await callThirdPartyAPI(job.data);
return result;
}, {
limiter: {
max: 10, // 对应第三方 API 的 QPS 限制
duration: 1000
}
});
3. 与网关 QPS 限制的区别
| 层面 | 网关 QPS 限制 | BullMQ 流量控制 |
|---|---|---|
| 作用点 | 请求入口处 | 任务处理时 |
| 限制对象 | HTTP 请求 | 队列任务执行 |
| 超限行为 | 直接拒绝请求 (429) | 任务排队等待 |
| 适用场景 | 保护系统不被打垮 | 保护下游服务 |
4. 实际应用场景示例
场景:电商系统调用支付接口
// 网关层:保护自己的系统 // 限制:每秒最多接收 1000 个支付请求
ts
app.use('/api/payment', rateLimit({
windowMs: 1000,
max: 1000,
message: '请求过于频繁,请稍后重试'
}));
// 应用层:接收请求并加入队列
ts
app.post('/api/payment/process', async (req, res) => {
// 所有通过网关的请求都加入队列
await paymentQueue.add('process-payment', req.body);
res.json({ orderId: req.body.orderId, status: 'processing' });
});
// BullMQ Worker:保护下游支付服务
const worker = new Worker('payment-queue', async (job) => {
// 支付服务限制 QPS = 50,这里严格控制
const result = await paymentService.process(job.data);
return result;
}, {
limiter: {
max: 50, // 匹配支付服务的 QPS 限制
duration: 1000
}
});
5. 动态调控策略
基于监控的动态调整:
ts
class AdaptiveWorker {
private currentLimit = 10;
constructor() {
this.setupWorker();
this.monitorAndAdjust();
}
private setupWorker() {
this.worker = new Worker('adaptive-queue', async (job) => {
try {
const result = await this.callExternalAPI(job.data);
this.onSuccess();
return result;
} catch (error) {
this.onError(error);
throw error;
}
}, {
limiter: {
max: this.currentLimit,
duration: 1000
}
});
}
private onError(error) {
if (error.status === 429) { // 限流错误
// 动态降低处理速度
this.currentLimit = Math.max(1, this.currentLimit - 2);
this.updateWorkerLimiter();
}
}
private onSuccess() {
// 成功时逐步提升处理速度
this.currentLimit = Math.min(20, this.currentLimit + 1);
this.updateWorkerLimiter();
}
}
6. 多层防护架构
// 第1层:网关限流(保护自己) // Nginx/Kong: limit_req_zone $binary_remote_addr zone=api:10m rate=100r/s;
// 第2层:应用层限流(保护数据库)
ts
app.use(rateLimit({ windowMs: 1000, max: 200 }));
// 第3层:队列限流(保护下游服务)
ts
const worker = new Worker('external-api', handler, {
limiter: { max: 10, duration: 1000 } // 匹配外部 API 限制
});
// 第4层:熔断器(故障保护)
ts
const circuitBreaker = new CircuitBreaker(externalAPICall, {
timeout: 3000,
errorThresholdPercentage: 50,
resetTimeout: 30000
});
总结 BullMQ 的流量控制主要解决的是"如何按照下游服务的承受能力来处理任务",而不是"如何限制用户请求"。
关键点:
- 请求入队不限制:用户请求可以快速响应并加入队列
- 任务执行限制:Worker 严格按照下游服务的 QPS 能力处理任务
- 削峰填谷:高峰期请求排队,低峰期逐步处理
- 保护下游:避免因突发流量导致下游服务崩溃
这样设计的好处是用户体验好(快速响应),系统稳定(不会压垮下游),资源利用充分(队列缓冲机制)。