一个下单接口,同步做发短信、发邮件、加积分、写推荐关系四件事,压测下来平均 780 毫秒。短信服务商偶尔超时,整条请求就跟着卡住。把三件非核心动作挪进队列,接口回到 90 毫秒。
先分清进程内队列和跨进程队列
System.Threading.Channels 是 .NET Core 之后内置的进程内队列,不落盘、不跨机器,适合削峰和生产者消费者解耦,进程一重启消息就没了。RabbitMQ、Kafka、Azure Service Bus 属于独立中间件,能跨进程跨机器,支持持久化和重投,代价是多一套要运维的东西。
RabbitMQ 在 .NET 里的最小闭环
var factory = new ConnectionFactory(); factory.HostName = host; var conn = factory.CreateConnection(); var ch = conn.CreateModel(); ch.QueueDeclare(queue, true, false, false, null);QueueDeclare 的第二个参数 durable 为 true,队列才会在 broker 重启后保留,消息本身还要按持久化方式投递,两处都做才真的不丢。消费端用 EventingBasicConsumer,处理完手动 BasicAck;出异常时 BasicNack 并把 requeue 设为 false,让它进死信队列,而不是原地重投把消费者堵死。
选型怎么定
- RabbitMQ:路由灵活,交换机支持 direct、topic、fanout,业务消息首选,文档和社区都成熟。
- Kafka:吞吐高、可回溯,适合日志、埋点、数据库变更这类量大且需要重放的数据流。
- Azure Service Bus:不想自己运维就选托管服务,自带会话、定时投递、重复检测。
- MSMQ:只在老 Windows 内网系统里还能见到,新项目不要选。
上生产必须补的四件事
消费端要幂等,重复投递是常态,用业务单号加唯一索引兜底。重试要有次数上限和退避间隔,别用 while 循环原地硬试。消息体带版本字段,字段增删时老消费者才不会反序列化失败。连接要复用,IConnection 是长连接,每发一条消息新建一次,很快就打满文件句柄,同时记得开自动恢复和心跳。
- 判断提醒:只是想在同一个进程里解耦几个后台任务,别上 RabbitMQ,Channel 加一个 HostedService 就够了。