MQ 分布式事務 微服務應用

2022-03-08 22:28:49 字數 4051 閱讀 7884

以支付、電商下單為例子。乙個電商系統包含了好幾大類模組,就比如有使用者模組、商品模組、庫存模組、訂單模組、支付模組、物流模組,活動模組等,以下就先列舉幾個最基礎常見的模組(使用者模組、商品模組、庫存模組、訂單模組、支付模組)。

使用者流程如下:

如果系統規模較小,資料表都在乙個資料庫例項上,專案服務端也都在同乙個專案,那上面的問題基本不是問題,直接用本地事務(一致性,原子性、隔離性、永續性)解決,比如支付轉賬(a->b)模組肯定會出現a賬戶減少,b賬戶增加,程式操作加個事務管理就解決。但是如果系統規模較大,比如支付寶賬戶表和餘額寶賬戶表顯然不會在同乙個資料庫例項上,他們往往分布在不同的物理節點上,又比如商品模組,訂單模組不會在同乙個資料庫中或是在同乙個專案中,這時本地事務就已經失去用武之地了。

支付寶轉1萬元到餘額寶,如果支付寶扣除1萬後,如果系統掛掉了,餘額寶並沒有增加1萬,資料出現不一致情況。

電商系統中,當有使用者下單後,除了在訂單表插入一條記錄外,對應商品表的這個商品數量必須 減1,怎麼保證??在 搜尋廣告系統中,當使用者點選某廣告後,除了在點選事件表中 增加一條

記錄外 ,還得去商家賬戶表中找到這個商家扣除廣告費吧,怎麼保證??

不拆分服務最常見的解決方案:

本地事務:

begin transaction

update a set amount = amount - 10000 where userid = 1

update b set amount = amount + 10000 where userid = 1

end transaction

commit;

當 支付寶賬戶扣除1萬後,我們只要生成乙個憑證(訊息)即可,這個憑證(訊息)上寫著「讓餘額寶賬戶增加一萬」,只要這個憑證(訊息)能可靠保證,我們最終是可以拿著這個憑證(訊息)讓餘額寶賬戶 增加1萬的,即我們能依靠這個憑證(訊息)完成最終一致性。

支付寶在完成扣款的同時,同時記錄訊息資料,這個訊息資料與業務資料儲存在同一資料庫例項裡(訊息記錄表名為message).

begin transtration

update a set amount = amount -10000 where userid = 1;

insert into message(userid,amount,status) values (1,10000,1);

end transaction

commit;

上述事務能保證只要支付寶賬戶裡被扣了錢,訊息一定能儲存下來。

當上述事務提交成功後,我們通過實時訊息服務將此訊息通知餘額寶,餘額寶處理成功後傳送回覆成功訊息後,支付寶收到回覆後刪除該條訊息資料。

為了解耦,可以採取以下方式:

1、支付寶在扣款事務提交之前,向實時訊息服務請求傳送訊息,實時訊息服務只記錄訊息資料,而不真正傳送(只是知道有這一條訊息),只有訊息傳送成功後才會提交事務。

//支付寶 - 10000 (業務需求)

//先把(支付寶-10000)封裝成乙個訊息(new message()))

//然後把這個訊息提交到mq伺服器上send(producer.send(new message(),callback(裡面處理本地事務)))

//在callback處理本地事務:在callback方法裡:

update a set amount = amount - 10000 where userid = 1;

..............

//當本地事務操作完成了以後

1.要麼成功:(給mq乙個標識:commit)

2.要麼失敗:(給mq乙個標識:rollback)

2. 當支付寶扣款事務被提交成功後,向實時 訊息服務確認傳送,只有在得到確認傳送指令後,實時訊息服務才真正傳送該訊息。

3. 當支付寶扣款事務提交失敗回滾後,向實時 訊息服務取消傳送。在得到取消傳送指令後, 該訊息將不會被傳送。

4. 對於那些未確認的訊息或者取消的訊息,需要有乙個訊息狀態確認系統定時去支付寶系統查詢這個訊息的 狀態進行更新。為什麼需要這乙個步驟:假設在支付寶扣款事務被成功提交後,系統掛了,此時訊息狀態並未被更新為「確認傳送」,從而導致訊息不能被傳送。

優點:訊息資料獨立儲存 ,降低業務系統與訊息系統之間的耦合。

缺點:一次訊息傳送需要兩次請求;業務處理服務需要實現訊息狀態回查介面

綜合上述的描述,rabbitmq 做了這麼三件事:

1,先傳送需要傳送的訊息到訊息中介軟體broker,並獲取到該message的transactionid。在第一次傳送的時候,該訊息的狀態為localtransactionstate.unknow

2,處理本地事物。

3,根據本地事物的執行結果,結合transactionid,找到該訊息的位置,在mq中標誌該訊息的最終處理結果。

rabbitmq的結構圖如下:

1、幾個概念說明:

broker:簡單來說就是訊息佇列伺服器實體。

exchange:訊息交換機,它指定訊息按什麼規則,路由到哪個佇列。

exchange型別

a. direct exchange:將與routing key 比配的訊息,直接推入相對應的佇列,建立佇列時,預設就建立同名的routing key。

b. fanout exchange:是一種廣播模式,忽略routingkey的規則。

c. topic exchange:應用主題,根據key進行模式匹配路由,例如:若為abc*則推入到所有abc*相對應的queue;若為abc.#則推入到abc.xx.one ,abc.yy.two對應的queue。

)queue:訊息佇列載體,每個訊息都會被投入到乙個或多個佇列。

binding:繫結,它的作用就是把exchange和queue按照路由規則繫結起來。

routing key:路由關鍵字,exchange根據這個關鍵字進行訊息投遞。

vhost:虛擬主機,乙個broker裡可以開設多個vhost,用作不同使用者的許可權分離。

producer:訊息生產者,就是投遞訊息的程式。

consumer:訊息消費者,就是接受訊息的程式。

channel:訊息通道,在客戶端的每個連線裡,可建立多個channel,每個channel代表乙個會話任務。是基於connection之上建立通訊通道,因為每次connection建立tcp協議通訊開銷及效能消耗較大,所以一次建立connection後,使用多個channel通道通訊減少開銷和提高效能。

2、訊息佇列的使用過程大概如下:

(1)客戶端連線到訊息佇列伺服器,開啟乙個channel。

(2)客戶端宣告乙個exchange,並設定相關屬性。

(3)客戶端宣告乙個queue,並設定相關屬性。

(4)客戶端使用routing key,在exchange和queue之間建立好繫結關係。

(5)客戶端投遞訊息到exchange。

exchange接收到訊息後,就根據訊息的key和已經設定的binding,進行訊息路由,將訊息投遞到乙個或多個佇列裡。

exchange也有幾個型別,完全根據key進行投遞的叫做direct交換機,例如,繫結時設定了routing key為」abc」,那麼客戶端提交的訊息,只有設定了key為」abc」的才會投遞到佇列。對key進行模式匹配後進行投遞的叫做topic交換機,符 號」#」匹配乙個或多個詞,符號」*」匹配正好乙個詞。例如」abc.#」匹配」abc.def.ghi」,」abc.*」只匹配」abc.def」。還 有一種不需要key的,叫做fanout交換機,它採取廣播模式,乙個訊息進來時,投遞到與該交換機繫結的所有佇列。

MQ實現分布式事務

什麼是分布式事務 傳統的事務是基於單資料庫的本地事務,簡單的來說,分布式事務就是實現跨資料庫的事務支援 cap理論 cap理論表面在分布式系統中,最多只能滿足c,a,p中的兩個 既然最多只能選擇兩個,那選擇哪兩個比較合適呢?對於乙個分布式系統來說,可用性和分割槽容錯性是必須要滿足的。對於可用性,如果...

微服務修煉之分布式事務 seata

做過網際網路業務開發的人都知道,在高qps的業務場景中使用分布式事務是乙個大坑,系統吞吐量影響非常大,而且單點故障情況也是不得不考慮的問題。但是在微服務發展越來越猛的今天,我們不得不面臨服務組裝的問題,尤其是對於中臺建設來說,分布式事務是乙個避不開的問題。下面我們來討論一下分布式事務seata官網 ...

分布式 集群 微服務

微服務是架構設計方式 分布式是系統部署工作方式 集群是個物理形態 微服務是啥?這裡不引用書本上的複雜概論了,簡單來說微服務就是很小的服務,小到乙個服務只對應乙個單一的功能,只做一件事。這個服務可以單獨部署執行,服務之間可以通過rpc來相互互動,每個微服務都是由獨立的小團隊開發,測試,部署,上線,負責...