docs: README/CLAUDE.md 对齐 rocketmq 消费去重落地——能力表 、新模块 mq-starter-idempotent-redis、mq.idempotent.* 配置、纠正序列化过时表述

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-10 13:18:09 +08:00
parent e2a956edb1
commit 96e26c9bbb
2 changed files with 41 additions and 28 deletions

View File

@@ -111,7 +111,7 @@ public class FrontDataConsumer {
去重、批量、失败落库都是 `@MqListener` 上的属性,业务方法本身不用改:
```java
// 去重:重复消息不会再进业务(需要 MqIdempotentStoreredis-stream 自带了一个
// 去重:重复消息不会再进业务(去重状态存 Redis两个 driver 都支持,见下方说明
@MqListener(topic = "LN_Topic", group = "g", idempotent = true)
public void onData(FrontData msg) { }
@@ -139,22 +139,22 @@ public class MyErrorHandler implements MqConsumeErrorHandler {
## 两个 driver 不太一样
这点得说在前面两套实现的完整度并不一致。Redis Stream 这套是照着 core 的设计意图做全的去重、批量、失败落库、reclaim 重试都接上了RocketMQ 那套目前只做了基础收发加原生的重试和死信,去重和 `RETRY_EXHAUSTED` 落库还没接进去。
两套实现的能力大头已经对齐:去重、失败落库两端都接上了。剩下的差异主要在死信模型和批量语义:
| 能力 | Redis Stream | RocketMQ |
|---|:---:|:---:|
| 收发 / 并发消费 | ✅ | ✅ |
| 去重 `idempotent` | ✅ 内置实现 | ❌ 还没接,配了也不生效 |
| 失败落库 `RETRY_EXHAUSTED` | ✅ | ❌ 只会进原生 DLQ |
| 去重 `idempotent` | ✅(需 Redis | ✅(需 Redis |
| 失败落库 `RETRY_EXHAUSTED` | ✅ | ✅ 落库并 ACK |
| 失败落库 `SINGLE` | ✅ | ⚠️ 异常会被转成 RECONSUME_LATER |
| 批量 `batchSize` | ✅ | ⚠️ 逐条回调,靠 core 内存攒批 |
| 重试 | ✅ PEL reclaim | ✅ 原生重投 |
| 死信队列 | ❌ 只落库 | ✅ 原生 `%DLQ%` |
| 顺序消息 | ❌ | ❌ 用的 Concurrently |
| 事务 / 延迟消息 | ❌ | ❌ 没暴露 |
| 序列化 | Jackson | fastjson |
| 序列化 | fastjson | fastjson |
所以现在如果你依赖去重或者失败落库,先用 Redis Stream。RocketMQ driver 能收能发,但还没「放量」,具体见下面的 TODO
去重的状态存在 Redis`processing / success / fail` 三态 + TTL由独立模块 `mq-starter-idempotent-redis` 提供,**不看 `mq.type`**——所以 RocketMQ 部署只要能连上 Redis标准 `spring.redis.*` 配置),`idempotent = true` 一样生效。引聚合坐标的话这个模块已经打在里面;单独只引 `mq-starter-rocketmq` 的话需要自己再加一个 `mq-starter-idempotent-redis` 依赖。没开去重时它完全不碰 Redis懒连接不会因为 Redis 没配好而影响启动
## 架构
@@ -173,14 +173,15 @@ public class MyErrorHandler implements MqConsumeErrorHandler {
└─────────────────────┘ └─────────────────────┘
```
个模块:
个模块:
| 模块 | 干什么 |
|---|---|
| `mq-starter-core` | 门面 `MqTemplate``@MqListener` 扫描注册、中立信封 `MqMessage`、消费处理链、几个 SPI还有基于 `SmartLifecycle` 的启停 |
| `mq-starter-redis-stream` | Redis Stream 实现XADD / 消费组 XREADGROUP / XACK / XPENDING+XCLAIM reclaim另带一个默认的去重实现 |
| `mq-starter-idempotent-redis` | 消费去重的 Redis 存储driver 中立,不看 `mq.type`,有 Redis 就装配;配置前缀 `mq.idempotent` |
| `mq-starter-redis-stream` | Redis Stream 实现XADD / 消费组 XREADGROUP / XACK / XPENDING+XCLAIM reclaim去重经依赖 idempotent-redis 获得 |
| `mq-starter-rocketmq` | RocketMQ 实现,基于 rocketmq-spring 编程式注册 |
| `mq-spring-boot-starter` | 聚合 jar业务方引这一个就够 |
| `mq-spring-boot-starter` | 聚合 jar业务方引这一个就够(恒含 idempotent-redis |
core 是中立的,编排逻辑不依赖 Spring 和 Redis可以直接单测。想看更细的图文消费链、SPI 契约、配置速查、FAQ 都在里面),打开 [`docs/mq-starter-全景手册.html`](./docs/mq-starter-全景手册.html)。
@@ -198,15 +199,23 @@ core 是中立的,编排逻辑不依赖 Spring 和 Redis可以直接单测
| `idempotent` | false | 是否去重 |
| `errorHandler` | `""` | 失败落库的 bean 名 |
Redis Stream 这边的参数(前缀 `mq.redis-stream`,都有默认值):
去重参数(前缀 `mq.idempotent`driver 中立,都有默认值):
| 配置 | 默认 | 说明 |
|---|---|---|
| `reclaim-min-idle` | 30s | 消息投出去多久没 ack 才 reclaim 重投,要大于单条处理耗时 |
| `idempotent.processing-ttl` | 60s | 「处理中」标记存多久,建议大于处理耗时、小于 reclaim-min-idle |
| `idempotent.success-ttl` | 300s | 「已完成」标记存多久(去重窗口) |
| `idempotent.fail-ttl` | 300s | 失败标记保留多久 |
| `idempotent.key-prefix` | `mq:idem:` | 去重键前缀 |
| `enabled` | true | 逃生开关,显式 false 关闭去重 store 装配 |
| `processing-ttl` | 60s | 「处理中」标记存多久,建议大于单条处理耗时rocketmq 下还建议小于业务重试节奏的累计时长,否则并发中的消息可能反复重投直至进原生 `%DLQ%` |
| `success-ttl` | 300s | 「已完成」标记存多久(去重窗口) |
| `fail-ttl` | 300s | 失败标记保留多久 |
| `key-prefix` | `mq:idem:` | 去重键前缀 |
> 旧键 `mq.redis-stream.idempotent.*` 仍向后兼容(会打一条弃用告警),中立键和旧键同时配置时以 `mq.idempotent.*` 为准。建议尽快迁移。
Redis Stream 这边的参数(前缀 `mq.redis-stream`
| 配置 | 默认 | 说明 |
|---|---|---|
| `reclaim-min-idle` | 30s | 消息投出去多久没 ack 才 reclaim 重投,要大于单条处理耗时(且建议大于 processing-ttl |
RocketMQ 这边直接复用 rocketmq-spring 原生的 `rocketmq.*` 配置。
@@ -217,12 +226,12 @@ RocketMQ 这边直接复用 rocketmq-spring 原生的 `rocketmq.*` 配置。
P0放量到生产前想补的
- [x] 失败落库、去重、批量消费core 已做)
- [ ] 给 rocketmq driver 补上去重和 `RETRY_EXHAUSTED` 落库,跟 redis-stream 对齐
- [x] 给 rocketmq driver 补上去重和 `RETRY_EXHAUSTED` 落库,跟 redis-stream 对齐(去重 store 已抽成 driver 中立的 `mq-starter-idempotent-redis`
- [ ] 批量消费加 idle flush现在低流量下攒不满会卡着进程重启还会丢内存里没攒满的那批
- [ ] 顺序消息
- [ ] 事务消息
P1延迟消息、死信队列统一抽象、消息轨迹 / 指标、序列化可插拔(现在两边一个 Jackson 一个 fastjson、广播消费。
P1延迟消息、死信队列统一抽象、消息轨迹 / 指标、序列化可插拔(两端都是 fastjson,但硬编码换不掉)、广播消费。
P2并发度语义统一、headers 完整透传、`mq.type` 错配时 fail-fast、监控告警。