大家好,我是君哥。
消息隊列的主要功能是系統間解耦,實現流量的削峰填谷。主流的消息隊列一般有三個核心操作:消費者發送消息,Broker 保存消息,消費者消費消息。如下圖:
圖片
對于一個完整的事務消息,可以理解為生產者生產消息和消費者消費消息,這兩個操作要不全部成功要不全部失敗。但事實上,很難有消息隊列來實現生產消息和消費消息的事務特性。
一些消息隊列在生產端實現事務消息,對生產的一批消息要不全部發送成功,要不全部發送失敗。
下圖是 RabbitMQ 的事務消息:
圖片
RabbitMQ 的事務消息實現的就是生產者的事務消息,發送消息的時候,把 Channel 設置為事務模式,這樣這一批消息就會緩存在 Channel,等提交事務時才會提交到 Broker。可以參考下面代碼:
ConnectionFactory factory=new ConnectionFactory();cnotallow=factory.newConnection();Channel channel=connection.createChannel();//開啟事務channel.txSelect();channel.basicPublish("directTransactionExchange","transactionRoutingKey",null,message.getBytes("utf-8"));//提交事務 或者 channel.txRollback()回滾事務channel.txCommit();
Kafka 的事務消息類似,指定一個事務 id,集群中不同的生產者都可以使用這個事務 id 來實現事務消息。看下面代碼:
String transactionId = "xxxx123yyy"Properties properties = new Properties();properties.put(ProducerConfig.TRANSACTIONAL_ID_CONFIG, transactionId);KafkaProducer<String, String> producer = new KafkaProducer<String, String>(properties);//開啟事務消息producer.initTransactions();producer.beginTransaction();try { //發送消息 String topic = "testTransactionId" producer.send(new ProducerRecord<String, String>(topic, "msg1")); producer.send(new ProducerRecord<String, String>(topic, "msg2")); producer.send(new ProducerRecord<String, String>(topic, "msg3")); // 提交事務 producer.commitTransaction();} catch (ProducerFencedException e) { producer.abortTransaction();}producer.close();
使用同一個事務 id 后,集群中的多個生產者可以實現對不同 Topic、不同分區的原子性寫入。在提交事務之前,這些消息是不可見的,事務提交之后,這些消息才能變為可見。
生產者加本地事務也是消息隊列事務消息的一種實現方式。這種事務是指本地事務和生產者生產消息是一個原子性操作,要不都成功,要不都失敗。如下圖所示:
圖片
RocketMQ 的事務消息是首先發送 half 消息到 Broker,然后執行本地事務,最后執行 commit/rollback 操作。執行了 commit 操作后,消費者就可以拉取到這條消息了。如下圖:
圖片
RocketMQ 的 half 消息是將消息投遞到 topic 為 RMQ_SYS_TRANS_HALF_TOPIC 中 queueId 等于 0 的隊列中,當 RocketMQ 發送 commit 消息后再把消息投遞到原始隊列,這樣消費者就可以拉取到這條消息了。
從上面的講解可以看到,消息隊列的事務消息使用的是兩階段提交的方式。那跟 TCC 模式的兩階段提交有什么區別呢?這節我們來看一下 TCC 模式。
TCC 模式將分布式事務分為 try 和 commit/rollback 兩個階段來執行,try 階段對每個分支事務進行預留資源,如果 try 階段所有節點都執行成功,則進入 commit 階段提交全局事務,只要有一個節點執行失敗則進入 rollback 階段回滾全局事務。
TCC 模式有三個角色,TM、RM 和 TC:
以購物場景中保存訂單、扣減庫存、扣減金額的例子來講,try 階段如下圖:
圖片
commit/rollback 階段如下圖:
圖片
可以看到,TCC 模式的兩階段提交,第一階段是用來嘗試預留資源,第二階段來扣減資源或釋放資源。而消息隊列中生產消息、保存消息、消費消息是不需要預留資源的,這是完全不同的業務場景。
本文主要講述了消息隊列中的事務消息跟分布式事務中兩階段提交的 TCC 模式在實現方式上的區別。TCC 模式中兩階段提交的目的主要是用來確定資源是否可用,而消息隊列的事務消息是不需要考慮資源的,二者是不同的業務場景。
本文鏈接:http://www.tebozhan.com/showinfo-26-14709-0.html阿里二面:消息隊列的事務消息可以用 TCC 模式實現嗎?
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com