2023-11-09 分類: 網(wǎng)站建設(shè)
原始方案(失?。涸诿看蜗掠唵吻拔覀兣袛啻黉N商品的數(shù)量夠不夠,不夠不允許下訂單,更改庫(kù)存量時(shí)加上一個(gè)條件,只更改商品庫(kù)存大于0的商品的庫(kù)存,當(dāng)時(shí)我們使用ab進(jìn)行壓力測(cè)試,當(dāng)并發(fā)超過(guò)500,訪問(wèn)量超過(guò)2000時(shí),還是會(huì)出現(xiàn)超賣現(xiàn)象。
public function buyOne() { $shop = Shop::find(1); if ($shop->number > 0) { Db::update("update shop set number = number - 1 where id = 1"); } }
第1種方案:使用mysql的事務(wù)加排他鎖來(lái)解決,首先我們選擇數(shù)據(jù)庫(kù)的存儲(chǔ)引擎為innoDb,使用的是排他鎖實(shí)現(xiàn)的,剛開始的時(shí)候我們測(cè)試了下共享鎖,發(fā)現(xiàn)還是會(huì)出現(xiàn)超賣的現(xiàn)象。有個(gè)問(wèn)題是,當(dāng)我們進(jìn)行高并發(fā)測(cè)試時(shí),對(duì)數(shù)據(jù)庫(kù)的性能影響很大,導(dǎo)致數(shù)據(jù)庫(kù)的壓力很大。
//2.利用數(shù)據(jù)庫(kù)的forupdate來(lái)加鎖(在數(shù)量少的情況下并不會(huì)出現(xiàn)問(wèn)題,但是當(dāng)并發(fā)達(dá)到(ab -n 1000 -c 200),
//就會(huì)出現(xiàn)請(qǐng)求非2XX的響應(yīng)增多,1000 失敗了 60)time per request 65.195
//在高并發(fā)的情況下,會(huì)導(dǎo)致數(shù)據(jù)庫(kù)連接數(shù)不夠,部分php獲取不到連接而報(bào)錯(cuò),或者是超過(guò)等待時(shí)間而報(bào)錯(cuò)
public function indexMysql() { Db::beginTransaction(); //通過(guò)for update 加排它鎖 $shop = Db::table('shop')->where('id', '=', 1)->lockForUpdate()->first(); if ($shop->number > 0) { if (Db::update("update shop set number = number - 1 where id = 1")) { Db::commit(); } else { Db::rollback();//回滾并重試 usleep(100000); $this->indexMysql(); } } else { Db::commit(); } }
第2種方案:使用文件鎖實(shí)現(xiàn)。當(dāng)用戶搶到一件促銷商品后先觸發(fā)文件鎖,防止其他用戶進(jìn)入,該用戶搶到促銷品后再解開文件鎖,放其他用戶進(jìn)行操作。這樣可以解決超賣的問(wèn)題,但是會(huì)導(dǎo)致文件得I/O開銷很大。
第3種方案:使用redis的setnx來(lái)實(shí)現(xiàn)鎖機(jī)制。但是并發(fā)大的情況下,鎖的爭(zhēng)奪會(huì)變多,導(dǎo)致響應(yīng)越來(lái)越慢。(與第四種方案類似)
//在數(shù)量少的情況下并不會(huì)出現(xiàn)問(wèn)題,但是當(dāng)并發(fā)達(dá)到(ab -n 1000 -c 200 就會(huì)出現(xiàn)請(qǐng)求非2XX的響應(yīng)增多,1000 失敗了 54) time per request 127.575
public function index() { //測(cè)試并發(fā)超賣現(xiàn)象 if (Redis::setnx(self::KEY, 1)) {//拿到了鎖 $this->buy(); } else { usleep(100000);//等會(huì)再去拿鎖 //Log::info("未爭(zhēng)奪到鎖,睡眠100ms"); $this->index(); } }
private function buy() { $shop = Shop::find(1); if ($shop->number > 0) { $shop->number --; $shop->save(); } Redis::del(self::KEY); }
第4種方案:redis的隊(duì)列來(lái)實(shí)現(xiàn)。將要促銷的商品數(shù)量以隊(duì)列的方式存入redis中,每當(dāng)用戶搶到一件促銷商品則從隊(duì)列中刪除一個(gè)數(shù)據(jù),確保商品不會(huì)超賣。這個(gè)操作起來(lái)很方便,而且效率極高
//4.使用redis隊(duì)列來(lái),用戶過(guò)來(lái)直接入隊(duì)列,然后再將操作更新到數(shù)據(jù)庫(kù)
//最佳體驗(yàn)(redis pconnect 9.481s, 無(wú)丟失, 無(wú)框架)
public function push() { //入隊(duì)列 Redis::lpush(self::QUEUE, 1); }
//腳本調(diào)用pop方法 * * * * * php xxx.php
public function pop()
{
while (($key = Redis::rpop(self::QUEUE))) {
$shop = Shop::find(1);
if ($shop->number > 0) {
Db::update("update shop set number = number - 1 where id = 1")
}
}
}
分享標(biāo)題:開發(fā)商城會(huì)遇到商品賣的超出預(yù)設(shè)?創(chuàng)新互聯(lián)教你如何更改
轉(zhuǎn)載來(lái)于:http://jinyejixie.com/news44/293294.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站設(shè)計(jì)公司、外貿(mào)建站、關(guān)鍵詞優(yōu)化、網(wǎng)站改版、虛擬主機(jī)、App設(shè)計(jì)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容