gmnon.cn-疯狂蹂躏欧美一区二区精品,欧美精品久久久久a,高清在线视频日韩欧美,日韩免费av一区二区

站長資訊網
最全最豐富的資訊網站

怎么解決PHP高并發(商品秒殺)問題?兩種解決方案分享

怎么解決PHP高并發(商品秒殺)問題?下面本篇文章就來給大家分享兩種解決方案(基于mysql或基于Redis),希望對大家有所幫助。

怎么解決PHP高并發(商品秒殺)問題?兩種解決方案分享

秒殺會產生一個瞬間的高并發,使用數據庫會增加數據庫的訪問壓力,也會降低訪問速度,所以我們應該使用緩存,來降低數據庫的訪問壓力;

可以看出這里的操作和原來的下單是不一樣的:產生的秒殺預訂單不會馬上寫入數據庫,會先寫入緩存,等用戶支付成功時,修改狀態,寫入數據庫。
?
假設num是存儲在數據庫中的字段,保存了被秒殺產品的剩余數量。

if($num > 0){   //用戶搶購成功,記錄用戶信息   $num--; }

假設在一個并發量較高的場景,數據庫中num的值為1時,可能同時會有多個進程讀取到num為1,程序判斷符合條件,搶購成功,num減一。

這樣會導致商品超發的情況,本來只有10件可以搶購的商品,可能會有超過10個人搶到,此時num在搶購完成之后為負值。

解決該問題的方案由很多,可以簡單分為基于mysql和redis的解決方案,redis的性能要由于mysql,因此可以承載更高的并發量,不過下面介紹的方案都是基于單臺mysql和redis的,更高的并發量需要分布式的解決方案,本文沒有涉及。

一、基于mysql的解決方案

商品表 goods

CREATE TABLE `goods` (  `id` int(11) NOT NULL,  `num` int(11) DEFAULT NULL,  `version` int(11) DEFAULT NULL,  PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8

搶購結果表 log

CREATE TABLE `log` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `good_id` int(11) DEFAULT NULL,  PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8

①悲觀鎖

悲觀鎖的方案采用的是排他讀,也就是同時只能有一個進程讀取到num的值。事務在提交或回滾之后,鎖會釋放,其他的進程才能讀取。

該方案最簡單易懂,在對性能要求不高時,可以直接采用該方案。要注意的是,SELECT … FOR UPDATE要盡可能的使用索引,以便鎖定盡可能少的行數;

排他鎖是在事務執行結束之后才釋放的,不是讀取完成之后就釋放,因此使用的事務應該盡可能的早些提交或回滾,以便早些釋放排它鎖。

$this->mysqli->begin_transaction(); $result = $this->mysqli->query("SELECT num FROM goods WHERE id=1 LIMIT 1 FOR UPDATE"); $row = $result->fetch_assoc(); $num = intval($row['num']); if($num > 0){   usleep(100);   $this->mysqli->query("UPDATE goods SET num=num-1");   $affected_rows = $this->mysqli->affected_rows;   if($affected_rows == 1){     $this->mysqli->query("INSERT INTO log(good_id) VALUES({$num})");     $affected_rows = $this->mysqli->affected_rows;     if($affected_rows == 1){       $this->mysqli->commit();       echo "success:".$num;     }else{       $this->mysqli->rollback();       echo "fail1:".$num;     }   }else{     $this->mysqli->rollback();     echo "fail2:".$num;   } }else{   $this->mysqli->commit();   echo "fail3:".$num; }

②樂觀鎖

樂觀鎖的方案在讀取數據是并沒有加排他鎖,而是通過一個每次更新都會自增的version字段來解決,多個進程讀取到相同num,然后都能更新成功的問題。在每個進程讀取num的同時,也讀取version的值,并且在更新num的同時也更新version,并在更新時加上對version的等值判斷。

假設有10個進程都讀取到了num的值為1,version值為9,則這10個進程執行的更新語句都是UPDATE goods SET num=num-1,version=version+1 WHERE version=9

然而當其中一個進程執行成功之后,數據庫中version的值就會變為10,剩余的9個進程都不會執行成功,這樣保證了商品不會超發,num的值不會小于0,但這也導致了一個問題,那就是發出搶購請求較早的用戶可能搶不到,反而被后來的請求搶到了。

$result = $this->mysqli->query("SELECT num,version FROM goods WHERE id=1 LIMIT 1"); $row = $result->fetch_assoc(); $num = intval($row['num']); $version = intval($row['version']); if($num > 0){   usleep(100);   $this->mysqli->begin_transaction();   $this->mysqli->query("UPDATE goods SET num=num-1,version=version+1 WHERE version={$version}");   $affected_rows = $this->mysqli->affected_rows;   if($affected_rows == 1){     $this->mysqli->query("INSERT INTO log(good_id) VALUES({$num})");     $affected_rows = $this->mysqli->affected_rows;     if($affected_rows == 1){       $this->mysqli->commit();       echo "success:".$num;     }else{       $this->mysqli->rollback();       echo "fail1:".$num;     }   }else{     $this->mysqli->rollback();     echo "fail2:".$num;   } }else{   echo "fail3:".$num; }

③where條件(原子操作)

悲觀鎖的方案保證了數據庫中num的值在同一時間只能被一個進程讀取并處理,也就是并發的讀取進程到這里要排隊依次執行。

樂觀鎖的方案雖然num的值可以被多個進程同時讀取到,但是更新操作中version的等值判斷可以保證并發的更新操作在同一時間只能有一個更新成功。

還有一種更簡單的方案,只在更新操作時加上num>0的條件限制即可。通過where條件限制的方案雖然看似和樂觀鎖方案類似,都能夠防止超發問題的出現,但在num較大時的表現還是有很大區別的。

假如此時num為10,同時有5個進程讀取到了num=10,對于樂觀鎖的方案由于version字段的等值判斷,這5個進程只會有一個更新成功,這5個進程執行完成之后num為9;

對于where條件判斷的方案,只要num>0都能夠更新成功,這5個進程執行完成之后num為5。

$result = $this->mysqli->query("SELECT num FROM goods WHERE id=1 LIMIT 1"); $row = $result->fetch_assoc(); $num = intval($row['num']); if($num > 0){   usleep(100);   $this->mysqli->begin_transaction();   $this->mysqli->query("UPDATE goods SET num=num-1 WHERE num>0");   $affected_rows = $this->mysqli->affected_rows;   if($affected_rows == 1){     $this->mysqli->query("INSERT INTO log(good_id) VALUES({$num})");     $affected_rows = $this->mysqli->affected_rows;     if($affected_rows == 1){       $this->mysqli->commit();       echo "success:".$num;     }else{       $this->mysqli->rollback();       echo "fail1:".$num;     }   }else{     $this->mysqli->rollback();     echo "fail2:".$num;   } }else{   echo "fail3:".$num; }

二、基于redis的解決方案

①基于watch的樂觀鎖方案

watch用于監視一個(或多個) key ,如果在事務執行之前這個(或這些) key 被其他命令所改動,那么事務將被打斷。

這種方案跟mysql中的樂觀鎖方案類似,具體表現也是一樣的。

$num = $this->redis->get('num'); if($num > 0) {   $this->redis->watch('num');   usleep(100);   $res = $this->redis->multi()->decr('num')->lPush('result',$num)->exec();   if($res == false){     echo "fail1";   }else{     echo "success:".$num;   } }else{   echo "fail2"; }

②基于list的隊列方案

基于隊列的方案利用了redis出隊操作的原子性,搶購開始之前首先將商品編號放入響應的隊列中,在搶購時依次從隊列中彈出操作,這樣可以保證每個商品只能被一個進程獲取并操作,不存在超發的情況。

該方案的優點是理解和實現起來都比較簡單,缺點是當商品數量較多是,需要將大量的數據存入到隊列中,并且不同的商品需要存入到不同的消息隊列中。

public function init(){   $this->redis->del('goods');   for($i=1;$i<=10;$i++){     $this->redis->lPush('goods',$i);   }   $this->redis->del('result');   echo 'init done'; } public function run(){   $goods_id = $this->redis->rPop('goods');   usleep(100);   if($goods_id == false) {     echo "fail1";   }else{     $res = $this->redis->lPush('result',$goods_id);     if($res == false){       echo "writelog:".$goods_id;     }else{       echo "success".$goods_id;     }   } }

③基于decr返回值的方案

如果我們將剩余量num設置為一個鍵值類型,每次先get之后判斷,然后再decr是不能解決超發問題的。

但是redis中的decr操作會返回執行后的結果,可以解決超發問題。我們首先get到num的值進行第一步判斷,避免每次都去更新num的值,然后再對num執行decr操作,并判斷decr的返回值,如果返回值不小于0,這說明decr之前是大于0的,用戶搶購成功。

public function run(){   $num = $this->redis->get('num');   if($num > 0) {     usleep(100);     $retNum = $this->redis->decr('num');     if($retNum >= 0){       $res = $this->redis->lPush('result',$retNum);       if($res == false){         echo "writeLog:".$retNum;       }else{         echo "success:".$retNum;       }     }else{       echo "fail1";     }   }else{     echo "fail2";   } }

④基于setnx的排它鎖方案

redis沒有像mysql中的排它鎖,但是可以通過一些方式實現排它鎖的功能,就類似php使用文件鎖實現排它鎖一樣。

setnx實現了exists和set兩個指令的功能,若給定的key已存在,則setnx不做任何動作,返回0;若key不存在,則執行類似set的操作,返回1。

我們設置一個超時時間timeout,每隔一定時間嘗試setnx操作,如果設置成功就是獲得了相應的鎖,執行num的decr操作,操作完成刪除相應的key,模擬釋放鎖的操作。

public function run(){   do {     $res = $this->redis->setnx("numKey",1);     $this->timeout -= 100;     usleep(100);   }while($res == 0 && $this->timeout>0);   if($res == 0){     echo 'fail1';   }else{     $num = $this->redis->get('num');     if($num > 0) {       $this->redis->decr('num');       usleep(100);       $res = $this->redis->lPush('result',$num);       if($res == false){         echo "fail2";       }else{         echo "success:".$num;       }     }else{       echo "fail3";     }     $this->redis->del("numKey");   } }

推薦學習:《PHP視頻教程》

贊(0)
分享到: 更多 (0)
?
網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
gmnon.cn-疯狂蹂躏欧美一区二区精品,欧美精品久久久久a,高清在线视频日韩欧美,日韩免费av一区二区
国产成人综合一区| 久久av综合网| 精品久久久久av| 日韩在线视频在线观看| 欧美成人高潮一二区在线看| 国产成人艳妇aa视频在线| 深爱五月综合网| 成年人三级视频| 亚洲国产精品女人| 丁香婷婷综合激情| 黄色动漫在线免费看| 999精品网站| 孩娇小videos精品| 精品日韩在线播放| 麻豆tv在线播放| av五月天在线| 26uuu成人| 波多野结衣与黑人| 精品视频一区二区在线| 国产色视频在线播放| 欧美成年人视频在线观看| 成人在线观看www| 玩弄中年熟妇正在播放| 免费激情视频在线观看| 精品国产鲁一鲁一区二区三区| 熟女熟妇伦久久影院毛片一区二区| 免费观看国产视频在线| 欧美日韩性生活片| 老司机久久精品| 国产人妻777人伦精品hd| 丰满少妇在线观看| 免费看日b视频| 日本888xxxx| 成人免费播放器| 色91精品久久久久久久久| 黄色激情在线视频| 在线视频观看一区二区| 六月激情综合网| 青青视频免费在线观看| mm131亚洲精品| 日本三级免费网站| 日韩在线视频在线| 欧美在线aaa| 国产欧美高清在线| 日韩国产欧美亚洲| japanese在线播放| 邪恶网站在线观看| 精品人妻一区二区三区四区在线| 中文字幕日韩久久| 中文字幕第17页| 黄色片视频在线播放| 国产精品久久中文字幕| 久操手机在线视频| 欧美 亚洲 视频| 经典三级在线视频| av电影一区二区三区| 亚洲国产午夜精品| 污免费在线观看| 亚洲一区二区三区四区精品| av污在线观看| 91日韩精品视频| 在线免费看v片| xxx中文字幕| 国产911在线观看| 中国黄色录像片| 永久免费看av| 欧日韩免费视频| 亚洲 自拍 另类小说综合图区| 国产日韩视频在线播放| 中文字幕在线乱| 日韩在线视频在线| 欧美日韩亚洲一| 国产精品99久久免费黑人人妻| 老司机午夜av| 无套内谢丰满少妇中文字幕| 看一级黄色录像| 成人免费在线小视频| 九色91popny| 成人手机在线播放| 日本中文字幕亚洲| 91淫黄看大片| 中国 免费 av| 国产免费黄色av| 日本高清久久久| 久久手机在线视频| 国产又大又黄又粗又爽| 久久久久久久久久久久久国产| 人妻夜夜添夜夜无码av| 国产97色在线 | 日韩| 日韩a一级欧美一级| 欧洲精品在线播放| 浓精h攵女乱爱av| 亚洲爆乳无码精品aaa片蜜桃| 久草青青在线观看| 一级片免费在线观看视频| 97视频久久久| 四虎成人在线播放| 91看片就是不一样| 97久久国产亚洲精品超碰热| 青青青在线播放| 97免费视频观看| www.污网站| 国产精品69页| www.av蜜桃| 亚欧精品在线视频| 69久久久久久| 国产性xxxx18免费观看视频| 精品无码av无码免费专区| 午夜久久久精品| 日本三区在线观看| 免费看黄在线看| av动漫在线免费观看| 欧美一级免费在线| 一级黄色特级片| 九色91popny| 成人在线观看黄| 国产xxxxx在线观看| 免费看国产曰批40分钟| 日韩精品在线观看av| 亚洲第一页在线视频| 三级a在线观看| 中文字幕第36页| 91日韩视频在线观看| 116极品美女午夜一级| 草草视频在线免费观看| 丁香婷婷综合激情| www.日本在线视频| av日韩一区二区三区| 成人免费看片'免费看| 热久久最新网址| 激情六月天婷婷| 国产乱淫av片杨贵妃| 91免费黄视频| 男人靠女人免费视频网站| www一区二区www免费| 欧美亚洲精品一区二区| 日韩视频第二页| 91n.com在线观看| 国产欧美一区二| 永久免费网站视频在线观看| 9色视频在线观看| 一二三四视频社区在线| 日韩a在线播放| 向日葵污视频在线观看| 香蕉视频xxx| 国产精品日韩三级| 无码专区aaaaaa免费视频| 日韩久久一级片| 三日本三级少妇三级99| 日韩xxxx视频| 亚洲不卡视频在线| 国内精品国产三级国产99| 日本日本19xxxⅹhd乱影响| 黄色一级免费大片| 400部精品国偷自产在线观看| 精品视频在线观看一区| www.99在线| av久久久久久| 91n.com在线观看| 日本人妻伦在线中文字幕| 欧美 激情 在线| 老司机午夜网站| 青青草精品视频在线观看| 日本黄网站色大片免费观看| 黄色片视频在线播放| ijzzijzzij亚洲大全| 国产成人在线免费看| 最近中文字幕免费mv| 欧美精品一区二区三区免费播放| 超碰在线免费观看97| 人妻丰满熟妇av无码区app| 国产91沈先生在线播放| 乌克兰美女av| 日韩精品视频一区二区在线观看| 57pao国产成永久免费视频| 给我免费播放片在线观看| 999热精品视频| 日韩大片一区二区| 欧美xxxxx在线视频| www.av蜜桃| 国产一级大片免费看| 青春草在线视频免费观看| 激情 小说 亚洲 图片: 伦| 国内外成人激情视频| 日本午夜激情视频| 国产成人一区二区三区别| 国产高清免费在线| 中文字幕一区二区三区四| 亚洲精品手机在线观看| 国产精品亚洲二区在线观看 | 久久视频这里有精品| 国产四区在线观看| 亚洲 欧洲 日韩| 国产女同无遮挡互慰高潮91| 国产又大又黄又粗的视频| 中文字幕无码不卡免费视频| 成年人视频网站免费观看| 青青草精品视频在线| 爱福利视频一区二区| 日本欧美视频在线观看|