MQ 学习笔记

张开发
2026/6/5 21:36:25 15 分钟阅读
MQ 学习笔记
写在前面为什么要学这个在分布式系统中消息队列Message QueueMQ是绕不开的基础组件。但面对 RabbitMQ、Kafka、RocketMQ 三大主流方案很多人的困惑是它们不都是收发消息的吗有啥区别我到底该选哪个本篇笔记的目标就是彻底回答这三个问题。一、为什么要用 MQ在讨论选哪个之前先想清楚为什么要用。1.1 一个让你秒懂的类比想象你要给朋友送一份礼物 没有 MQ同步 你 ──亲自上门──▶ 朋友正在洗澡 ↓ 你在门口死等...阻塞 有了 MQ异步 你 ──丢进快递驿站──▶ [驿站] ──拿到回执──▶ 你回家打游戏 朋友忙完自己来取解耦 异步这个类比藏着 MQ 最核心的两个价值调用方不阻塞、双方不直接依赖。1.2 MQ 的三大核心价值 价值一解耦没有 MQ 的世界服务之间强依赖┌──▶ 库存服务 │ 订单服务 ──直接调用──┼──▶ 积分服务 ← 任何一个挂了订单服务受影响 │ └──▶ 通知服务引入 MQ 之后┌──订阅──▶ 库存服务 │ 订单服务 ──发消息──▶[MQ]────┼──订阅──▶ 积分服务 ← 互不认识随意扩展 │ └──订阅──▶ 通知服务上游只管发消息下游谁想消费谁来订阅。新增一个服务上游代码零改动。⚡ 价值二异步提速同步场景下用户下单需要等所有步骤完成下单请求 │ ├─ 写订单数据库 50ms ├─ 发短信通知 200ms ← 这些都是非核心步骤 ├─ 写审计日志 100ms 却让用户白白等待 └─ 发放优惠券 150ms ↓ 用户等待总计500ms 引入 MQ 之后下单请求 │ ├─ 写订单数据库 50ms ← 只等核心步骤 └─ 发消息到MQ5ms ↓ 立即返回55ms 后台异步消费发短信/写日志/发优惠券... 价值三削峰填谷大促时的流量洪峰会直接压垮数据库正常时段1,000请求/秒 ──▶ 数据库能扛✅ 大促瞬间100,000请求/秒 ──▶ 数据库直接宕机 引入MQ100,000请求/秒 ──▶[MQ蓄水池]──▶ 数据库 快速写入 慢慢消化1,000/秒匀速消费 ✅MQ 就像水库的大坝上游洪峰来了先蓄水下游按需放水永远不会被淹。1.3 小结什么时候不需要 MQ引入 MQ 也有代价系统复杂度上升、需要保障消息可靠性、多了一个需要运维的组件。适合引入 MQ不适合引入 MQ有明显的流量峰谷差异调用链路简单无峰值压力多个下游需要同一份数据强依赖实时返回结果存在耗时的非核心操作团队没有 MQ 运维能力二、认识三位主角2.1 RabbitMQ — 精细化路由专家诞生2007年 语言Erlang协议AMQP定位企业级消息中间件最核心的设计Exchange交换机RabbitMQ 不像其他 MQ 那样生产者直接往队列里塞消息它多了一层 Exchange生产者 │ ▼ Exchange交换机──路由规则──▶ Queue A ──▶ 消费者 A ──▶ Queue B ──▶ 消费者 B ──▶ Queue C ──▶ 消费者 CExchange 有三种核心模式模式路由规则类比典型场景Direct精确匹配路由键精准快递上门指定服务处理Fanout广播给所有队列全员广播通知系统公告推送Topic通配符匹配*、#按标签订阅杂志多维度消息分类其他亮点死信队列DLX消息处理失败后自动转入死信区便于排查 管理界面自带可视化Web控制台运维极友好SpringAMQPSpring原生支持Java项目集成极快2.2 Kafka — 高吞吐量日志存储怪物诞生2011年LinkedIn 语言Scala/Java协议自研 定位分布式流处理平台Kafka 的设计哲学与众不同其他 MQ 把消息视为一封信处理后即删除。 Kafka 把消息视为日志流持久保存可重复读。为什么 Kafka 这么快三大底层技术① 顺序写磁盘 随机写磁头到处跑 ──▶ 慢寻道时间长 顺序写一路追加 ──▶ 快接近内存速度 ② 零拷贝Zero-Copy 传统方式磁盘 → 内核缓冲区 → 用户态 →Socket缓冲区 → 网卡4次拷贝 零拷贝 磁盘 ──────────────────────────────────────▶ 网卡2次拷贝 利用Linuxsendfile()系统调用绕过用户态 ③ 页缓存PageCache 写入时先写OS内存缓存由操作系统异步刷盘 读取时优先命中内存极大减少磁盘IOKafka 的存储模型Partition分区Topic:order-events ├──Partition0[0,1,2,3,...]──▶ Consumer A ├──Partition1[0,1,2,3,...]──▶ Consumer B └──Partition2[0,1,2,3,...]──▶ Consumer C ↑ 每条消息有唯一Offset偏移量消费者自己记录消费到哪里✅ 优势多消费者并行消费不同分区吞吐量线性扩展⚠️ 注意分区数量不是越多越好过多会导致顺序写退化2.3 RocketMQ — 金融级全能战士诞生2012年阿里巴巴 语言Java协议自研 定位金融级分布式消息中间件RocketMQ 的底气来自哪里每年双 11万亿级消息量的实战考验。它不是在实验室里设计的是从生产环境里打出来的。它在 Kafka 高性能的基础上额外增加了大量业务特性特性解决什么问题典型场景事务消息分布式事务一致性下单 扣库存原子操作延迟消息定时触发业务逻辑下单 30 分钟未付款自动关闭消息回溯按时间重新消费故障恢复重跑历史数据死信队列消费失败兜底人工介入处理异常消息消费过滤精细化消息分发按 Tag 过滤减少无效消费RocketMQ 的存储模型CommitLog所有 Topic 消息 │ ▼ CommitLog一个顺序追加的大文件 │ ▼ ConsumeQueue每个 Topic/Queue 对应一个索引文件 │ 记录消息在 CommitLog 中的偏移量 ▼ 消费者通过 ConsumeQueue 快速定位消息 与 Kafka 的核心区别 Kafka 每个 Partition 是独立文件多文件写入 RocketMQ 所有消息写进同一个 CommitLog单文件顺序写 在分区/队列数量很多时RocketMQ 的磁盘 IO 性能更稳定。三、深度对比 — 一张表看清差异四、选型决策 — 该选谁4.1 决策树30 秒快速定位你的核心诉求是什么 │ ├─ 海量数据 / 日志采集 / 流式计算 / 大数据对接 │ └──▶ ✅ Kafka │ ├─ 电商 / 支付 / 金融 / 需要事务 延迟消息 │ └──▶ ✅ RocketMQ │ ├─ 灵活路由 / 微服务解耦 / 中小体量 / 快速上手 │ └──▶ ✅ RabbitMQ │ └─ 以上都沾边 └──▶ 继续往下看 4.2 典型场景深度拆解 场景一电商订单系统业务背景用户下单 ├── 扣减库存必须和下单保持事务一致性 ├── 发送下单成功短信非核心异步即可 ├── 发放优惠券非核心异步即可 └──30分钟未付款自动关闭订单延迟任务需求分析需求点所需 MQ 特性下单 扣库存一致性事务消息异步发短信/优惠券基础消息发送30 分钟自动关单延迟消息消息不能丢高可靠性结论✅ RocketMQ// 延迟消息示例下单后发送 30 分钟延迟消息MessagemessagenewMessage(order-close-topic,JSON.toJSONBytes(orderCloseEvent));// RocketMQ 支持 18 个延迟级别// 1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2hmessage.setDelayTimeLevel(16);// 第16级 30分钟producer.send(message);// 30 分钟后消费者才能收到这条消息// 事务消息示例下单和扣库存的分布式事务TransactionMQProducerproducernewTransactionMQProducer(order-group);producer.setTransactionListener(newTransactionListener(){OverridepublicLocalTransactionStateexecuteLocalTransaction(Messagemsg,Objectarg){try{// 执行本地事务写订单数据库orderService.createOrder(arg);returnLocalTransactionState.COMMIT_MESSAGE;// 本地事务成功提交消息}catch(Exceptione){returnLocalTransactionState.ROLLBACK_MESSAGE;// 本地事务失败回滚消息}}OverridepublicLocalTransactionStatecheckLocalTransaction(MessageExtmsg){// Broker 回查检查本地事务是否成功booleansuccessorderService.checkOrder(msg.getTransactionId());returnsuccess?LocalTransactionState.COMMIT_MESSAGE:LocalTransactionState.ROLLBACK_MESSAGE;}}); 场景二日志采集与实时分析平台业务背景全公司50个微服务 ├── 每秒产生约50万条访问日志 ├── 需要实时统计PV/UV、错误率 ├── 对接Flink做用户行为分析 └── 日志需要保留7天用于故障回溯需求分析需求点所需 MQ 特性50 万条/秒写入极高吞吐量对接 Flink/Spark流处理生态保留 7 天消息持久化 回溯多个消费方Consumer Group 隔离结论✅ Kafka日志采集架构 各微服务 │ Logback Appender/Filebeat ▼ KafkaTopic: app-logs12个Partition │ ├──▶ ConsumerGroupAFlink 实时分析 │ └── 实时大屏、告警 │ ├──▶ ConsumerGroupB写入 Elasticsearch │ └── 日志检索平台 │ └──▶ ConsumerGroupC写入 HDFS └── 离线数仓、报表 Kafka 的 Consumer Group 机制 同一条消息不同的消费组各消费一次、互不干扰。 这是 Kafka 在日志场景中碾压其他 MQ 的核心优势之一。场景三微服务事件总线业务背景一个中台系统管理20个微服务 ├── 用户注册事件 → 发给「积分服务」「邮件服务」 ├── 订单状态变更 → 根据状态发给不同服务 │ ├── 已支付 → 发给「物流服务」 │ ├── 已取消 → 发给「退款服务」 │ └── 已完成 → 发给「评价服务」「积分服务」 └── 消息量不大峰值1万/秒但路由逻辑复杂需求分析需求点所需 MQ 特性按订单状态路由到不同服务灵活路由机制一条消息多个服务同时消费多队列绑定路由规则随业务迭代频繁变化路由规则可配置、扩展零侵入团队规模小运维资源有限部署简单、管理界面友好结论✅ RabbitMQ事件总线架构 各微服务 │SpringAMQP▼RabbitMQTopicExchange:platform.events │ ├──▶ user.register ──▶ queue.points.user ──▶ 积分服务 │ ──▶ queue.email.user ──▶ 邮件服务 │ ├──▶ order.paid ──▶ queue.logistics ──▶ 物流服务 │ ├──▶ order.cancel ──▶ queue.refund ──▶ 退款服务 │ ├──▶ order.done ──▶ queue.review ──▶ 评价服务 │ ──▶ queue.points.order ──▶ 积分服务 │ └──▶ order.* ──▶ queue.audit ──▶ 审计服务全量接收 RabbitMQ 的 Topic Exchange 机制生产者只管按路由键发消息下游服务自行声明队列并绑定感兴趣的路由键。新增一个消费方上游代码零改动。这是它在微服务事件路由场景中优于 Kafka 和 RocketMQ 的核心原因。五、避坑指南无论选哪种 MQ以下三个坑都必须提前应对。坑一消息丢失 丢失可能发生在三个环节 生产者 ──[①]──▶MQBroker──[②]──▶ 消费者[③磁盘]环节解决方案① 生产者 → Broker开启生产者 Confirm 机制 失败重试② Broker 存储开启消息持久化刷盘策略③ Broker → 消费者关闭自动 Ack改为手动 Ack处理成功后再确认坑二重复消费 原因链路消费者处理成功 → 发送Ack→ 网络抖动 →Ack丢失 →Broker认为未消费 → 重新投递 → 重复消费核心原则消费端必须保证幂等性// 方案一数据库唯一键约束自动去重INSERTIGNOREINTOorder_log(msg_id,...)VALUES(?,...)// 方案二Redis 记录已处理 IDif(redis.setNX(msg:msgId,1,24h)){// 处理业务逻辑}else{// 已处理直接跳过}坑三消息积压 定位原因生产速度消费速度 → 队列持续堆积解决策略适用情况水平扩展消费者实例消费者处理能力不足优化消费逻辑批量处理、异步化单条消费耗时过长临时扩大分区/队列数需要提高并发消费上限紧急降级丢弃非核心消息极端情况保核心链路⚠️ 提前预防上线前用压测评估消费速率配置积压告警阈值如队列深度 1w 触发报警。六、总结三句话记住三个 MQ。MQ定位一句话RabbitMQ 瑞士军刀精致灵活中小业务的万能选手Kafka 重型卡车力大无穷大数据海洋的基础设施RocketMQ️ 特种兵身经百战电商金融的首选利器选型口诀大数据管道选Kafka 电商金融选RocketMQ 小巧灵活选Rabbit。避坑三件套消息不丢 → 持久化手动Ack生产者重试 不重复消费 → 消费端幂等Redis/数据库唯一键 不积压 → 压测评估扩消费者积压告警

更多文章