From fed75645c69e6e30e5ffcce6420d28ae291aa7ca Mon Sep 17 00:00:00 2001 From: hhs <386998068@qq.com> Date: Sun, 24 May 2026 20:58:10 +0800 Subject: [PATCH] vault backup: 2026-05-24 20:58:10 --- hhs/MQ/01-基础概念/1-MQ-基础概念.md | 38 ++++++++- hhs/MQ/01-基础概念/2-MQ-适用场景与选型原则.md | 81 ++++++++++++++++++- 2 files changed, 115 insertions(+), 4 deletions(-) diff --git a/hhs/MQ/01-基础概念/1-MQ-基础概念.md b/hhs/MQ/01-基础概念/1-MQ-基础概念.md index 8500393..5ca9f75 100644 --- a/hhs/MQ/01-基础概念/1-MQ-基础概念.md +++ b/hhs/MQ/01-基础概念/1-MQ-基础概念.md @@ -1,6 +1,9 @@ --- tags: - MQ + - 基础概念 + - 异步 + - 架构 create time: 2026-05-24 19:52 --- @@ -8,7 +11,7 @@ create time: 2026-05-24 19:52 ## 概述 -消息队列(Message Queue,简称 MQ)是一种异步通信机制,允许应用程序通过消息的生产和消费来实现解耦与协作。本文从生活类比出发,梳理核心术语、基本工作流程以及 MQ 的三大核心价值。 +消息队列(Message Queue,简称 MQ)是一种异步通信机制,允许应用程序通过消息的生产和消费来实现解耦与协作。本文从生活类比出发,梳理核心术语、Pull/Push 两种消费模型、基本工作流程、MQ 的三大核心价值,以及引入 MQ 需要付出的代价。 ## 正文 @@ -53,6 +56,22 @@ sequenceDiagram > [!question] > 第 6 步的 Ack 确认机制为什么重要?如果没有 Ack 会怎样? +### Pull vs Push:两种消费模型 + +流程图第 3 步提到了"拉取"和"推送"两种方式,这其实是消息消费的两种根本模型: + +| 维度 | **Pull(拉取)** | **Push(推送)** | +|------|-----------------|-----------------| +| 主动方 | Consumer 主动拉取 | Broker 主动推送 | +| 消费节奏 | Consumer 自己控制,想拉多少拉多少 | Broker 控制推送速率,Consumer 被动接收 | +| 适用场景 | 消费能力不均匀、需要精确控速 | 低延迟要求、实时性敏感 | +| 典型代表 | Kafka、RocketMQ(默认) | RabbitMQ、MQTT | + +**简单理解**:Pull 是"我去超市买东西"(我决定什么时候买、买多少),Push 是"外卖送到家门口"(商家决定什么时候送)。 + +> [!tip] +> 大多数现代 MQ 默认采用 Pull 模式,因为 Consumer 更清楚自己的处理能力,天然具备背压(Backpressure)能力。详细的流控与背压机制见 [[31-MQ-背压与流控]]。 + ### MQ 的三大核心价值 #### 1. 解耦 @@ -140,7 +159,24 @@ func ConsumeSeckill() { > [!question] > 如果不需要解耦和削峰,还有必要引入 MQ 吗? +### MQ 引入的代价 + +MQ 不是银弹,引入它就意味着接受以下挑战: + +1. **运维复杂度上升**:多了一个需要监控、扩容、容灾的中间件。Broker 挂了怎么办?消息积压怎么告警?这些都是新增的运维命题。 +2. **消息丢失与重复**:网络不可靠,消息可能丢、可能重复投递。你需要设计 ACK 机制、幂等消费、甚至 Exactly-Once 语义——这些都不简单。 +3. **系统可用性转移**:原本你的可用性取决于自己,现在还取决于 Broker。Broker 成了新的单点风险。 +4. **调试链路变长**:同步调用出了问题,顺着调用栈就能排查。引入 MQ 后,消息可能在队列里"躺"了很久才被消费,排查问题的难度显著增加。 + +> [!warning] +> 在决定引入 MQ 之前,先问自己:**我真正需要的是解耦、异步还是削峰?** 如果答案都是"不太需要",直接调用可能是更简单可靠的选择。何时该用 MQ 见 [[2-MQ-适用场景与选型原则]]。 + +> [!tip] +> **一句话总结**:MQ 通过引入"中间人"角色,实现了生产者与消费者之间的解耦、异步和削峰,但代价是更高的系统复杂度和最终一致性。理解这个 trade-off,是用好 MQ 的第一步。 + ## 关联笔记 - [[2-MQ-适用场景与选型原则]] - [[3-MQ-消息模型]] +- [[12-MQ-消息确认与持久化]] — Ack 机制的详细设计 +- [[28-MQ-Competing-Consumers-模式]] — Partition 并行消费的实战模式 diff --git a/hhs/MQ/01-基础概念/2-MQ-适用场景与选型原则.md b/hhs/MQ/01-基础概念/2-MQ-适用场景与选型原则.md index 0d877e3..5874e1e 100644 --- a/hhs/MQ/01-基础概念/2-MQ-适用场景与选型原则.md +++ b/hhs/MQ/01-基础概念/2-MQ-适用场景与选型原则.md @@ -1,6 +1,10 @@ --- tags: - MQ + - 架构 + - 异步 + - 选型 + - 流量削峰 create time: 2026-05-24 19:52 --- @@ -125,9 +129,37 @@ MQ 解决了分布式系统中的很多问题,但有些场景引入 MQ 反而 游戏服务器的实时状态同步、在线聊天等场景要求毫秒级响应。MQ 的存储转发机制会引入额外延迟,直接 WebSocket 或长连接更合适。 +### 你需要 MQ 吗?——决策引导 + +在进入选型细节之前,先回答一个更根本的问题:**你的系统是否真的需要 MQ?** + +很多团队在"技术潮流"的驱动下盲目引入 MQ,最后发现自己在用大炮打蚊子。下面这个流程图帮你快速判断: + +```mermaid +graph TD + START["你有异步通信需求吗?"] -->|否| NO["不需要 MQ,直接调用即可"] + START -->|是| Q1{"需要解耦多个下游?"} + Q1 -->|是| YES["建议引入 MQ"] + Q1 -->|否| Q2{"有流量突增需要削峰?"} + Q2 -->|是| YES + Q2 -->|否| Q3{"有非核心链路可异步化?"} + Q3 -->|是| YES + Q3 -->|否| Q4{"需要消息持久化和重试?"} + Q4 -->|是| MAYBE["考虑 MQ 或轻量方案"] + Q4 -->|否| SIMPLE["考虑 goroutine 池或任务队列"] + + style YES fill:#27AE60,color:#fff + style NO fill:#95A5A6,color:#fff + style MAYBE fill:#F39C12,color:#fff + style SIMPLE fill:#3498DB,color:#fff +``` + +> [!warning] +> 不要因为"别人在用"就引入 MQ。如果你的需求只是简单的后台任务,一个 goroutine 池 + channel 就能搞定,不需要动用分布式 Broker。 + ### 选型决策框架 -选型时需要综合考虑以下维度,没有"最好"的 MQ,只有"最合适"的: +确认需要 MQ 后,选型时需要综合考虑以下维度。没有"最好"的 MQ,只有"最合适"的: | 维度 | Kafka | RabbitMQ | RocketMQ | Pulsar | |------|-------|----------|----------|--------| @@ -138,6 +170,21 @@ MQ 解决了分布式系统中的很多问题,但有些场景引入 MQ 反而 | 生态 | 极丰富(Flink/Spark) | 成熟(插件体系) | 较丰富 | 成长中 | | 典型场景 | 大数据管道、日志 | 企业应用、复杂路由 | 电商、金融 | 多租户、云原生 | +下面是基于核心需求的快速决策路径: + +```mermaid +graph TD + START["确认需要 MQ"] --> Q1{"核心需求是什么?"} + Q1 -->|"大数据 / 日志管道"| Kafka["Kafka"] + Q1 -->|"灵活路由 / 企业集成"| RabbitMQ["RabbitMQ"] + Q1 -->|"事务消息 / 电商金融"| RocketMQ["RocketMQ"] + Q1 -->|"多租户 / 云原生"| Pulsar["Pulsar"] + Q1 -->|"极致轻量 / 低延迟"| NATS["NATS"] +``` + +> [!tip] +> 如果你拿不准,**RabbitMQ 是最稳妥的起步选择**——运维简单、文档完善、社区活跃。等业务规模增长后,再根据瓶颈点考虑迁移。更多维度的深度对比见 [[27-MQ-选型对比]]。 + > [!question] > 如果你的团队只有 3 个人,系统日均消息量 10 万条,你会选择哪个 MQ?为什么? @@ -156,7 +203,35 @@ MQ 解决了分布式系统中的很多问题,但有些场景引入 MQ 反而 记住一个原则:**用户需要立即看到结果的操作,不要异步化。** +**忽略幂等设计** + +这是引入 MQ 后最容易翻车的地方。网络抖动、消费者重启、Broker 重试都可能导致同一条消息被投递多次。如果消费者的处理逻辑不是幂等的,结果就是重复扣款、重复发货、重复积分。 + +```go +// 非幂等: 消息重投会导致重复扣款 +func HandlePayment(msg Message) { + db.UpdateBalance(msg.UserID, -msg.Amount) // 每次执行都扣一次! +} + +// 幂等: 利用消息 ID 做去重 +func HandlePayment(msg Message) { + if db.Exists("processed:" + msg.ID) { + return // 已处理过,跳过 + } + db.UpdateBalance(msg.UserID, -msg.Amount) + db.Set("processed:" + msg.ID, true) +} +``` + +> [!warning] +> 上 MQ 之前,先确保每个消费者都有幂等保障。幂等不是可选项,是必选项。详细设计见 [[14-MQ-消息幂等性]]。 + ## 关联笔记 -- [[1-MQ-基础概念]] -- [[3-MQ-消息模型]] +- [[1-MQ-基础概念]] — MQ 是什么、核心术语、Pull/Push 模型 +- [[3-MQ-消息模型]] — 队列与发布订阅模型的深入对比 +- [[27-MQ-选型对比]] — 七大维度横向对比各主流 MQ +- [[14-MQ-消息幂等性]] — 幂等消费的设计方案 +- [[12-MQ-消息确认与持久化]] — ACK 机制如何保证消息不丢 +- [[16-MQ-死信队列与消息回溯]] — 消费失败后的兜底处理 +- [[46-MQ-分布式事务实践]] — 事务消息在电商/金融场景的实战