高并发解决方案_高并发提交订单的解决方案
商城系統,根據不同的業務需求,歸類出幾種購買活動。比如:常規商品的購買,稀缺商品的秒殺活動,特價商品的限時優惠活動,加價換購活動,拼團活動,眾籌活動,將要發行銷售的預售活動。這里,針對預售活動場景,來進行細聊。
預售活動,一個商品,還未上市,提前進行預售,這是對市場需求的摸底。比如,某位歌手,要發行新的專輯,提前進行銷售,根據預售的情況,進行生產,而不會造成大量庫存積壓。
粉絲為了自己偶像,沖擊各種記錄,比如幾分鐘銷量破多少萬,第一天銷量多少萬,而導致預售開始的前幾十分鐘,并發很高。
商家為了更好的刺激用戶,會設置多種促銷方案,比如,實時銷量,用戶購買排行榜,購買的用戶可以解鎖某個合成的海報,可以獲得專輯的抽獎碼等。所以,用戶支付成功后,后端需要進行很多相應的處理。
根據上面的分析,預售活動,一般無需設置庫存,也就不存在由于扣減庫存導致的鎖爭奪而造成提交訂單失敗。
但是按照常規提交訂單的流程,高并發去提交訂單到一個數據庫表中,這時服務器磁盤io性能瓶頸限制了mysql性能。
首先,我們可以更換服務器的硬盤為SSD,但單臺的服務器性能始終有上限,那么我們可以通過擴展服務器的數量,橫向擴展(理論上可以無限擴展)。
比如,有1w個用戶,提交訂單,1臺數據庫服務器性能支撐不住,那么如果我們有10臺緩沖數據庫服務器,一臺緩沖數據庫服務器只需支撐1k用戶提交訂單,大大減少了服務器io壓力。最后在一個后臺任務中把緩沖數據庫中的訂單同步到訂單表中。
一臺服務器能夠支撐的并發,上限是5k,那么如果只有一臺web服務器,需要支撐1w個并發請求,也是遠遠不夠的,更何況還要處理支付成功后的幾種促銷方案。這時我們需要準備多幾臺web服務器,需要根據不斷的壓測,來決定web服務器的數量。
我們還需要一臺總入口nginx服務器,來進行輪詢訪問幾臺web服務器。這樣,其中一臺web服務器的宕機,只影響一部分用戶的訪問。同時,還需要用一臺性能差些的服務器作為入口nginx服務器的備份。
Token,身份令牌,可以讓一個用戶訪問不同的web服務器,而用戶是無感知的。而用戶具體的信息,我們可以存放到redis緩存中。這樣不同web服務器,拿到token的時候,都可以獲取到用戶id,組成一個緩存key(比如:user:session:用戶id),從而去redis獲取到用戶的相關信息,實現session在不同web服務器間共享。
1,提交訂單
(1)生成訂單號。我們可以使用“年月日時分秒+流水號”,redis的incr方法實現流水號,key值為年月,這樣每個月的流水號都從1開始。
(2)獲取緩沖數據庫的索引。比如,我們有2臺緩沖服務器。訂單流水號為1,那么index=1%2=1訂單流水號為2,那么index=2%2=0訂單流水號為3,那么index=3%2=1
(3)訂單插入到對應的緩沖數據庫中。我們可以只存訂單號,訂單數據轉化為josn字符串存放到字段中,方便擴展。訂單號為了方便搜索訂單數據。
2,寫入緩存
(1)根據用戶id和訂單號合成redis緩存key,比如“Mall:OrderBuffer:1:2020021312130100001”(1=用戶id,2020021312130100001=訂單號),把訂單詳情緩存key存放到緩存中。后面獲取所有還沒同步到訂單表的緩沖訂單號列表,就可以直接從redis中讀取。
(2)根據訂單號合成redis訂單詳情緩存key,比如“Mall:OrderBuffer:2020021312130100001”(2020021312130100001=訂單號),把訂單所有信息存放到緩存中。這樣,可以根據上面兩種redis緩存,讀取出用戶所有在緩沖表中但還沒同步到訂單表中的訂單。
3,寫入消息隊列
把訂單號和緩沖庫的索引,推送到消息隊列中,這里使用的是RabbitMQ,返回提交成功。
4,后臺訂閱任務
(1)訂閱消息隊列
(2)同步緩沖表中的訂單到訂單表中
(3)刪除緩沖表中到訂單數據
5,訂單有變更,更新緩存
訂單支付成功同步回調/異步回調,都需要判斷,緩沖訂單是否同步到訂單表中,如果沒有,需要更新緩沖數據庫中的訂單支付狀態,更新redis緩存中的訂單支付狀態。這里需要注意:如果緩存訂單在同步中,剛好支付成功回調了,要規避好邊界點。
每一個技術,很難直接生產價值,只能依托于某個產品,去兌現價值。
總結
以上是生活随笔為你收集整理的高并发解决方案_高并发提交订单的解决方案的全部內容,希望文章能夠幫你解決所遇到的問題。