最近某披薩品牌與知名遊戲的聯動再次衝上熱搜,只不過原因是許多用户在支付過程中遇到問題,出現長時間無法支付,重複支付等異常情況。本文想要從一般的秒殺及支付系統的設計方面探討一下故障出現的可能原因,以及預防方案,最後聊一聊區塊鏈在這方面的解決方案。由於作者並不瞭解本次故障具體的技術細節,所以文中可能包含大量的主觀推測,還請讀者見諒。
流程覆盤
活動開始當日上午9點,披薩APP上開啓活動產品的預約,不久,產品就已售罄。同時,社交網絡上開始出現“披薩APP崩潰“的用户反饋。主要反饋的問題有:
- 訂單已經支付,但是顯示支付未完成
- 一份訂單支付成功兩次
- 訂單無法支付(提示網絡異常)
在大量用户反饋問題之後,披薩品牌表示會將訂單的可支付時間由半小時延長到24小時。
問題分析
本次活動的主要步驟可以分解為:1. 創建訂單;2.支付訂單。
在創建訂單這一步是沒有出現用户反饋問題的,儘管同時搶購的用户數量很多,但是一般只需要合理地將用户進行分區,例如,假設產品限量10萬份,可以創建10個並行的服務,每個服務上放置預先生成的1萬份產品編碼,我們這裏用 token 來表示。然後使用哈希將用户分流到這10個服務上。每個服務就只需要維護1萬 token 的集合。
主要問題是在支付訂單這一步,首先,只有獲得 token 的用户才有資格進行支付。那麼當服務器拿到用户發來的 token 的時候,需要做以下工作:1. 驗證此token是否是真實的;2. 驗證此token是否過期;3. 驗證此token是否被使用過。
第一步是比較簡單的,可以使用數字簽名技術來驗證,比如每個 token 都是有商傢俬鑰簽名的。第二步也很簡單,token內的時間戳和當前的時間對比一下,就知道有沒有過期。真正複雜的是第三步,我們剛才提到了,總共有 10 萬份產品,那麼至少就有 10 萬個 token,且它們一直在更新(每時每刻都有訂單支付成功,支付成功,token 失效)。這意味着這一步是無法並行的,一旦並行,就有可能出現雙花 ———— 一個 token 被使用兩次。
這一步裏極大的串行任務的堆積,有可能是導致服務崩潰的主要原因。
另外,有用户表示同一筆訂單支付了兩次,這是因為大多數用户使用的是第三方支付服務,在“支付成功->token失效“這個過程中,如果中間斷開了,就可能導致支付兩次。
解決方案
首先我們探討一下在業務層面的解決方案,可以採用預付訂金的機制,比如,在活動開始前的一週裏,用户可以預付訂金參與抽籤,活動開始當日公佈抽籤結果,未中籤的用户自動退還訂金。將支付的任務分散開來。
如果不想改變業務邏輯,我們還可以在 token 上做文章,比如,將全部 token 分為 n 組,並在 token 上標註分組編號;同時啓用 n 個驗證服務,每個服務只負責維護對應分組的 token 集合,相當於把串行任務分為了 n 個並行任務。
區塊鏈的應用
根據白皮書 "A Peer-to-Peer Electronic Cash System" 實現的區塊鏈系統理論上是可以無限擴容的,並且由其特有的工作量證明(POW)機制,能夠超越分佈式系統不可能三角(CAP),有效解決支付過程中的雙花問題。
這裏我們嘗試設計一個運用區塊鏈系統的解決方案。首先,商家發行10萬個 token,每個 token 是一個 UTXO(未花費輸出),其中包含的金額可以是 1 聰(區塊鏈上最小的金額單位)。
另外,我們需要第三方支付也支持這一區塊鏈系統,例如現在的數字人民幣系統。
在用户獲得了 token,進行支付的時候,用户將發起一筆區塊鏈交易,這筆交易的會消耗 token,並向商家支付對應的金額。當商家從區塊鏈的“交易處理商”(俗稱礦工)那裏瞭解到這筆交易已經有極大概率成功 ———— 這個過程只理論上不到1秒鐘,實際取決於區塊鏈系統中礦工的網絡狀況 ———— 就可以認為這個token已經失效,且支付已成功,這是一個原子操作。
如果交易不成功,那麼token不失效,且支付不會成功。
結語
以上,是作者對某披薩品牌這次聯動事故的簡單分析,和嘗試提出的解決方案。我們相信在現有的網絡服務技術下,是有可能實現此類大型活動的。而在採用一些新技術,例如區塊鏈,則有機會大大降低硬件成本和操作難度。本文乃作者一家之言,如有錯誤之處,請不吝賜教。