那些你不得不知的搶購業務要點

1 評論 4049 瀏覽 23 收藏 15 分鐘

剛入門的產品小朋友們,或許你們只知道有搶購、團購、閃購等名詞,但是你們有具體了解過這其中的業務要點是什么嗎?下面就跟著我來具體了解一下吧!

案例:馬上就到雙十一了,上級給我安排了一個秒殺搶購的活動,讓我設計一個方案,那我應該如何下手呢?

頁面上面的設計,這里我就不多說了,各大網站上都有很多案例了!

現在我重點來講一下需要注意的幾點:

一、超賣問題

假如你的庫存有10,現在3個用戶來購買,a用戶購買3個,b用戶購買5個,c用戶購買3個,合起來就是準備購買11個。

如果三個用戶是同時并發購買,會出現怎樣的情況呢?

每個用戶進行減庫存的時候,數據庫都會去修改一下數據,如下:update goods set amount=amount-購買數量 where goods_id=xxx。

mysql會鎖定這一行數據(使用innodb存儲引擎),數據庫加的是排他鎖。根據排他鎖的特點:其他線程不能讀、不能寫此行數據。

排他鎖情況下,那么其他用戶就是等待狀態了。

  1. a用戶執行update的時候,鎖定庫存數據。update執行完畢后,減去了3個后,mysql自動釋放鎖。
  2. b用戶執行,減去了5個。此時,已經賣掉8個庫存了,庫存數為2了。
  3. 但是c用戶接著執行,Update goods set amount=amount-1 where goods_id=xxx。

結果庫存數量變成-1了。

思考:把庫存數量字段的類型,設計成正數類型,不允許出現負數,會怎么樣呢?

測驗結果:數據庫會直接報錯,通不過。

解決辦法:只有庫存數量,大于或等于購買數量的時候,才能去減庫存。其他情況,提示信息,庫存不足。

二、并發的問題

為了更好的理解并發和同步,我們需要先明白兩個重要的概念:同步和異步。

同步和異步的區別和聯系

  • 所謂同步,可以理解為在執行完一個函數或方法之后,一直等待系統返回值或消息,這時程序是出于阻塞的,只有接收到返回的值或消息后才往下執行其它的命令。
  • 異步,執行完函數或方法后,不必阻塞性地等待返回值或消息,只需要向系統委托一個異步過程,那么當系統接收到返回值或消息時,系統會自動觸發委托的異步過程,從而完成一個完整的流程。

同步在一定程度上可以看做是單線程,這個線程請求一個方法后就待這個方法給他回復,否則他不往下執行。異步在一定程度上可以看做是多線程的,請求一個方法后,就不管了,繼續執行其他的方法。

如何處理并發和同步?

首先需要明白,鎖機制有兩個層面:

  • 一種是代碼層次上的,如:java中的同步鎖,典型的就是同步關鍵字synchronized,這里我不在做過多的講解;
  • 另外一種是數據庫層次上的,比較典型的就是悲觀鎖和樂觀鎖。這里我們重點講解的就是悲觀鎖(傳統的物理鎖)和樂觀鎖。

悲觀鎖(Pessimistic Locking):

悲觀鎖,正如其名,它指的是對數據被外界(包括本系統當前的其他事務,以及來自?外部系統的事務處理)修改持保守態度,因此,在整個數據處理過程中,將數據處于鎖定狀態。

悲觀鎖的實現,往往依靠數據庫提供的鎖機制(也只有數據庫層提供的鎖機制才能?真正保證數據訪問的排他性,否則,即使在本系統中實現了加鎖機制,也無法保證外部系?統不會修改數據)。

第一種問題中描述的超賣現象,其實是并發搶購時出現的情況。用到的是數據庫內帶的加排他鎖方式,阻止了其他線程讀取、訪問數據,這樣等待的時間就比較長。而業界一般的解決是使用樂觀鎖的辦法來解決:使用數據庫的樂觀鎖是通用解決辦法。

樂觀鎖:

相對悲觀鎖而言,樂觀鎖機制采取了更加寬松的加鎖機制。悲觀鎖大多數情況下依靠數據庫的鎖機制實現,以保證操作最大程度的獨占性。但隨之而來的就是數據庫性能的大量開銷,特別是對長事務而言,這樣的開銷往往無法承受。

如:一個金融系統,當某個操作員讀取用戶的數據,并在讀出的用戶數據的基礎上進?行修改時(如更改用戶帳戶余額),如果采用悲觀鎖機制,也就意味著整個操作過程中(從操作員讀出數據、開始修改直至提交修改結果的全過程,甚至還包括操作員中途去煮咖啡的時間),數據庫記錄始終處于加鎖狀態??梢韵胍姡绻鎸装偕锨€并發,這樣的情況將導致怎樣的后果。

樂觀鎖機制在一定程度上解決了這個問題。

通俗說就是:修改數據的時候,不給數據加鎖。

樂觀鎖意思是不鎖定表的情況下,利用業務的控制來解決并發問題,這樣即保證數據的并發可讀性又保證保存數據的排他性,保證性能的同時解決了并發帶來的臟數據問題。

所以很多情況下都會采用樂觀鎖來解決業務上的問題。

高并發的解決方法主要有以下幾點:

(1)前臺優化

  1. 減少http請求——css文件合并? ,js文件合并;
  2. 壓縮js,css文件;
  3. 使用雪碧圖;
  4. 懶加載(只加載看到的第一屏內容,下拉之后看到其他的內容);
  5. 預加載(只加載默認圖);
  6. cdn 加速。

(2)服務端優化:

  1. 頁面靜態化;
  2. 負載均衡、集群;
  3. 分布式;
  4. 使用隊列。

(3)MySQL優化:

  1. 查詢優化,能單表的單表
  2. 查詢一條數據使用limit
  3. 生成查詢緩存
  4. 使用索引
  5. 多表查詢使用id進行關聯
  6. 數據庫分表
  7. 數據庫分區
  8. 數據庫集群
  9. 要查詢的字段避免使用*號,指定需要的字段
  10. 避免使用%前綴的模糊查詢
  11. 避免使用負向查詢
  12. 避免使用or查詢
  13. 避免使用子查詢
  14. 避免使用MySQL自帶函數
  15. 不要是rand
  16. 有順序的讀取
  17. 設置合適的數據類型
  18. 避免使用text類型
  19. 避免使用null

(4)代碼優化:

  1. 用單引號代替雙引號,雙引號會查詢變量;
  2. 避免使用require_once require_once會判斷文件是否加載過;
  3. 使用靜態方法代替普通方法,靜態方法速度比普通方法快4倍;
  4. 變量使用完之后需要銷毀;
  5. 盡量不要使用@;
  6. include用絕對路徑,不要使用相對路徑,相對路徑會有查詢的過程;
  7. 避免使用__SET __GET __AUTOLOAD;
  8. 循環的時候先確定循環次數,不要每次循環都要計算;
  9. 避免循環查庫;
  10. 避免多層foreach嵌套;
  11. 避免使用遞歸 ,遞歸比較浪費資源。

三、下單和減庫存要在一個事務中

如果不在一個事務內,可能出現兩種現象:

  1. 訂單入庫失敗、減庫存成功。發現訂單入庫失敗,減庫存就不要繼續進行下去了。
  2. 訂單入庫成功、減庫存失敗。實際下了20個訂單,庫存卻沒有減。數據不一致了。

四、設計虛擬庫存和真實庫存兩套方案

有些人下單完后,最終并不會去付款。如果一下單就馬上減庫存,很多人下單,最終并不會去付款,可能導致庫存數最后為0,別的用戶無法下單了。而實際中倉庫中卻有庫存在,這樣庫存數據是不準確的。

什么時候減庫存?是下單完成減庫存、還是付款完后減庫存呢?

付款后,才減庫存,可能出現的現象:用戶下完單,接著去付款,結果庫存不夠了,這樣用戶體驗很不好。但是淘寶的設計是3天(大廠就是比較任性哦)

買家拍下商品后,“等待買家付款”的狀態下系統會給予買家3天的時間進行付款,此時的付款動作是將錢款支付到支付寶公司。

此付款時間無法延長,若逾期未付款,交易將自動關閉,如您仍想購買,建議重新購買并及時付款。但是如果下完單就減庫存,并能夠保證用戶下單只要付款,就一定能買到這個商品。這樣的用戶體驗會較好。

具體技術實現辦法:下單后,馬上減去庫存。另外設置一個定時腳本,掃描超過30分未支付的訂單,把訂單中的商品數量返回到庫存中去,訂單關閉。

如唯品會的購物下單:

為什么使用虛擬庫存和真實庫存兩套方案?

假設庫存數是50,a訂單購買了5個件商品,支付完畢,庫存數減去5,庫存數變成了45件。由于還沒有發貨,實際庫存中還有50件商品,這樣會出現混淆了。

使用兩套庫存記錄方案是有必要的!

  1. 下單-操作虛擬庫存數
  2. 商品發貨出庫-操作真實庫存數

五、減少頻繁讀數據庫的壓力

用戶每次點擊一個商品詳情頁面,都要讀取庫存,判斷:有沒有庫存。如果讀庫存走的是數據庫判斷,很多人來搶購的情況下,數據庫的壓力會很大。

假設是1萬個用戶同時訪問搶購頁面,數據庫接受的訪問次數是1萬個并發。

用戶還要進行刷新頁面操作,由于每次刷新都會走數據庫判斷庫存。數量會更大,數據庫的壓力就更大了。所以最好是,把庫存總數,緩存在redis中去。

內存中緩存的庫存數量,只用來做讀判斷,這樣壓力扛住了。而更改數據庫的庫存總數了,程序馬上要把庫存總數,同步到緩存中去。

系統抗壓力問題:

  1. 如何限流?
  2. 如何防止惡意刷數據?

?防止限流就是寫代碼去阻止部分人進行頻繁請求,為了識別是機器還是人工。加一些友好一點的驗證碼,這樣不管是從體驗上還是從系統的穩定性方面都是比較好的。

如下圖淘寶做的驗證:

滑塊驗證碼方案,驗證碼后臺針對用戶產生的行為軌跡數據進行機器學習建模,結合訪問頻率、地理位置、歷史記錄等多個維度信息,快速、準確的返回人機判定結果。

攻與防技術都是在對抗中不斷升級的,無解的驗證碼還不存在,但防的一方可以不斷提升破解成本。應用選擇滑塊驗證,也有部分因素是因為競爭激烈的互聯網很看重用戶體驗。拖動畢竟是趣味性交互且容易完成,而圖形驗證碼既容易被黑客攻破,對用戶也并沒有那么友好——肉眼識別無趣(可能還很艱難),鍵盤手動輸入更浪費時間,體驗不太好。

總結

本文介紹了產品在設計搶購閃購商品活動中應該注意的幾點事項,在設計閃購活動時,會圍繞如何處理并發、扣除庫存、防止惡意刷數據等問題。

各公司可以先根據自己的業務情況來設計相對應的方案,然后再用成本計算法,反算開發時間與成本,這樣既保證了項目進度,性能體驗等也不錯。

 

本文由 @香魚 原創發布于人人都是產品經理。未經許可,禁止轉載

題圖來自 Pexels,基于 CC0 協議

更多精彩內容,請關注人人都是產品經理微信公眾號或下載App
評論
評論請登錄
  1. 目前還沒評論,等你發揮!