相关主题
场景地图见 Web3 交易所与钱包。
RabbitMQ 拆分链上监听与业务写入¶
要点卡¶
30 秒回答
RabbitMQ 用 exchange 将同一链事件路由到相互隔离的业务队列,避免慢写库阻塞其他投影。 可靠性要把两条确认链分开:Publisher Confirm 只说明 broker 已接管发布,手动 ACK 只说明 当前 delivery 已被消费者确认;二者都不等于外部数据库天然 exactly-once。消费者先做 业务幂等再 ACK,失败按可重试/毒消息分类进入有界重试或 parking queue。
3 分钟展开
- 发布端使用 durable/quorum queue、持久消息、confirm 和 mandatory/return 处理未路由消息;confirm 未知时重发仍可能重复。
- 消费端设置 prefetch 和处理 deadline;连接丢失时未 ACK delivery 可能自动重投,所以写库必须有 event identity/唯一约束。
nack(requeue=true)可能形成热循环;requeue=false只有配置 DLX 时才会死信,否则可能被丢弃。- 链事件还要携带 block hash、log ordinal 和 canonical/finality 状态;MQ 可靠不能替代 reorg 回滚与补扫。
| 记忆槽 | 内容 |
|---|---|
| 三个不变量 | confirm 与 ACK 正交;至少一次必须业务幂等;链消息保留 lineage/finality |
| 手画图 | indexer → topic exchange → isolated queues → idempotent workers → DB |
| 项目落点 | Launchpad 类 DEX 讲 K 线/持仓/返佣独立队列、parking queue 与区块补扫 |
| 一个取舍 | RabbitMQ 路由和任务队列语义直接,但长保留、大规模重放和日志流要重新评估 Kafka 等方案 |
错误表达
- ❌ “Publisher Confirm 代表消费者写库成功;
nack(false,false)一定会进 DLQ。” - ✅ “Confirm 只到 broker;是否 dead-letter 取决于 DLX 配置,消费副作用仍需幂等和对账。”
自测追问:连接在写库成功后、ACK 前断开,会发生什么?如何防止重复返佣?
10 分钟版(拓扑)¶
flowchart LR
Indexer[Block Indexer] --> Ex[block.events Exchange]
Ex --> Q1[kline.queue]
Ex --> Q2[position.queue]
Ex --> Q3[rebate.queue]
Q1 --> W1[Kline Worker]
Q2 --> W2[Position Worker]
| 模式 | 用途 |
|---|---|
| Topic Exchange | 按有界的事件域/版本路由;避免按每个 token 动态创建海量 binding |
| 手动 ACK | 处理成功再 ack;失败按错误类型选择重试或停车 |
| DLX + TTL | requeue=false 后由死信交换机进入延迟重试/parking queue |
| Prefetch | 限制 unacked 防 OOM |
Go 客户端要点(amqp091-go)
ch.Qos(prefetch, 0, false) // 限制未确认消息数,不保证绝对公平
deliveries, _ := ch.Consume(queue, "", false) // autoAck=false
for d := range deliveries {
if err := handle(d.Body); err != nil {
// requeue=true 会回原队列,毒消息可能立即热循环;
// requeue=false 才会在配置了 DLX 时进入死信/延迟重试拓扑。
_ = d.Nack(false, false)
continue
}
_ = d.Ack(false)
}
生产场景¶
- 监听与写入解耦:消息成功发布后,队列能吸收消费者写库抖动;它不能修复发布前的 RPC 漏块, 所以 indexer 仍需扫块水位、补扫和区块证据
- 与 Kafka 选型:不要只背吞吐高低;比较路由/投递、保留与重放、顺序范围、消费模型、 运维经验和实测 workload(S-RMQ-03)
深挖问答¶
- 消息丢失? → Publisher Confirm + durable/quorum queue + persistent message + 消费手动 ACK;仍要处理连接恢复和 confirm 未知结果导致的重复发布。
- 顺序性? → 单 queue + Single Active Consumer 可保持主要交付顺序,但 redelivery、优先级和失败重试会影响观察到的顺序;业务仍应带 sequence。
- 和 Kafka/RocketMQ 对比? → 先说明任务队列还是可重放事件日志,再比较路由、保留、 顺序、延迟、客户端与团队运维能力,不按公司/链类型给出绝对结论。
反模式¶
- autoAck=true → 处理失败丢消息
- 所有事件一个 queue → 慢消费者阻塞快路径
- 无 DLX → 毒消息无限 requeue
- 只保证 MQ delivery,不保存区块 hash/finality → reorg 后错误投影无法可靠回滚