跳到主要内容
版本:1.0.0(开发版)

事务消息

事务消息用于协调事件可见性与生产者侧业务事务。Broker 先存储准备消息,即半消息,生产者再报告本地提交、回滚或结果未知。它不是横跨 Broker 存储和应用数据库的分布式 ACID 事务。

使用注册了 TransactionListener、注入了 ClientRuntimeTransactionMQProducer。普通生产者上的同名方法不能替代事务生产者初始化。先阅读生产者生命周期,并创建目标业务主题。

准备、决策与回查

最后一条箭头表示具备投递资格,不代表立即回调或业务已处理。半消息响应继承当前存储及复制策略,不能把所有已接纳半消息都描述为已持久复制。

当前客户端仅在 SendOk 时执行本地监听器。FlushDiskTimeoutFlushSlaveTimeoutSlaveNotAvailable 会选择回滚,不执行该监听器。在获得可用发送结果前发生传输错误,则直接返回错误。部分非成功状态仍可能对应已接纳的日志追加,因此需要区分这些分支。

实现可恢复的决策

TransactionListener 包含两个同步回调:

回调职责
execute_local_transaction(&dyn MessageTrait, Option<&(dyn Any + Send + Sync)>)幂等执行本地业务,返回 LocalTransactionState
check_local_transaction(&MessageExt)读取权威持久化结果,返回同一状态域

两者均返回 CommitMessageRollbackMessageUnknown。回调工作应有界。客户端通过受管理的阻塞边界运行本地执行;调用者超时或 panic 映射不会回滚已经提交的外部事务。

以下是应用伪代码,并非完整数据库实现:

execute(message):
event_id = 消息携带的稳定业务标识
在同一本地数据库事务中:
若已有结果记录:返回该结果
幂等应用业务变更
持久化 event_id 与最终业务结果
仅在确认提交后返回 CommitMessage

check(message):
使用 event_id 读取权威结果
已提交 -> CommitMessage
已确定中止 -> RollbackMessage
不可用或未解决 -> Unknown

不要把进程内 map 作为恢复依据。生产者重启,或同组其他合格生产者接到回查时,必须能够通过持久化业务状态回答。回调可选的内存参数不会作为持久事务元数据由 Broker 回传。

状态缺失需要业务策略:它可能表示尚未执行、暂不可见或存储不可用。把所有查询失败都返回为回滚,可能隐藏已提交的业务变更;永久返回未知则会积累未解决工作,并最终受到 Broker 配置的回查或丢弃策略约束。

集成生产者

以下片段假设 client_runtime 是应用共享运行时,listener 是真实的 TransactionListener 实现:

let mut producer = TransactionMQProducer::builder(client_runtime.clone())
.producer_group("docs_transaction_group")
.name_server_addr("127.0.0.1:9876")
.topics(vec!["TransactionSendTestTopic"])
.transaction_listener(listener)
.build();

发送前启动生产者,并检查返回 TransactionSendResult 中的两个字段:

let message = Message::builder()
.topic("TransactionSendTestTopic")
.key("order-1001:event-1")
.body("order created")
.build()?;
let outcome = producer
.send_message_in_transaction::<(), _>(message, None)
.await?;

send_result 描述准备消息发送,local_transaction_state 描述客户端决策。两个字段都不是 Broker 最终提交回执。 当前实现会记录结束事务请求失败,但仍可能返回 Ok(TransactionSendResult)。应保持事务回查可用,以弥合这个故障窗口。

在未完成工作已经解决,或交给明确恢复流程后,依次关闭事务生产者、共享 ClientRuntime、RuntimeOwner 和遥测设施。返回未知后立即停机,会使当前进程无法回答后续回查。

故障窗口

窗口对应用的影响
半消息结果不确定不应假定消息不存在;通过稳定业务标识协调状态
业务已提交,报告提交前进程退出Broker 回查必须恢复持久化的已提交结果
结束事务请求失败本地返回提交不能证明消费者立即可见
回查到达不共享状态的生产者该组无法可靠解决待定事务
业务执行或回查 panic当前客户端将回调失败映射为未知;需要排查底层操作
消费者副作用已提交,但进度未持久化消费者可能再次收到已提交消息

事务消息不会消除消费者幂等要求,详见投递与重试

限制与组合条件

当前事务路径拒绝延迟或定时属性,包括延迟级别、相对延迟和绝对投递时间。不要组合普通批量 API 与事务发送,并由此推断支持批次事务。

回查设置要求 min/max 均为正值、min 不大于 max、请求保留上限为正值。实现采用准入信号量:max 限制并发回查,hold max 限制已接纳回查工作。min 会被校验,但不能据此认为会创建指定最小数量的专用操作系统线程池。

Broker 回查间隔、最大回查次数、事务服务可用性和生产者连通性都会影响结果解决。它们属于部署条件;只有监听器类型存在,不能证明完整事务路径已经配置。

阅读示例时区分接口演示与恢复验证

rocketmq-example/ 中执行:

cargo check --example producer-transaction-send
cargo run --example producer-transaction-send

先在回环集群创建 TransactionSendTestTopic。示例在内存中交替返回提交、回滚、未知,发送六条后关闭。它展示监听器接入和结果结构,没有持久化业务事务日志,也不会持续运行以证明所有未知消息最终解决。

验证应用事务集成时,应保持可回查生产者在线,在消费者侧观察仅已提交业务事件可见,并单独演练本地提交后、报告结束事务前的重启窗口。记录该场景的真实结果;编译示例不等于完成这种验证。

源码依据:事务 facade发送与决策路径回查调度示例