7.微服務-分佈式事務最終一致性(一)

1、如何做到消息一致,消息可靠投遞
2、消息中間件的使用,快速入門rabbitMQ
3、設計消息子系統(重點)

一、可靠消息最終一致(異步確保型)

在這裏插入圖片描述

實現
業務處理服務在業務事務提交前,向實時消息服務請求發送消息,實時消息服務只記錄消息數據,而不真正發送。業務處理服務在業務事務提交後,向實時消息服務確認發送。只有在得到確認發送指令後,實時消息服務才真正發送

消息
業務處理服務在業務事務回滾後,向實時消息服務取消發送。消息狀態確認系統定期
找到未確認發送或回滾發送的消息,向業務處理服務詢問消息狀態,業務處理服務根
據消息ID或消息內容確定該消息是否有效

約束
被動方的處理結果不影響主動方的處理結果,被動方的消息處理操作是冪等操作
成本
可靠消息系統建設成本
一次消息發送需要兩次請求,業務處理服務需實現消息狀態回查接口
優點、適用範圍
消息數據獨立存儲、獨立伸縮,降低業務系統與消息系統間的耦合

需要實現的服務
可查詢操作、冪等操作
方案特點
兼容所有實現AMQP標準的MQ中間件(
確保業務數據可靠的前提下,實現業務數據的最終一致(理想狀態下基本是準實時一致)
適用
1、對應支付系統會計異步記賬業務
2、普通的積分賬戶增加積分的服務

分佈式部署環境下,需要通過網絡進行通訊,就引入了數據傳輸的不確定性,也就是CAP理論中的P(分區容錯性的問題),但是我們需要保證消息儘可能的一致

消息發送一致性的概念:是指產生消息的業務動作與消息發送的一致。
(也就是說,如果業務操作成功,那麼由這個業務操作所產生的消息一定要成功投遞出去,否則就丟消息)

舉例:

/** 支付訂單處理 **/ 
public  completeOrder() { 
//訂單服務本地更新訂單狀態(業務操作) 
orderDao::update(); 
//調用積分服務給積分帳戶增加積分(發送消息) 
pointService::update(); 
}

1、如果業務操作成功,執行消息發送前應用故障,消息發不出去,導致消息丟失(訂單系統與積分系統的數據不一致);
2、如果業務操作成功,應用正常,但消息系統故障或網絡故障,也會導致消息發不出去(訂單系統與積分系統的數據不一致);

二、那消息投遞如何做到可靠呢?

看看下圖的思路:
在這裏插入圖片描述

  1. 主動方應用先把消息發給消息中間件,消息狀態標記爲“待確認”;
  2. 消息中間件收到消息後,把消息持久化到消息存儲中,但並不向被動方應用投遞消息;
  3. 消息中間件返回消息持久化結果(成功/失敗),主動方應用根據返
    回結果進行判斷如何進行業務操作處理:
    a) 失敗:放棄業務操作處理,結束(必要時向上層返回失敗結果);
    b) 成功:執行業務操作處理;
  4. 業務操作完成後,把業務操作結果(成功/失敗)發送給消息中間件;
  5. 消息中間件收到業務操作結果後,根據業務結果進行處理;
    a) 失敗:刪除消息存儲中的消息,結束;
    b) 成功:更新消息存儲中的消息狀態爲“待發送(可發送)”,緊接 着執行消息投遞;
  6. 被動方應用監聽並接收“待發送”狀態的消息,執行業務處理;
  7. 業務處理完成後,向消息中間件發送ACK,確認消息已經收到(消息 )
    中間件將從隊列中刪除該消息)

當然除了正向的流程以外還有異常的處理流程,也要保證可靠性
在這裏插入圖片描述

1、從主動方應用的角度

在這裏插入圖片描述
在這裏插入圖片描述

2.從中間件的角度

在這裏插入圖片描述
在這裏插入圖片描述

3.異常情況的總結處理

在這裏插入圖片描述

那有沒有支持這種發送一致性流程的現成消息中間件?

三、常規消息隊列的流程跟特點

在這裏插入圖片描述

MQ隊列消息模型的特點
隊列消息模型的特點:
1、消息生產者將消息發送到Queue中,然後消息消費者監聽Queue並接收消息;
2、消息被確認消費以後,就會從Queue中刪除,所以消息消費者不會消費到已經被消費的消息;
3、Queue支持存在多個消費者,但是對某一個消息而言,只會有一個消費者成功消費。

3.1、MQ隊列消息的生產與消費常規流程

在這裏插入圖片描述

常用的MQ中間件產品 ActiveMQ、RabbitMQ、kafka等基本都是這樣的流程基於AMQP協議

① Producer生成消息併發送給MQ(同步、異步);
② MQ接收消息並將消息數據持久化到消息存儲(持久化操作爲可選配置);
③ MQ向Producer返回消息的接收結果(返回值、異常);
④ Consumer監聽並消費MQ中的消息;
⑤ Consumer獲取到消息後執行業務處理;
⑥ Consumer對已成功消費的消息向MQ進行ACK確認(確認後的消息將從MQ中刪除)。

3.2、AMQP協議的認識

在這裏插入圖片描述

RabbitMQ Server: 也叫broker server,它是一種傳輸服務。 他的角色就是維護一條從Producer到Consumer的路線,保證數據能夠按照指定的方式進行傳輸。但是這個保證也不是100%的保證,但是對於普通的應用來說這已經足夠了。當然對於商業系統來說,可以再做一層數據一致性的guard,就可以徹底保證系統的一致性了。

Producer: 消息生產者,如圖A、B、C,數據的發送方。消息生產者連接RabbitMQ服務器然後將消息投遞到Exchange。

Consumer:消息消費者,如圖1、2、3,數據的接收方。消息消費者訂閱隊列,RabbitMQ將Queue中的消息發送到消息消費者。

Exchange:生產者將消息發送到Exchange(交換器),由Exchange將消息路由到一個或多個Queue中(或者丟棄)。Exchange並不存儲消息。RabbitMQ中的Exchange有fanout、direct、topic、headers四種類型,每種類型對應不同的路由規則,後面詳細介紹這四種類型。

Queue:(隊列)是RabbitMQ的內部對象,用於存儲消息。消息消費者就是通過訂閱隊列來獲取消息的,RabbitMQ中的消息都只能存儲在Queue中,生產者生產消息並最終投遞到Queue中,消費者可以從Queue中獲取消息並消費。多個消費者可以訂閱同一個Queue,這時Queue中的消息會被平均分攤給多個消費者進行處理,而不是每個消費者都收到所有的消息並處理。

RoutingKey:生產者在將消息發送給Exchange的時候,一般會指定一個routing key,來指定這個消息的路由規則,而這個routing key需要與Exchange Type及binding key聯合使用才能最終生效。在Exchange Type與binding key固定的情況下(在正常使用時一般這些內容都是固定配置好的),我們的生產者就可以在發送消息給Exchange時,通過指定routing key來決定消息流向哪裏。RabbitMQ爲routing key設定的長度限制爲255 bytes。

Connection: (連接)。Producer和Consumer都是通過TCP連接到RabbitMQ Server的。以後我們可以看到,程序的起始處就是建立這個TCP連接。

Channels: (信道)。它建立在上述的TCP連接中。數據流動都是在Channel中進行的。也就是說,一般情況是程序起始建立TCP連接,第二步就是建立這個Channel。

代碼演示:
1.生產者消費者模式
2.實現ack確認

通過我們的使用我們發現跟前面的消息一致性流程對比實際上現有的消息中間件,沒辦法滿足一致性處理的流程

那怎麼解決?

四、當前包含了消息管理子系統

在這裏插入圖片描述

消息系統組成
1.消息服務子系統:是最重要的一個子系統,它接收並存儲預發送的消息,並提供進一步的確認功能。一般需要實現以下接口服務。
存儲預發送消息(主動方應用系統)
確認併發送消息(主動方應用系統)
查詢狀態確認超時的消息(消息狀態確認子系統)
確認消息已被成功消費(被動方應用系統)
查詢消費確認超時的消息(消息恢復子系統)

2、消息管理子系統:提供一個可視化的管理界面,對可靠消息服務系統中的數據,進行查詢和管理。比如可查看已死亡的消息,可通過界面手工重發等。

3、消息狀態確認子系統:提供對異常情況的處理。當消息服務子系統收到並保存預發送消息,但因異常情況,沒有收到確認發送消息時,這種消息不可能一直留存在數據庫中。這種情況的數據,就需要消息狀態確認子系統定期撈取這些待確認超時的數據,去調用主動方應用系統中的業務查詢接口進行覈對確認。根據覈對結果決定是發送消息還是刪除數據。

4、消息恢復子系統:如果消息數據已經接收到業務確認,這種經過業務確認的消息,就一定要發送到MQ,並被消費方成功消費,絕不能丟。消息恢復子系統定期撈取那些狀態是“發送中”,而沒有被消費確認的超時消息,進行重新發送。

5、實時消息服務子系統(MQ):消費方監聽程序,接收MQ消息,成功處理後調用消息服務子系統的接口,確認消息已被成功消費,可以刪除。

整體流程:
1、用戶下單,主動方應用預發送消息給消息服務子系統。
2、消息服務子系統存儲預發送的消息。
3、返回存儲預發送消息的結果。
4、如果第3步返回的結果是成功的,則執行業務操作,否則不執行。
5、業務操作成功後,調用消息服務子系統進行確認發送消息。
6、將消息服務庫中存儲的預發送消息發送,並更新該消息的狀態爲已發送(但不是已被消費)。
7、消息中間件發送消息到消費端應用。
8、消費端應用調用被動方應用服務。
9、被動方應用返回結果給消費端應用。
10、消費端應用向消息中間件ack此條消息,並向消息服務子系統進行確認成功消費消息,
11、讓消息服務子系統刪除該條消息或者將狀態置爲已成功消費。
12、消息狀態子系統定時去查一下消息數據,看看有沒有是已發送狀態的超時消息,就是一直沒有變成已成功消費的那種消息,主動方應用系統應該提供查詢接口,針對某條消息查詢該條消息對應的業務數據是否爲處理成功
13、如果業務數據是處理成功的狀態,那麼就再次調用確認併發送消息,即進入第6步。
14、如果業務數據是處理失敗的,那麼就調用消息服務子系統進行刪除該條消息數據。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章