日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

故障現場 | MQ消息亂序造成的業務事故

來源: 責編: 時間:2024-04-02 17:21:50 168觀看
導讀1. 問題&分析1.1. 案例深夜,小艾接到了一通突如其來的電話,是物流系統的負責人曹工焦急的聲音。他火急火燎地反饋了一個嚴重的問題——大批用戶投訴物流信息異常,訂單狀態與實際情況不符,用戶已完成支付,但物流單還是待支

1. 問題&分析

1.1. 案例

深夜,小艾接到了一通突如其來的電話,是物流系統的負責人曹工焦急的聲音。他火急火燎地反饋了一個嚴重的問題——大批用戶投訴物流信息異常,訂單狀態與實際情況不符,用戶已完成支付,但物流單還是待支付狀態。38N28資訊網——每日最新資訊28at.com

小艾立刻警覺起來,意識到這個問題可能對公司的業務以及用戶體驗造成重大影響。她一邊安撫曹工的情緒,一邊迅速啟動緊急響應機制,通知QA對線上變更進行回滾。38N28資訊網——每日最新資訊28at.com

隨著回滾進程的推進,系統逐步恢復正常。緊接著,他手工導出上線以來的全部訂單,并與曹工一起進行數據核對,對問題數據進行修復。終于忙完了,天空已經微微發亮……38N28資訊網——每日最新資訊28at.com

1.2. 問題分析

上午稍微補了個覺,小艾洗漱完畢后對這件事進行分析:訂單已支付,物流單待支付。38N28資訊網——每日最新資訊28at.com

現在訂單和物流的系統交互如下:38N28資訊網——每日最新資訊28at.com

圖片圖片38N28資訊網——每日最新資訊28at.com

在正常的業務流程中,訂單發布事件和物流監聽事件緊密相連。38N28資訊網——每日最新資訊28at.com

  • 訂單系統發布一個“訂單已創建”事件時,物流系統會立即響應并在其內部創建一條對應的物流單據。
  • 當支付環節完成并觸發“訂單已支付”事件時,物流系統會找到關聯的物流單據并更新其為待發貨狀態。

在正常情況下,沒有出現不一致的情況。小艾想到了最近的系統變更:38N28資訊網——每日最新資訊28at.com

最近上線的一項新功能——禮品贈送。為了降低對下游系統的影響,小艾通過在應用層對流程進行編排的方式實現該功能,簡單來說,就是系統先創建訂單,然后模擬支付成功,這樣既能滿足禮品贈送的需求,又能保障下游契約消息沒有變化。新流程如下所示:38N28資訊網——每日最新資訊28at.com

圖片圖片38N28資訊網——每日最新資訊28at.com

整個流程與原來的方案沒有差別,問題究竟出現在哪呢?無奈的小艾只好打開 idea 查看源碼,終于發現問題所在:38N28資訊網——每日最新資訊28at.com

@Servicepublic class RocketMQProducer {    @Autowired    private RocketMQTemplate rocketMQTemplate;    @TransactionalEventListener    public void handle(OrderCreatedEvent event){        rocketMQTemplate.convertAndSend("order_created_event", event);    }    @TransactionalEventListener    public void handle(OrderPaidEvent event){        rocketMQTemplate.convertAndSend("order_paid_event", event);    }}

下單和支付成功使用兩個不同的 topic,兩個 topic 相互獨立,根本就無法保障投遞順序。在手動支付場景下,由于用戶從訂單創建到支付完成通常會有 5 秒以上的延遲,在這種情況下該實現可以保障邏輯的執行順序。然而在禮品贈送這個場景,系統先創建訂單,然后模擬支付成功,導致“訂單已創建”和“訂單已支付”兩個事件幾乎同時發出,在接收端就有可能先收到支付成功事件,再收到訂單已創建事件,從而導致訂單狀態和物流單狀態不一致,具體流程如下:38N28資訊網——每日最新資訊28at.com

圖片圖片38N28資訊網——每日最新資訊28at.com

如果順序錯了,就會導致業務狀態不一致:38N28資訊網——每日最新資訊28at.com

  • 物流先接到支付成功事件,在查詢物流單時由于找不到物流單所以更新失敗。
  • 隨后物流接到訂單創建事件,根據邏輯創建一條待支付的物流單,但由于該訂單的支付成功事件在上一步已經錯過,所以物流一直停留在待支付狀態。

問題終于找到了!!!38N28資訊網——每日最新資訊28at.com

2. 解決方案

2.1. 方案一:主動延時

既然是順序問題,那最簡的方法就是對支付成功消息進行延時發送。38N28資訊網——每日最新資訊28at.com

方案如下:38N28資訊網——每日最新資訊28at.com

圖片圖片38N28資訊網——每日最新資訊28at.com

中間增加一個延時組件便能解決這個問題,但不同的方案影響巨大:38N28資訊網——每日最新資訊28at.com

  • sleep 方案,會導致大量線程處于阻塞狀態,增加接口響應時間,同時降低系統的吞吐。在線上絕對不允許這種方案的出現!
  • 定時器方案,下單完成后,注冊一個定時調度任務,時間到達時調度器將自動執行任務。

定時器方案,核心代碼如下:38N28資訊網——每日最新資訊28at.com

@TransactionalEventListenerpublic void handle(OrderPaidEvent event){    // 創建Runnable任務    Runnable task = () -> {        rocketMQTemplate.convertAndSend("order_paid_event", event);    };    // 使用ScheduledExecutorService schedule方法在5秒后執行任務    executor.schedule(task, 5, TimeUnit.SECONDS);}

該方案存在幾個比較嚴重的問題:38N28資訊網——每日最新資訊28at.com

  • 全內存操作,容易操作任務的丟失。當遇到非優雅關機時,內存中的 task 就會丟失,從而導致業務邏輯不完整;
  • 異步執行,容易造成錯覺。用戶完成任務提交并不代表任務肯定會成功運行
  • 資源管理困難,如果任務量太大會大量消耗內存資源,甚至引起整個服務 OOM

2.2. 方案二:順序消息

現在不少 MQ 提供順序消息的支持,比如常見的 RocketMQ 提供了兩種類型的順序消息:全局順序消息和分區順序消息。38N28資訊網——每日最新資訊28at.com

  • 全局順序消息要求所有的消息都在一個隊列上發送和消費,因此只適用于少量隊列(通常是1個隊列,否則就無法做到全局順序)。
  • 分區順序消息則允許基于(分片鍵)進行分區,相同的消息會被發送到同一隊列中,從而在每個分區內部實現順序。

分區順序消息整體設計如下:38N28資訊網——每日最新資訊28at.com

圖片圖片38N28資訊網——每日最新資訊28at.com

核心代碼如下:38N28資訊網——每日最新資訊28at.com

@TransactionalEventListenerpublic void handle(OrderCreatedEvent event){    Long orderId = event.getOrderId();    Message<OrderCreatedEvent> message = MessageBuilder.withPayload(event)            .setHeader(RocketMQHeaders.KEYS, orderId) // 設置 Sharding Key,即訂單ID            .setHeader(RocketMQHeaders.TAGS, "OrderCreatedEvent") // 設置 Tag            .build();    // 發送至統一的 order_event_topic    rocketMQTemplate.send("order_event_topic", message);}@TransactionalEventListenerpublic void handle(OrderPaidEvent event){    Long orderId = event.getOrderId();    Message<OrderPaidEvent> message = MessageBuilder.withPayload(event)            .setHeader(RocketMQHeaders.KEYS, orderId) // 設置 Sharding Key,即訂單ID            .setHeader(RocketMQHeaders.TAGS, "OrderCreatedEvent") // 設置 Tag            .build();    // 發送至統一的 order_event_topic    rocketMQTemplate.send("order_event_topic", message);}

3. 示例&源碼

代碼倉庫:https://gitee.com/litao851025/learnFromBug38N28資訊網——每日最新資訊28at.com

代碼地址:https://gitee.com/litao851025/learnFromBug/tree/master/src/main/java/com/geekhalo/demo/mq/disorder38N28資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-80867-0.html故障現場 | MQ消息亂序造成的業務事故

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 三分鐘學會消息隊列實踐

下一篇: 你最擅長使用哪個異步編程模式?

標簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 全州县| 德昌县| 盘山县| 崇仁县| 林周县| 登封市| 红河县| 绥阳县| 津市市| 永顺县| 阿鲁科尔沁旗| 紫金县| 扎兰屯市| 西安市| 高州市| 颍上县| 广宗县| 定南县| 双流县| 高台县| 常德市| 定西市| 青冈县| 廉江市| 原阳县| 双桥区| 芒康县| 洛南县| 华亭县| 安仁县| 高密市| 尤溪县| 辽阳县| 启东市| 大厂| 宜都市| 广灵县| 梓潼县| 青海省| 鹤岗市| 遂宁市|