那些你不得不知的搶購業(yè)務(wù)要點(diǎn)

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

剛?cè)腴T的產(chǎn)品小朋友們,或許你們只知道有搶購、團(tuán)購、閃購等名詞,但是你們有具體了解過這其中的業(yè)務(wù)要點(diǎn)是什么嗎?下面就跟著我來具體了解一下吧!

案例:馬上就到雙十一了,上級給我安排了一個(gè)秒殺搶購的活動(dòng),讓我設(shè)計(jì)一個(gè)方案,那我應(yīng)該如何下手呢?

頁面上面的設(shè)計(jì),這里我就不多說了,各大網(wǎng)站上都有很多案例了!

現(xiàn)在我重點(diǎn)來講一下需要注意的幾點(diǎn):

一、超賣問題

假如你的庫存有10,現(xiàn)在3個(gè)用戶來購買,a用戶購買3個(gè),b用戶購買5個(gè),c用戶購買3個(gè),合起來就是準(zhǔn)備購買11個(gè)。

如果三個(gè)用戶是同時(shí)并發(fā)購買,會(huì)出現(xiàn)怎樣的情況呢?

每個(gè)用戶進(jìn)行減庫存的時(shí)候,數(shù)據(jù)庫都會(huì)去修改一下數(shù)據(jù),如下:update goods set amount=amount-購買數(shù)量 where goods_id=xxx。

mysql會(huì)鎖定這一行數(shù)據(jù)(使用innodb存儲(chǔ)引擎),數(shù)據(jù)庫加的是排他鎖。根據(jù)排他鎖的特點(diǎn):其他線程不能讀、不能寫此行數(shù)據(jù)。

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

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

結(jié)果庫存數(shù)量變成-1了。

思考:把庫存數(shù)量字段的類型,設(shè)計(jì)成正數(shù)類型,不允許出現(xiàn)負(fù)數(shù),會(huì)怎么樣呢?

測驗(yàn)結(jié)果:數(shù)據(jù)庫會(huì)直接報(bào)錯(cuò),通不過。

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

二、并發(fā)的問題

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

同步和異步的區(qū)別和聯(lián)系

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

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

如何處理并發(fā)和同步?

首先需要明白,鎖機(jī)制有兩個(gè)層面:

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

悲觀鎖(Pessimistic Locking):

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

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

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

樂觀鎖:

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

如:一個(gè)金融系統(tǒng),當(dāng)某個(gè)操作員讀取用戶的數(shù)據(jù),并在讀出的用戶數(shù)據(jù)的基礎(chǔ)上進(jìn)?行修改時(shí)(如更改用戶帳戶余額),如果采用悲觀鎖機(jī)制,也就意味著整個(gè)操作過程中(從操作員讀出數(shù)據(jù)、開始修改直至提交修改結(jié)果的全過程,甚至還包括操作員中途去煮咖啡的時(shí)間),數(shù)據(jù)庫記錄始終處于加鎖狀態(tài)??梢韵胍?,如果面對幾百上千個(gè)并發(fā),這樣的情況將導(dǎo)致怎樣的后果。

樂觀鎖機(jī)制在一定程度上解決了這個(gè)問題。

通俗說就是:修改數(shù)據(jù)的時(shí)候,不給數(shù)據(jù)加鎖。

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

所以很多情況下都會(huì)采用樂觀鎖來解決業(yè)務(wù)上的問題。

高并發(fā)的解決方法主要有以下幾點(diǎn):

(1)前臺(tái)優(yōu)化

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

(2)服務(wù)端優(yōu)化:

  1. 頁面靜態(tài)化;
  2. 負(fù)載均衡、集群;
  3. 分布式;
  4. 使用隊(duì)列。

(3)MySQL優(yōu)化:

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

(4)代碼優(yōu)化:

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

三、下單和減庫存要在一個(gè)事務(wù)中

如果不在一個(gè)事務(wù)內(nèi),可能出現(xiàn)兩種現(xiàn)象:

  1. 訂單入庫失敗、減庫存成功。發(fā)現(xiàn)訂單入庫失敗,減庫存就不要繼續(xù)進(jìn)行下去了。
  2. 訂單入庫成功、減庫存失敗。實(shí)際下了20個(gè)訂單,庫存卻沒有減。數(shù)據(jù)不一致了。

四、設(shè)計(jì)虛擬庫存和真實(shí)庫存兩套方案

有些人下單完后,最終并不會(huì)去付款。如果一下單就馬上減庫存,很多人下單,最終并不會(huì)去付款,可能導(dǎo)致庫存數(shù)最后為0,別的用戶無法下單了。而實(shí)際中倉庫中卻有庫存在,這樣庫存數(shù)據(jù)是不準(zhǔn)確的。

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

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

買家拍下商品后,“等待買家付款”的狀態(tài)下系統(tǒng)會(huì)給予買家3天的時(shí)間進(jìn)行付款,此時(shí)的付款動(dòng)作是將錢款支付到支付寶公司。

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

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

如唯品會(huì)的購物下單:

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

假設(shè)庫存數(shù)是50,a訂單購買了5個(gè)件商品,支付完畢,庫存數(shù)減去5,庫存數(shù)變成了45件。由于還沒有發(fā)貨,實(shí)際庫存中還有50件商品,這樣會(huì)出現(xiàn)混淆了。

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

  1. 下單-操作虛擬庫存數(shù)
  2. 商品發(fā)貨出庫-操作真實(shí)庫存數(shù)

五、減少頻繁讀數(shù)據(jù)庫的壓力

用戶每次點(diǎn)擊一個(gè)商品詳情頁面,都要讀取庫存,判斷:有沒有庫存。如果讀庫存走的是數(shù)據(jù)庫判斷,很多人來搶購的情況下,數(shù)據(jù)庫的壓力會(huì)很大。

假設(shè)是1萬個(gè)用戶同時(shí)訪問搶購頁面,數(shù)據(jù)庫接受的訪問次數(shù)是1萬個(gè)并發(fā)。

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

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

系統(tǒng)抗壓力問題:

  1. 如何限流?
  2. 如何防止惡意刷數(shù)據(jù)?

?防止限流就是寫代碼去阻止部分人進(jìn)行頻繁請求,為了識別是機(jī)器還是人工。加一些友好一點(diǎn)的驗(yàn)證碼,這樣不管是從體驗(yàn)上還是從系統(tǒng)的穩(wěn)定性方面都是比較好的。

如下圖淘寶做的驗(yàn)證:

滑塊驗(yàn)證碼方案,驗(yàn)證碼后臺(tái)針對用戶產(chǎn)生的行為軌跡數(shù)據(jù)進(jìn)行機(jī)器學(xué)習(xí)建模,結(jié)合訪問頻率、地理位置、歷史記錄等多個(gè)維度信息,快速、準(zhǔn)確的返回人機(jī)判定結(jié)果。

攻與防技術(shù)都是在對抗中不斷升級的,無解的驗(yàn)證碼還不存在,但防的一方可以不斷提升破解成本。應(yīng)用選擇滑塊驗(yàn)證,也有部分因素是因?yàn)楦偁幖ち业幕ヂ?lián)網(wǎng)很看重用戶體驗(yàn)。拖動(dòng)畢竟是趣味性交互且容易完成,而圖形驗(yàn)證碼既容易被黑客攻破,對用戶也并沒有那么友好——肉眼識別無趣(可能還很艱難),鍵盤手動(dòng)輸入更浪費(fèi)時(shí)間,體驗(yàn)不太好。

總結(jié)

本文介紹了產(chǎn)品在設(shè)計(jì)搶購閃購商品活動(dòng)中應(yīng)該注意的幾點(diǎn)事項(xiàng),在設(shè)計(jì)閃購活動(dòng)時(shí),會(huì)圍繞如何處理并發(fā)、扣除庫存、防止惡意刷數(shù)據(jù)等問題。

各公司可以先根據(jù)自己的業(yè)務(wù)情況來設(shè)計(jì)相對應(yīng)的方案,然后再用成本計(jì)算法,反算開發(fā)時(shí)間與成本,這樣既保證了項(xiàng)目進(jìn)度,性能體驗(yàn)等也不錯(cuò)。

 

本文由 @香魚 原創(chuàng)發(fā)布于人人都是產(chǎn)品經(jīng)理。未經(jīng)許可,禁止轉(zhuǎn)載

題圖來自 Pexels,基于 CC0 協(xié)議

更多精彩內(nèi)容,請關(guān)注人人都是產(chǎn)品經(jīng)理微信公眾號或下載App
評論
評論請登錄
  1. 目前還沒評論,等你發(fā)揮!