關於高併發支付 秒殺的一些設計思路

2021-08-09 15:44:03 字數 2579 閱讀 8546

於高併發支付、秒殺的一些設計思路

一、問題描述

高併發支付和秒殺的場景有很多,amazon黑色星期

五、天貓雙11**、京東618等情況都是如此。假如amazon某件低價商品只有100個,庫存也就是這100份,不會再變了。在00:00秒殺開搶的那一刻,會湧入非常多的流量程序查詢(read)和下單支付(write)操作。這就是乙個非常典型的秒殺支付場景。

由於支付業務開發中,和錢相關的業務是非常重要的,不能出現任何差錯,所以需要依賴關係型資料庫例如mysql的事務和鎖的機制來保證資料的一致性。因此,對於秒殺支付的場景中,瞬時流量激增,並且都是讀相同的資料,update相同的資料。造成mysql讀寫衝突,鎖嚴重,各種的鎖等待,鎖fail等情況。這就是我們在支付秒殺業務中遇到的實際案例。

下文總結一下優化秒殺支付業務的設計思路與方向。

二、優化設計方向

1. 開源節流

2. 引入分布式快取

3. 引入mq請求佇列與非同步操作

4. 引入悲觀鎖狀態標記,解決分布式下的資料一致性

5. 業務設計的合理性

關於開源節流,目的是盡可能多的攔截的請求,減少mysql層的鎖衝突。因為一旦mysql鎖衝突多了,mysql響應變慢,但是併發量依然很高,幾乎所有請求全部timeout,那麼真正支付成功的基本沒有,那麼這個秒殺系統是失敗的案例。因此基於以上的想法,我們就需要攔截盡可能多的請求。

那麼如何做到開源節流,需要以下幾個方向:

(1) client端,禁止使用者出現double click和double payment的情況。限制client在n秒內只能發出一次秒殺請求。

(2) 在後端服務的controller層,根據請求使用者的account物件的uuid進行計數和排重。保證乙個account物件在n秒內只能發出一次秒殺請求。(這個步驟防止有hacker穿透client層直接http抓包for迴圈)

(3) 引入頁面快取,同乙個account物件的uuid,限制訪問頻度,做頁面快取,n秒內的秒殺請求,均返回同一頁面。同乙個查詢,做頁面快取,n秒內到達的請求,均返回同一頁面。

關於引入分布式快取,這裡通常使用的是主流的redis。在傳統的電商系統或是subscription billing&payment系統中,秒殺的情況都是讀多寫少的情況。場景都是先查詢,如果依然有庫存,然後發出寫請求進行支付操作;如果沒有庫存或是結果等待查詢時間過長,再次重新整理查詢請求,所以在整個秒殺過程中,大部分情況下寫請求佔0.001%,讀請求佔99.999%。因此,在讀多寫少的情況下,非常適合使用redis。redis單例項最多可以hold住qps 10w的讀請求。因此,在秒殺的讀請求99.999%全部查redis。如此限流,只有非常少的寫請求能夠到達data center,和非常少的讀請求會miss掉穿透到data center去,然而,最多的99.999%的讀請求被攔住了。

關於引入mq,作為請求佇列。為了增加支付系統的吞吐量,將秒殺支付的過程變成非同步過程。可以使用active mq作為請求佇列,對於client提交過來的支付請求(write),做請求佇列,只會透過和庫存等量的寫請求到data center層。例如:庫存有3000,這裡active mq的bet只會透過3000個message去處理。activemq中剩下的message在處理的時候,直接返回「soldout」。如果業務需求中對生成invoice的下單操作和對invoice的payment支付操作可以分離的話,也可以通過active mq將兩個操作做成非同步。

關於引入悲觀鎖狀態標記,解決分布式下的資料一致性。由於支付過程中,需要rpc訪問payment gateway service,無法使用localtransaction來保證資料一致性。因此,在最後寫請求進行支付的時候,需要在mysql的payment表中設定乙個狀態為標記payment status,在訪問payment gateway的過程中將標誌位成processing,通過悲觀鎖將這條記錄鎖住,直到payment gateway的settle成功後,將payment status置成success。在此期間其他的併發的支付請求無法對相關的invoice賬單進行支付,保證分布式資料的一致性。

關於業務設計的合理性,對於沒有必須要知道庫存數量的case,只需要顯示是否有庫存,所以快取可以直接存true和false即可。對於12306的火車票的秒殺情況,分時分段售票也是可以均攤流量的方式等等。

三、總結

client:做開源節流

web server(controller層):account uuid做limit,做頁面快取

back end service:請求佇列控制流量,做資料快取

data center:垂直切分global shard,水平切分分流資料,悲觀鎖保證分布式資料一致性

business model:考慮均攤流量

假如實際情況是1000w的請求秒殺乙個3000庫存的商品,client端和web server端可以擋住30%的無效請求。redis hold住所有的查詢請求,back end service層把寫請求傳送到amq中,bet在消費amq的時候只有前3000條訊息是可以支付成功的,後面的訊息處理會sold out。

以上只是乙個設計的思路,具體的細節還是需要根據具體的業務場景而定,離開業務的討論技術細節是不可行的。

關於高併發的一些思考

1.什麼是高併發?高併發是解決大資料量業務的一種思路,源於現實的生產生活中的問題。舉乙個現實生活中的例子 去銀行辦業務,銀行裡段時間來了100個人辦理業務,但是只有乙個視窗來辦理,平均乙個人辦完業務需要5分鐘,100個人需要500分鐘。當出現類似問題的時候,我們應該怎樣去解決呢?1 提高單個視窗辦理...

如何設計乙個高可用 高併發秒殺系統

如今的網際網路已經在海量服務領域有了很成熟的理論,因此自己也很慶幸,能夠從 0 到 1 完整踐行海量服務。微視春節專案中的集卡瓜分活動,是乙個典型的秒殺場景,自己參與其中,分享一些心得和總結。上圖是乙個典型的網際網路業務,使用者完成乙個寫操作,一般會通過接入層和邏輯層,這裡的服務都是無狀態,可以通過...

高併發的一些處理方法

最近一段時間一直在看一些高併發處理策略的文章,在此也稍微總結一下自己的心得 一.高併發 可以這麼理解高併發,在同一時間,有大量使用者同時訪問同乙個url,容易導致伺服器和資料庫資源被佔滿崩潰,資料庫的儲存和更新結果跟理想不一致,例如出現重複的資料記錄,多次新增記錄等資料錯亂問題。二.高併發的處理策略...