用php写京东抢购,关于抢京东券高并发的问题?
之前在一個(gè)微信公眾號(hào)上做了一個(gè)搶京東券的功能, 50 張京東券,面額 50 、 100 不等,存在一張 card 表中,四個(gè)字段, id , number , money , is_taken 。
因?yàn)橹皼](méi)有這種高并發(fā)處理的經(jīng)驗(yàn),所以使用了一種最傳統(tǒng)的方式來(lái)實(shí)現(xiàn):
方案一:來(lái)一個(gè)人我就從數(shù)據(jù)庫(kù)中取一張京東券出來(lái)給他,并將該京東券標(biāo)記為已使用(即更新 is_taken 字段),并將該用戶插入到 winner 表中
這個(gè)方案最終導(dǎo)致的悲劇是,有一張京東券被兩個(gè)人領(lǐng)取到了。
我所理解會(huì)出現(xiàn)這個(gè)問(wèn)題的原因是獲取未被占用的京東券數(shù)據(jù)( select )和更新該條京東券數(shù)據(jù)( update )是兩個(gè)獨(dú)立的操作,在這兩個(gè)操作之間存在時(shí)間間隔,例如 A 用戶剛得到了一張 100 元的京東券,還未來(lái)得及更新, B 用戶涌入查詢到這張京東券未被使用,所以 B 用戶也獲得了這張京東券。
問(wèn)題一:我這個(gè)理解是正確的嗎?還是有更深入的原因?
出了這個(gè)問(wèn)題后,我在網(wǎng)上查找關(guān)于高并發(fā)相關(guān)的資料,幾乎都提到了隊(duì)列和鎖。就我個(gè)人了解隊(duì)列可以使用 redis 或者 memcacheq(這個(gè)沒(méi)用過(guò),不熟悉),所以自己想了第二種方案。
方案二:事先將京東券 id 數(shù)據(jù)壓入到 redis 的 list 中,每過(guò)來(lái)一個(gè)有效的用戶,就 pop 一個(gè) id 給他(當(dāng) pop 出來(lái)的數(shù)據(jù)為空時(shí)說(shuō)明京東券已經(jīng)被搶光),并將用戶 id 與京東券 id 的對(duì)應(yīng)關(guān)系存儲(chǔ)到 redis 的 set 當(dāng)中去,然后根據(jù)這個(gè) id 來(lái)查找京東券數(shù)據(jù),顯示給用戶京東券的面額,并將 set 中的數(shù)據(jù)存儲(chǔ)到數(shù)據(jù)庫(kù)當(dāng)中去。
個(gè)人覺(jué)得這種方案會(huì)比第一種方案要好的多。但是沒(méi)有真正意義上去實(shí)踐過(guò),只是個(gè)人思考的一個(gè)結(jié)果。
問(wèn)題二:第二種方案是否可行?是否還有更優(yōu)方案?或者說(shuō)方案二是否有可以優(yōu)化的地方?
問(wèn)題三:在高并發(fā)時(shí)很多文章中說(shuō)到的鎖是一個(gè)怎樣的概念呢?我的理解是這個(gè)鎖就像是數(shù)據(jù)庫(kù)的一個(gè)大門(mén),一次只放一個(gè)人進(jìn)去,是這樣嗎?具體該如何設(shè)計(jì)和使用?
問(wèn)題四:在應(yīng)對(duì)大流量高并發(fā)的情況時(shí),在服務(wù)器層面要做哪些工作?
問(wèn)題五:我所舉得這個(gè)例子與平常類(lèi)似網(wǎng)上商城中的秒殺功能有哪些相同和相異之處呢?是否可以按照方案二的設(shè)計(jì)思路進(jìn)行設(shè)計(jì)呢?
回復(fù)內(nèi)容:
之前在一個(gè)微信公眾號(hào)上做了一個(gè)搶京東券的功能, 50 張京東券,面額 50 、 100 不等,存在一張 card 表中,四個(gè)字段, id , number , money , is_taken 。
因?yàn)橹皼](méi)有這種高并發(fā)處理的經(jīng)驗(yàn),所以使用了一種最傳統(tǒng)的方式來(lái)實(shí)現(xiàn):
方案一:來(lái)一個(gè)人我就從數(shù)據(jù)庫(kù)中取一張京東券出來(lái)給他,并將該京東券標(biāo)記為已使用(即更新 is_taken 字段),并將該用戶插入到 winner 表中
這個(gè)方案最終導(dǎo)致的悲劇是,有一張京東券被兩個(gè)人領(lǐng)取到了。
我所理解會(huì)出現(xiàn)這個(gè)問(wèn)題的原因是獲取未被占用的京東券數(shù)據(jù)( select )和更新該條京東券數(shù)據(jù)( update )是兩個(gè)獨(dú)立的操作,在這兩個(gè)操作之間存在時(shí)間間隔,例如 A 用戶剛得到了一張 100 元的京東券,還未來(lái)得及更新, B 用戶涌入查詢到這張京東券未被使用,所以 B 用戶也獲得了這張京東券。
問(wèn)題一:我這個(gè)理解是正確的嗎?還是有更深入的原因?
出了這個(gè)問(wèn)題后,我在網(wǎng)上查找關(guān)于高并發(fā)相關(guān)的資料,幾乎都提到了隊(duì)列和鎖。就我個(gè)人了解隊(duì)列可以使用 redis 或者 memcacheq(這個(gè)沒(méi)用過(guò),不熟悉),所以自己想了第二種方案。
方案二:事先將京東券 id 數(shù)據(jù)壓入到 redis 的 list 中,每過(guò)來(lái)一個(gè)有效的用戶,就 pop 一個(gè) id 給他(當(dāng) pop 出來(lái)的數(shù)據(jù)為空時(shí)說(shuō)明京東券已經(jīng)被搶光),并將用戶 id 與京東券 id 的對(duì)應(yīng)關(guān)系存儲(chǔ)到 redis 的 set 當(dāng)中去,然后根據(jù)這個(gè) id 來(lái)查找京東券數(shù)據(jù),顯示給用戶京東券的面額,并將 set 中的數(shù)據(jù)存儲(chǔ)到數(shù)據(jù)庫(kù)當(dāng)中去。
個(gè)人覺(jué)得這種方案會(huì)比第一種方案要好的多。但是沒(méi)有真正意義上去實(shí)踐過(guò),只是個(gè)人思考的一個(gè)結(jié)果。
問(wèn)題二:第二種方案是否可行?是否還有更優(yōu)方案?或者說(shuō)方案二是否有可以優(yōu)化的地方?
問(wèn)題三:在高并發(fā)時(shí)很多文章中說(shuō)到的鎖是一個(gè)怎樣的概念呢?我的理解是這個(gè)鎖就像是數(shù)據(jù)庫(kù)的一個(gè)大門(mén),一次只放一個(gè)人進(jìn)去,是這樣嗎?具體該如何設(shè)計(jì)和使用?
問(wèn)題四:在應(yīng)對(duì)大流量高并發(fā)的情況時(shí),在服務(wù)器層面要做哪些工作?
問(wèn)題五:我所舉得這個(gè)例子與平常類(lèi)似網(wǎng)上商城中的秒殺功能有哪些相同和相異之處呢?是否可以按照方案二的設(shè)計(jì)思路進(jìn)行設(shè)計(jì)呢?
我估計(jì)你的方案一是這樣子的
select * from card where is_token=0 limit 1;
//有結(jié)果時(shí),繼續(xù)執(zhí)行以下語(yǔ)句
update card set is_token=1 where id=xx;
insert into winner ...
改進(jìn)
select * from card where is_token=0 limit 1;
//有結(jié)果時(shí),繼續(xù)執(zhí)行以下語(yǔ)句
update card set is_token=1 where id=xx and is_token=0;
//獲取影響行數(shù),為0則失敗,否則執(zhí)行 insert into winner ...
方案二
可行。
因?yàn)槟愕臉I(yè)務(wù)邏輯比較簡(jiǎn)單,也可以使用redis的計(jì)數(shù)器
即當(dāng)計(jì)數(shù)器 <=50 時(shí)按順序一人領(lǐng)一張,通過(guò)計(jì)數(shù)器來(lái)過(guò)濾
問(wèn)題三 鎖
悲觀鎖(Pessimistic Lock)
顧名思義,就是很悲觀,每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人會(huì)修改,所以每次在拿數(shù)據(jù)的時(shí)候都會(huì)上鎖,這樣別人想拿這個(gè)數(shù)據(jù)就會(huì)block直到它拿到鎖。傳統(tǒng)的關(guān)系型數(shù)據(jù)庫(kù)里邊就用到了很多這種鎖機(jī)制,比如行鎖,表鎖等,讀鎖,寫(xiě)鎖等,都是在做操作之前先上鎖。
begin;
select * from card where is_token=0 limit 1 for update;
樂(lè)觀鎖
顧名思義,就是很樂(lè)觀,每次去拿數(shù)據(jù)的時(shí)候都認(rèn)為別人不會(huì)修改,所以不會(huì)上鎖,但是在更新的時(shí)候會(huì)判斷一下在此期間別人有沒(méi)有去更新這個(gè)數(shù)據(jù),可以使用版本號(hào)等機(jī)制。參考改進(jìn)后的方案一。
樂(lè)觀鎖用的比較多,使用redis的watch
本文原創(chuàng)發(fā)布php中文網(wǎng),轉(zhuǎn)載請(qǐng)注明出處,感謝您的尊重!
總結(jié)
以上是生活随笔為你收集整理的用php写京东抢购,关于抢京东券高并发的问题?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: django如何调用php接口,使用dj
- 下一篇: php获取form传递的变量,PHP-将