ソースすることであなたを教えて、最終的にはアリRocketMQトランザクションメッセージが退行したもので

「インターネット業界のおかげでMQ負荷シフト、デカップリング、非同期操作およびその他の機能は、分散サービスへの場所を持っていると言うことができ、MQはしばしば存在しないことはないだろう。」

RocketMQの研究所からのアリより経験豊富な二重の取引メッセージの追跡レポートに関連するソースコードのRocketMQ 4.5.0バージョンの新機能情勢ニュース紙の4.3.0バージョンを発売し、高い同時実行上の課題、の11年は、読書を通じて知ることができます:

  • 問題のいずれかの種類を解決するために、Transactionメッセージ

  • その設計の原則は、取引メッセージを強調します


01--すべての問題を解決します

私は今、このようなシナリオがあるシステムと仮定します。

ローカルオープン引き落としトランザクションデータベース、ストックセンターへの配信成功後に送信されるMQメッセージ。

一部の人々はまだライン上で一緒にオープンMyBatisのトランザクションの実装、ローカル・トランザクションおよびMQメッセージングではないと思うかもしれ?MQが正常に送信された場合は、一度にトランザクション、全体の操作をロールバックに失敗した送信し、トランザクションをコミットします。

ソースすることであなたを教えて、最終的にはアリRocketMQトランザクションメッセージが退行したもので


一見問題が、ないネットワークが信頼できるものではありませんインチ

応答オーバーMQの戻り仮定ネットワークは、その理由をもらっていないので、私は不確実なリターンMQ結果の顔にロールバックする必要がありましたので。しかし、MQサーバはそう失敗担当、成功した配信の結果であり、実際にこのメッセージを受信したが、失われたクライアントに応答します。

ソースすることであなたを教えて、最終的にはアリRocketMQトランザクションメッセージが退行したもので


MQメッセージとローカル業務を送っているので、全体的な需要はそれの原子性を持っていることを確認する方法を、一緒に書き込むことはできませんか?:答えは、今日私たちが主人公紹介ということであるトランザクションメッセージを

02 - 概要

ソースすることであなたを教えて、最終的にはアリRocketMQトランザクションメッセージが退行したもので


全体RocketMQ取引メッセージは、2つの主要なラインに分割されています

  1. 送信プロセスタイマタスク:送信半メッセージ(メッセージの半分)は、ローカル・トランザクションを実行するトランザクションの実行結果を送信します

  2. 定期的なタスクの逆流を確認してください:MQサーバーをバックローカル業務をチェックするために、トランザクションの結果を送りました

したがって、この紙はまた、ソースの二つの主要な線によって分析しました

03--ソースコード解析

セミメッセージ送信プロセス

ローカルアプリケーション(クライアント)

在本地应用发送事务消息的核心类是TransactionMQProducer,该类通过继承DefaultMQProducer来复用大部分发送消息相关的逻辑,这个类的代码量非常少只有100来行,下面是这个类的sendMessageTransaction方法

ソースすることであなたを教えて、最終的にはアリRocketMQトランザクションメッセージが退行したもので


这个方法做了两件事,

  1. 检查transactionListener是否存在

  2. 调用父类执行事务消息发送

TransactionListener在事务消息流程中起到至关重要的作用,一起看看这个接口

ソースすることであなたを教えて、最終的にはアリRocketMQトランザクションメッセージが退行したもので


接口注释说的很明白,配合上面的概览图来看就是,executeLocalTransaction方法对应的就是执行本地事务操作,checkLocalTransaction对应的就是回查本地事务操作。

下面是DefaultMQProducer类的

sendMessageInTransaction方法源码

ソースすることであなたを教えて、最終的にはアリRocketMQトランザクションメッセージが退行したもので


为了使源码的逻辑更加直观,笔者精简了核心代码。sendMessageInTransaction方法主要做了以下事情

  1. 给消息打上事务消息相关的标记,用于MQ服务端区分普通消息和事务消息

  2. 发送半消息(half message)

  3. 发送成功则由transactionListener执行本地事务

  4. 执行endTransaction方法,如果半消息发送失败本地事务执行失败告诉服务端是删除半消息,半消息发送成功本地事务执行成功则告诉服务端生效半消息。

发送半消息流程,Client端代码到这里差不多就结束了,接下来看看RocketMQ Server端是如何处理的

RocketMQ Server

Server在接收到消息过后会进行一些领域对象的转化和是否支持事务消息的权限校验,对理解事务消息用处不大,此处就省略对旁枝末节的介绍了。下面是TransactionalMessageBridge类处理half message的源码

ソースすることであなたを教えて、最終的にはアリRocketMQトランザクションメッセージが退行したもので


这两个方法主要做了以下事情:

ソースすることであなたを教えて、最終的にはアリRocketMQトランザクションメッセージが退行したもので


  1. 将消息的topic,queueId放进消息体自身的map里进行缓存

  2. 将消息的topic设置为“RMQ_SYS_TRANS_OP_HALF_TOPIC”,将queueId设置为0

  3. 将消息写入磁盘持久化

可以看到所有的事务半消息都会被放进同一个topic的同一个queue里面,通过对topic的区分,从而避免了半消息被consumer给消费到

Server将半消息持久化后然后会发送结果给我们本地的应用程序。到了这里Server端对半消息的处理就结束了,紧接着的是定时任务的登场。

定时任务回查流程

RocketMQ Server

定时任务是一个叫TransactionalMessageService类的线程,下面是该类的check方法

ソースすることであなたを教えて、最終的にはアリRocketMQトランザクションメッセージが退行したもので


check方法非常长,省略的代码大致都是对半消息进行过滤操作(如超过72小时的事务消息,就被算作过期),只保留符合条件的半消息对其进行回查。

其中很有意思的是putBackHalfMsgQueue方法,因为每次把半消息从磁盘拉到内存里进行处理都会对其属性进行改变(例如TRANSACTION_CHECK_TIMES,这是是否丢弃事务消息的关键信息)。

所以在发送回查消息之前需要对半消息再次放进磁盘。

RocketMQ采取的方法是基于最新的物理偏移量重新写入,而不是对原有的半消息进行修改,其中的目的就是RocketMQ的存储设计采用顺序写,如果去修改消息 ,无法做到高性能。

下面是resolveHalfMsg方法,主要就是开启一个线程然后发送check消息。

ソースすることであなたを教えて、最終的にはアリRocketMQトランザクションメッセージが退行したもので


本地应用(client)

下面是DefaultMQProducerImpl的checkTransactionState方法,是本地应用对回查消息的处理逻辑

ソースすることであなたを教えて、最終的にはアリRocketMQトランザクションメッセージが退行したもので


精简代码逻辑后可以清晰的看到

  • 开启一个线程来执行回查的逻辑

  • 执行transactionListener的checkLocalTransaction方法来获取本地事务执行的结果

RocketMQ Server

RocketMQ 服务器在收到Client发过来的Commit消息后会

读出半消息——>恢复topic等原消息体的信息——>和普通消息一样再次写入磁盘——>删除之前的半消息

如果是Rollback消息则直接删除之前的半消息

到此,整条RocketMQ 事务消息的调用链就结束了

04——思考

1. 分布式事务等于事务消息吗?

两者并没有关系,事务消息仅仅保证本地事务和MQ消息发送形成整体的原子性,而投递到MQ服务器后,消费者是否能一定消费成功是无法保证的。

2. 源码设计上有什么亮点吗?

通过对整条链路源码的学习理解发现还是有不少亮点的

  • server端回查消息的发送,client端回查消息逻辑的处理,client端commit/rollback消息的提交都是用了异步进行,可以说能异步的地方都用了异步,通过异步+重试的方式保证了在分布式环境中即使短暂的网络状况不良好,也不会影响整体逻辑。

  • 引入TransactionListener,真正做到了开闭原则以及依赖倒置原则,面向接口编程。整体扩展性做得非常好,使用者只需要编写自己的Listener就可以做到事务消息的发送,非常方便

  • TransactionMQProducer通过继承DefaultMQProducer极大地复用了关于发送消息相关的逻辑

3. 源码设计上有什么不足吗?

RocketMQ作为一款极其成功的消息中间件,要发现不足不是那么容易了,笔者谈几点看法

  • sendMessageIntransaction他のトランザクションに関連する方法は、凝集の観点から、内部DefaultMQProducer分割され、これは関連する方法はTransactionMQProducerを分割しなければならないメッセージトランザクションで送信されます。

  • すべての半トピックメッセージはメッセージキューRMQ_SYS_TRANS_OP_HALF_TOPICの半分のためのトピックに書かれており、それぞれの半分のメッセージは、全体の書かれた多くの回内のリンク、同時大とメッセージのほとんどの場合があるだろう、そのメッセージは、トランザクション、信頼性があります問題があるでしょう。


おすすめ

転載: blog.51cto.com/14480698/2427417