GitHub user Bughue edited a discussion: Seata集成RocketMQ设计

## 背景

[https://github.com/apache/incubator-seata/issues/3752](https://link.zhihu.com/?target=https%3A//github.com/apache/incubator-seata/issues/3752)

## 设计

### 前提

**seata的全局事务**

seata目前全局事务是有两种方式的,一种是saga,另一种是二阶段。我们现在希望做的是把rocketmq的事务作为一个分支加入到二阶段全局事务里,事务里同时可以和AT
 TCC等分支。

**rocketmq的事务消息**

rocketmq支持发送一个半消息(broker收到后暂不投递),然后执行本地事务,完成后通知broker是提交还是回滚这条消息(所以只涉及发送阶段一致性,消费阶段的一致性由重试和其他手动保证)

![image](https://github.com/apache/incubator-seata/assets/3788653/37f39841-40f6-48df-a690-e267d72c2129)

### 总体设计思路

本次集成的能力重点在全局事务的一阶段,我们会提供一个SeataMQProducer,在里面将以下两个方法自动加入到全局事务中。其他方法会调用到原生父类进行,不会加入到全局事务。(原因是request/oneway/批量发送/指定selector的send等很多方法在原生里也不支持事务消息)

```text
SendResult send(final Message msg) throws MQClientException, RemotingException, 
MQBrokerException, InterruptedException; SendResult send(final Message msg, 
final long timeout) throws MQClientException, RemotingException, 
MQBrokerException, InterruptedException;
```

### 方案流程

![seata-rocketmq 
drawio](https://github.com/apache/incubator-seata/assets/3788653/e189be2e-31da-4269-8e1a-511d4f7f0275)


### 时序图(commit&rollback两种情况)
![seata-rocketmq时序图(commit)](https://github.com/user-attachments/assets/216ee7c7-6567-41c2-8e01-a353da2c6500)

![seata-rocketmq时序图(rollback)](https://github.com/user-attachments/assets/216ee7c7-6567-41c2-8e01-a353da2c6500)



### 一致性问题

参考上面的时序图,考虑以下的正常流程,发现有一致性问题难以解决:

1.  TM发起全局事务
2.  注册rocketmq事务分支
3.  发送半消息
4.  执行本地事务(这里是直接返回unknown)
5.  上报rocketmq分支执行结果(目前看来TC对此只做记录,不会影响二阶段的决策)
6.  (如果4和5成功)注册并上报其他事务分支
7.  TM发起二阶段/全局事务超时

**seata分支已产生,但半消息未发送**

如果在\[3\]之前宕机了,消息未发送,seata的分支一阶段也会失败,这种情况下TC有可能发起回滚,但是在事务context里却没有messageid(无法通知mq的broker),这种情况下应该可以直接回滚成功(类似空回滚)

**seata分支已产生,半消息已发送,但发送结果和message没有放入context中**

如果在\[2\]之后\[3\]之前宕机了,TC也会发起回滚,同样的context里也没有messageid,这种情况下有两个问题,

1.  对于seata的处理,类似消息未发送的情况,rollback应该允许成功,问题解决。
2.  对于broker的回查处理,我们如果一味的返回unknown,那消息将永远不可见,不commit也不rollback

对于问题2,如果拥有回查1阶段状态的能力是可以支持的,但目前现在RM没有这个能力,所以:

-   要么改造RM,支持回查globalstatus
-   要么在这种情况下直接当成失败(消息会rollback)。

会议讨论的结论是TC支持回查,前提是在发送消息时在头部加入xid。

但随之而来的还有一个问题,如果globalstatus查不到呢?这种情况现在看来是回滚或提交已经完成且通知broker了,但broker可能还没收到或者状态还没扭转,又发起了一次回查listener,忽略就可以。

### 其他问题

**支持加入全局事务的producer方法**:目前只支持上述两个,其他的暂不考虑。

**使用切面还是直接编写SeataMqProducer**:直接写SeataMqProducer会更加好读和好维护,虽然在维护上也有其他成本,但是我们现在需要“代理”的方法少,这样做比代理类更加可控,影响范围也更加可控,不会带来额外影响。

GitHub link: https://github.com/apache/incubator-seata/discussions/6314

----
This is an automatically sent email for dev@seata.apache.org.
To unsubscribe, please send an email to: dev-unsubscr...@seata.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@seata.apache.org
For additional commands, e-mail: dev-h...@seata.apache.org

Reply via email to