ConcurrentQueue适用于单进程多线程内的轻量消息缓冲,如指令排队、限流缓冲;不适用于需ACK、死信、延迟或跨机器的分布式场景。

ConcurrentQueue 适合什么场景?不适合什么场景?
当你的“消息队列”只在单进程内、多线程间流转(比如硬件指令排队、本地任务缓冲),ConcurrentQueue 是最轻量、零依赖的选择。它不跨进程、不持久化、不支持事务,但吞吐极高、无锁设计、GC 友好。
常见错误现象:ConcurrentQueue 被误用于微服务间通信——结果一重启,队列全空;或用它替代 RabbitMQ 做分布式重试,发现失败消息根本无法落盘、无法监控、无法人工干预。
- 适用:设备控制指令缓存、Web API 请求限流缓冲、后台任务暂存(如日志批量写入前的内存聚合)
- 不适用:需要消息确认(ACK)、死信处理、延迟投递、跨机器分发的场景
- 注意:
Enqueue和TryDequeue都是 O(1),但别在循环里反复TryDequeue空转——加await Task.Delay(1)或用Channel更合适
RabbitMQ 的 Connection 和 Channel 到底怎么管?
很多人写完第一版 RabbitMQ 代码就遇到连接泄漏、Channel 关闭异常、或者“Operation interrupted”错误——根源几乎都出在生命周期管理上。IConnection 是重量级对象,必须复用;IModel(即 Channel)是轻量级但**非线程安全**,不能跨线程共享,也不能长期闲置。
使用场景:高并发 Web API 接收请求后发消息,后台多个消费者线程各自独占一个 IModel 拉取消息。
-
IConnection应作为单例(如注入IServiceProvider),整个应用生命周期只创建一次 - 每个消费者线程应创建自己的
IModel,并在该线程结束时显式调用Close() - 别在
using块里创建IModel后立刻Dispose——RabbitMQ 官方客户端会抛AlreadyClosedException - 示例关键点:
channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false)必须设,否则消费者可能一次拉太多消息导致堆积或 OOM
Kafka 在 C# 里为什么总连不上 localhost:9092?
不是代码问题,99% 是 Kafka 服务端配置没对。Kafka 默认监听的是 localhost,但 Docker 容器或 WSL 环境下,.NET 客户端实际访问的是宿主机网络栈,而 Kafka server.properties 里 advertised.listeners 如果写成 PLAINTEXT://localhost:9092,消费者拿到这个地址后会尝试连自己本机的 9092 端口——自然失败。
错误信息典型表现:Unable to resolve the IP address for 'localhost' 或连接超时后抛 TimeoutException。
- Windows + Docker Desktop:把
advertised.listeners改成PLAINTEXT://host.docker.internal:9092 - WSL2:改用宿主机真实 IP(如
PLAINTEXT://172.20.10.5:9092),并确保 Windows 防火墙放行 9092 - C# 客户端用
Confluent.Kafka时,bootstrap.servers必须和advertised.listeners的协议+域名+端口完全一致 - 别跳过
group.id配置——没有它,消费者无法加入组,也就收不到任何消息
MSMQ 还值得学吗?Windows Server 环境下怎么绕过权限坑?
如果项目运行在老旧内网、离线环境、或必须满足等保三级对“国产化中间件不可用”的兜底要求,MSMQ 仍有现实价值。但它不是“过时”,而是“窄路”——一旦选了,就得接受它的规则。
最容易卡住的不是代码,是 Windows 权限。哪怕你用管理员身份运行程序,MessageQueue.Create 仍可能报 Access is denied。
- 必须先在“控制面板 → 程序和功能 → 启用或关闭 Windows 功能”中勾选“Microsoft Message Queue (MSMQ) Server”及其子项
- 创建私有队列时路径格式必须是
@".\Private$\MyAppQueue",开头的.表示本地机器,Private$不可省略或拼错 - 首次创建队列后,右键“计算机管理 → 服务和应用程序 → 消息队列 → 私有队列”,找到队列 → 属性 → 安全 → 给当前运行程序的用户(如
IIS_IUSRS或具体用户名)添加“完全控制”权限 - 事务队列(
MessageQueueTransactionType.Single)需额外启用“MSMQ Directory Service”组件,否则抛MessageQueueException
跨进程、跨机器、要重试、要监控、要可观测——这些需求一出现,ConcurrentQueue 就该让位;而 RabbitMQ 和 Kafka 的差异不在性能数字,而在你愿不愿意为“消息不丢”付出运维成本。MSMQ 的坑不在代码,在 Windows 策略和权限弹窗里——这点很容易被忽略。











