生产者端:消息确认(Publisher Confirms)与返回机制(Return Messages)
1 ) 技术背景:
RabbitMQ 通过 Publisher Confirms 确保消息到达 Broker,通过 Return Messages 处理无法路由的消息。在 NestJS 中需显式开启这两项特性,并解决异步回调中的消息追踪问题。
2 ) 关键配置步骤
-
启用 ConnectionFactory 特性
// rabbitmq.config.ts import { RabbitMQModule } from '@golevelup/nestjs-rabbitmq'; import { ConfirmChannel } from 'amqplib'; @Module({ imports: [ RabbitMQModule.forRoot(RabbitMQModule, { exchanges: [{ name: 'order_exchange', type: 'direct' }], uri: 'amqp://localhost:5672', connectionInitOptions: { wait: true }, // 开启生产者确认与返回模式 connectionManagerOptions: { connectionOptions: { confirm: true, // 等效于 setPublisherConfirmType(ConfirmType.CORRELATED) clientProperties: { publisherReturns: true } // 开启消息返回 } } }) ] }) export class RabbitConfigModule {} -
配置 RabbitTemplate 回调
// rabbit.service.ts import { RabbitRPC, RabbitSubscribe } from '@golevelup/nestjs-rabbitmq'; import { RabbitMQProducer } from '@golevelup/nestjs-rabbitmq'; @Injectable() export class RabbitService { constructor(private readonly producer: RabbitMQProducer) {} async sendOrderMessage(orderId: string) { const correlationId = orderId.toString(); await this.producer.publish('order_exchange', 'order.routing.key', { id: orderId }, { correlationId, mandatory: true, // 触发 ReturnCallback headers: { 'x-delay': 5000 } } ); // 注册全局回调(需在模块初始化时完成) this.producer.registerConfirmCallback((ack: boolean, correlation: any) => { if (ack) { console.log(`[Confirm] Message ${correlation.id} confirmed`); } else { console.error(`[Confirm] Message ${correlation.id} nacked`); } }); this.producer.registerReturnCallback((returned) => { console.error( `[Return] Message ${returned.properties.correlationId} returned: ` + `Code=${returned.replyCode}, Reason=${returned.replyText}` ); }); } } -
异步回调关联消息
使用correlationId绑定消息与业务标识(如订单ID),解决异步确认中的消息追踪问题:// 消息发送时携带 correlationId await this.rabbitService.sendOrderMessage('order_123');
消费者端:SimpleMessageListenerContainer 高级特性
容器核心能力:
- 多队列监听
- 并发消费者线程池管理
- 手动消息确认(Manual Ack)
- 消费端限流(QoS Prefetch)
消费者容器配置
// order.consumer.ts
import { RabbitSubscribe } from '@golevelup/nestjs-rabbitmq';
@Controller()
export class OrderConsumer {
@RabbitSubscribe({
exchange: 'order_exchange',
routingKey: 'order.routing.key',
queue: 'order_queue',
queueOptions: { durable: true },
// 关键参数配置
allowNonJsonMessages: true,
prefetchCount: 1, // 消费端限流 (QoS)
ackMode: 'MANUAL' // 手动确认模式
})
async handleOrderMessage(
message: {},
@Ctx() context: AmqpConnection
) {
const { channel, deliveryTag } = context.getChannelRef();
try {
console.log(`Processing message: ${JSON.stringify(message)}`);
// 业务逻辑处理...
channel.ack(deliveryTag, false); // 手动确认
} catch (error) {
channel.nack(deliveryTag, false, true); // 重回队列
}
}
}
高级特性实现
-
手动消息确认
通过ackMode: 'MANUAL'及channel.ack()控制消息确认时机,异常时调用nack()实现重回队列。 -
消费端限流
prefetchCount: 1限制每次仅预取一条消息,避免消费者过载。 -
动态线程池调整
在@golevelup/nestjs-rabbitmq中通过装饰器参数控制并发:@RabbitSubscribe({ prefetchCount: 5, // 每个信道预取量 concurrency: 3 // 并发消费者数量 })
工程示例:NestJS 集成 RabbitMQ 的三种方案
1 ) 方案1:基础生产者-消费者模型
// 生产者
@Injectable()
export class ProducerService {
constructor(private amqpConnection: AmqpConnection) {}
async publishEvent(exchange: string, routingKey: string, payload: object) {
await this.amqpConnection.publish(exchange, routingKey, payload);
}
}
// 消费者
@RabbitSubscribe({ exchange: 'events', routingKey: '#' })
handleEvent(msg: {}) {
console.log(`Received: ${JSON.stringify(msg)}`);
}
2 ) 方案2:RPC 模式(请求-响应)
// 服务端
@RabbitRPC({
exchange: 'rpc_exchange',
routingKey: 'math.sqrt',
queue: 'sqrt_queue'
})
async sqrtRPC(num: number) {
return { result: Math.sqrt(num) };
}
// 客户端调用
const response = await this.amqpConnection.request<{ result: number }>({
exchange: 'rpc_exchange',
routingKey: 'math.sqrt',
payload: 9
});
3 ) 方案3:死信队列(DLX)实现延迟消息
// 配置死信交换器
@Module({
imports: [
RabbitMQModule.forRootAsync(RabbitMQModule, {
useFactory: () => ({
exchanges: [
{
name: 'dlx_exchange',
type: 'direct',
options: { durable: true }
}
],
queues: [
{
name: 'delayed_queue',
options: {
deadLetterExchange: 'dlx_exchange',
messageTtl: 10000 // 10秒后转入死信队列
}
}
]
})
})
]
})
RabbitMQ 运维命令参考
# 查看队列状态
rabbitmqctl list_queues name messages_ready messages_unacknowledged
# 监控信道预取设置
rabbitmqctl list_channels name prefetch_count
# 创建死信队列
rabbitmqadmin declare queue name=dlx_queue durable=true
rabbitmqadmin declare exchange name=dlx_exchange type=direct
rabbitmqadmin declare binding source=dlx_exchange destination=dlx_queue routing_key=dead
关键总结:
- 生产者确认需同时开启
confirm和publisherReturns参数,通过correlationId关联异步回调 - 消费者容器通过
@RabbitSubscribe实现线程池/限流/手动ACK的集中管理 - 工程方案选择取决于场景:基础消息(方案1)、同步调用(方案2)、延迟任务(方案3)
- 运维核心:
prefetch_count控制消费速率,dead-letter-exchange处理异常消息
851

被折叠的 条评论
为什么被折叠?



