怎麼設計一個優惠系統

怎麼設計一個優惠系統

參與的項目有過類似的系統,但當時不是本人負責設計,故可能有些細節問題,勿怪。

大致的流程圖:

在這裏插入圖片描述

只是大致的流程圖,細節需完善,比如最終支付完成後,肯定需要落地MySQL保存該支付信息的,還有下單操作是多線程操作,而不是圖中的單機操作,一些線程安全問題需要考慮。

大概面臨的問題:

1.改系統設計之初就需面臨高併發處理,怎麼實現多線程下單?

以目前主流框架SpringBoot爲例:
Spring是通過任務執行器(TaskExecutor)來實現多線程和併發編程,使用ThreadPoolTaskExecutor來創建一個基於線城池的TaskExecutor。在使用線程池的大多數情況下都是異步非阻塞的。然後配置註解@EnableAsync可以開啓異步任務。然後在實際執行的方法上配置註解@Async上聲明是異步任務。
總結:創建一個線程池類實現 AsyncConfigurer接口,重寫 getAsyncExecutor()方法,該方法定義線程池屬性。最後在需要執行多線程的方法上加上@Async註解(別開口就是 new Thread(),被鄙視別怪沒提醒

2.用戶排隊實現(爲什麼排隊,因爲先到先得)

可以封裝一個排隊的實體類,封裝用戶信息,要下單的商品信息,該訂單的狀態信息,時間信息等。
Redis的List數據結構是有序列表結構,可以以此實現一個隊列。然後將封裝的排隊實體類信息存進去(記得左存右取,右存左取)

3.防止惡意搶購(即一個用戶買多次)

當用戶的訂單進入Redis進行排隊時,可以設置一個自增的int值,一旦搶單成功則該值進行自增。然後在防重複校驗的過程中對該值進行判斷,是否大於原值,大於則是重複排隊,提示沒資格購買,否則則提示已經在排隊。

4.高併發下處理超賣問題

高併發環境下,容易出現多個用戶搶一個訂單且都下單成功的情況。
可以給參與活動的商品創建一個該商品的個數隊列,如參與活動的某泡麪有1000盒,某牛奶2000盒等。然後可以考慮給該泡麪創建一個長度爲1000的隊列,牛奶類似。
多線程下單時,先從該商品的個數隊列獲取數據,取到數據則說明庫存有餘,反子則說明該商品已售罄。
在使用Redis操作時,在內存中修改數據,然後存入Redis。在高併發的情況下,容易造成多個不同的操作同時修改一個數據的情況。可以引入一個自增的int值,操作時先進行與原值判斷,是否已經被修改過,若已經被修改則再次修改則拋異常。

5.訂單超時問題

超時的訂單需要進行數量回滾操作。可以採用MQ的延時消息實現,當該用戶下單成功,即訂單創建成功的時間點,同時發送一個延時消息進入MQ,大概原理即是,以延時30分鐘爲例,12:00成功創建一個訂單,12:30的時候消費系統(mq的消息消費者)會受到該消息,同時它會去查詢該訂單的支付狀態,如果支付成功,會在MySQL中生成一個訂單,如果MySQL中沒有支付,則Redis中還有該訂單信息的存在,需要刪除該訂單信息以及用戶排隊信息,並恢復庫存。

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