亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 數據庫 > Redis > 正文

php結合redis實現高并發下的搶購、秒殺功能的實例

2020-10-28 21:38:18
字體:
來源:轉載
供稿:網友

搶購、秒殺是如今很常見的一個應用場景,主要需要解決的問題有兩個:

1 高并發對數據庫產生的壓力

2 競爭狀態下如何解決庫存的正確減少("超賣"問題)

對于第一個問題,已經很容易想到用緩存來處理搶購,避免直接操作數據庫,例如使用Redis。

重點在于第二個問題

常規寫法:

查詢出對應商品的庫存,看是否大于0,然后執行生成訂單等操作,但是在判斷庫存是否大于0處,如果在高并發下就會有問題,導致庫存量出現負數

<?php$conn=mysql_connect("localhost","big","123456"); if(!$conn){ 	echo "connect failed"; 	exit; } mysql_select_db("big",$conn); mysql_query("set names utf8");$price=10;$user_id=1;$goods_id=1;$sku_id=11;$number=1;//生成唯一訂單function build_order_no(){  return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);}//記錄日志function insertLog($event,$type=0){	global $conn;	$sql="insert into ih_log(event,type) 	values('$event','$type')"; 	mysql_query($sql,$conn); }//模擬下單操作//庫存是否大于0$sql="select number from ih_store where goods_id='$goods_id' and sku_id='$sku_id'";//解鎖 此時ih_store數據中goods_id='$goods_id' and sku_id='$sku_id' 的數據被鎖住(注3),其它事務必須等待此次事務 提交后才能執行$rs=mysql_query($sql,$conn);$row=mysql_fetch_assoc($rs);if($row['number']>0){//高并發下會導致超賣	$order_sn=build_order_no();	//生成訂單 	$sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price) 	values('$order_sn','$user_id','$goods_id','$sku_id','$price')"; 	$order_rs=mysql_query($sql,$conn); 		//庫存減少	$sql="update ih_store set number=number-{$number} where sku_id='$sku_id'";	$store_rs=mysql_query($sql,$conn); 	if(mysql_affected_rows()){ 		insertLog('庫存減少成功');	}else{ 		insertLog('庫存減少失敗');	} }else{	insertLog('庫存不夠');}?>

優化方案1:將庫存字段number字段設為unsigned,當庫存為0時,因為字段不能為負數,將會返回false

 

//庫存減少$sql="update ih_store set number=number-{$number} where sku_id='$sku_id' and number>0";$store_rs=mysql_query($sql,$conn); if(mysql_affected_rows()){ 	insertLog('庫存減少成功');}

優化方案2:使用MySQL的事務,鎖住操作的行

<?php$conn=mysql_connect("localhost","big","123456"); if(!$conn){ 	echo "connect failed"; 	exit; } mysql_select_db("big",$conn); mysql_query("set names utf8");$price=10;$user_id=1;$goods_id=1;$sku_id=11;$number=1;//生成唯一訂單號function build_order_no(){  return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);}//記錄日志function insertLog($event,$type=0){	global $conn;	$sql="insert into ih_log(event,type) 	values('$event','$type')"; 	mysql_query($sql,$conn); }//模擬下單操作//庫存是否大于0mysql_query("BEGIN");	//開始事務$sql="select number from ih_store where goods_id='$goods_id' and sku_id='$sku_id' FOR UPDATE";//此時這條記錄被鎖住,其它事務必須等待此次事務提交后才能執行$rs=mysql_query($sql,$conn);$row=mysql_fetch_assoc($rs);if($row['number']>0){	//生成訂單 	$order_sn=build_order_no();		$sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price) 	values('$order_sn','$user_id','$goods_id','$sku_id','$price')"; 	$order_rs=mysql_query($sql,$conn); 		//庫存減少	$sql="update ih_store set number=number-{$number} where sku_id='$sku_id'";	$store_rs=mysql_query($sql,$conn); 	if(mysql_affected_rows()){ 		insertLog('庫存減少成功');		mysql_query("COMMIT");//事務提交即解鎖	}else{ 		insertLog('庫存減少失敗');	}}else{	insertLog('庫存不夠');	mysql_query("ROLLBACK");}?>

優化方案3:使用非阻塞的文件排他鎖

<?php$conn=mysql_connect("localhost","root","123456"); if(!$conn){ 	echo "connect failed"; 	exit; } mysql_select_db("big-bak",$conn); mysql_query("set names utf8");$price=10;$user_id=1;$goods_id=1;$sku_id=11;$number=1;//生成唯一訂單號function build_order_no(){  return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);}//記錄日志function insertLog($event,$type=0){	global $conn;	$sql="insert into ih_log(event,type) 	values('$event','$type')"; 	mysql_query($sql,$conn); }$fp = fopen("lock.txt", "w+");if(!flock($fp,LOCK_EX | LOCK_NB)){	echo "系統繁忙,請稍后再試";	return;}//下單$sql="select number from ih_store where goods_id='$goods_id' and sku_id='$sku_id'";$rs=mysql_query($sql,$conn);$row=mysql_fetch_assoc($rs);if($row['number']>0){//庫存是否大于0	//模擬下單操作 	$order_sn=build_order_no();		$sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price) 	values('$order_sn','$user_id','$goods_id','$sku_id','$price')"; 	$order_rs=mysql_query($sql,$conn); 		//庫存減少	$sql="update ih_store set number=number-{$number} where sku_id='$sku_id'";	$store_rs=mysql_query($sql,$conn); 	if(mysql_affected_rows()){ 		insertLog('庫存減少成功');		flock($fp,LOCK_UN);//釋放鎖	}else{ 		insertLog('庫存減少失敗');	} }else{	insertLog('庫存不夠');}fclose($fp);

優化方案4:使用redis隊列,因為pop操作是原子的,即使有很多用戶同時到達,也是依次執行,推薦使用(mysql事務在高并發下性能下降很厲害,文件鎖的方式也是)

先將商品庫存如隊列

 

<?php$store=1000;$redis=new Redis();$result=$redis->connect('127.0.0.1',6379);$res=$redis->llen('goods_store');echo $res;$count=$store-$res;for($i=0;$i<$count;$i++){	$redis->lpush('goods_store',1);}echo $redis->llen('goods_store');?>

搶購、描述邏輯

<?php$conn=mysql_connect("localhost","big","123456"); if(!$conn){ 	echo "connect failed"; 	exit; } mysql_select_db("big",$conn); mysql_query("set names utf8");$price=10;$user_id=1;$goods_id=1;$sku_id=11;$number=1;//生成唯一訂單號function build_order_no(){  return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);}//記錄日志function insertLog($event,$type=0){	global $conn;	$sql="insert into ih_log(event,type) 	values('$event','$type')"; 	mysql_query($sql,$conn); }//模擬下單操作//下單前判斷redis隊列庫存量$redis=new Redis();$result=$redis->connect('127.0.0.1',6379);$count=$redis->lpop('goods_store');if(!$count){	insertLog('error:no store redis');	return;}//生成訂單 $order_sn=build_order_no();$sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price) values('$order_sn','$user_id','$goods_id','$sku_id','$price')"; $order_rs=mysql_query($sql,$conn); //庫存減少$sql="update ih_store set number=number-{$number} where sku_id='$sku_id'";$store_rs=mysql_query($sql,$conn); if(mysql_affected_rows()){ 	insertLog('庫存減少成功');}else{ 	insertLog('庫存減少失敗');} 

模擬5000高并發測試

webbench -c 5000 -t 60 http://192.168.1.198/big/index.php
ab -r -n 6000 -c 5000  http://192.168.1.198/big/index.php

上述只是簡單模擬高并發下的搶購,真實場景要比這復雜很多,很多注意的地方

如搶購頁面做成靜態的,通過ajax調用接口

再如上面的會導致一個用戶搶多個,思路:

需要一個排隊隊列和搶購結果隊列及庫存隊列。高并發情況,先將用戶進入排隊隊列,用一個線程循環處理從排隊隊列取出一個用戶,判斷用戶是否已在搶購結果隊列,如果在,則已搶購,否則未搶購,庫存減1,寫數據庫,將用戶入結果隊列。

測試數據表

---- 數據庫: `big`---- ------------------------------------------------------------ 表的結構 `ih_goods`--CREATE TABLE IF NOT EXISTS `ih_goods` (  `goods_id` int(10) unsigned NOT NULL AUTO_INCREMENT,  `cat_id` int(11) NOT NULL,  `goods_name` varchar(255) NOT NULL,  PRIMARY KEY (`goods_id`)) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;---- 轉存表中的數據 `ih_goods`--INSERT INTO `ih_goods` (`goods_id`, `cat_id`, `goods_name`) VALUES(1, 0, '小米手機');-- ------------------------------------------------------------ 表的結構 `ih_log`--CREATE TABLE IF NOT EXISTS `ih_log` ( `id` int(11) NOT NULL AUTO_INCREMENT, `event` varchar(255) NOT NULL, `type` tinyint(4) NOT NULL DEFAULT '0', `addtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;---- 轉存表中的數據 `ih_log`---- ------------------------------------------------------------ 表的結構 `ih_order`--CREATE TABLE IF NOT EXISTS `ih_order` ( `id` int(11) NOT NULL AUTO_INCREMENT, `order_sn` char(32) NOT NULL, `user_id` int(11) NOT NULL, `status` int(11) NOT NULL DEFAULT '0', `goods_id` int(11) NOT NULL DEFAULT '0', `sku_id` int(11) NOT NULL DEFAULT '0', `price` float NOT NULL, `addtime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='訂單表' AUTO_INCREMENT=1 ;---- 轉存表中的數據 `ih_order`---- ------------------------------------------------------------ 表的結構 `ih_store`--CREATE TABLE IF NOT EXISTS `ih_store` ( `id` int(11) NOT NULL AUTO_INCREMENT, `goods_id` int(11) NOT NULL, `sku_id` int(10) unsigned NOT NULL DEFAULT '0', `number` int(10) NOT NULL DEFAULT '0', `freez` int(11) NOT NULL DEFAULT '0' COMMENT '虛擬庫存', PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='庫存' AUTO_INCREMENT=2 ;---- 轉存表中的數據 `ih_store`--INSERT INTO `ih_store` (`id`, `goods_id`, `sku_id`, `number`, `freez`) VALUES(1, 1, 11, 500, 0);

以上就是小編為大家帶來的php結合redis實現高并發下的搶購、秒殺功能的實例全部內容了,希望大家多多支持武林網~

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲乱码国产乱码精品精天堂| 久久黄色av网站| 色午夜这里只有精品| 欧美日韩在线免费观看| 久久久国产视频91| 国产亚洲精品综合一区91| 亚洲成人精品视频在线观看| 亚洲国产精品yw在线观看| 欧美日韩国产激情| 国产婷婷色综合av蜜臀av| 久久夜精品va视频免费观看| 5566日本婷婷色中文字幕97| 欧美日韩国产丝袜另类| 色婷婷av一区二区三区在线观看| 人人爽久久涩噜噜噜网站| 亚洲色图在线观看| 亚洲第一二三四五区| 久久久久久久色| 黑人巨大精品欧美一区二区| 亚洲人午夜色婷婷| 亚洲在线视频福利| 亚洲天堂av电影| 中文字幕av一区| 欧美精品18videos性欧| 日韩欧美aⅴ综合网站发布| 国产日韩一区在线| 国产视频久久久| 亚洲xxx大片| 狠狠躁夜夜躁人人爽超碰91| 久久精品人人做人人爽| 国产女精品视频网站免费| 亚洲欧美中文日韩v在线观看| 亚洲性日韩精品一区二区| 国产精品色午夜在线观看| 国产精品人人做人人爽| 亚洲一区二区三区久久| 国产成人精品日本亚洲专区61| 日韩最新中文字幕电影免费看| 国产精品爽爽爽爽爽爽在线观看| 91精品国产综合久久久久久久久| 亚洲欧美国产精品va在线观看| 成人激情在线观看| 国产成人激情视频| 国产欧美日韩高清| 欧美激情图片区| 91久久夜色精品国产网站| 亚洲自拍另类欧美丝袜| 精品国产依人香蕉在线精品| 日韩电影中文 亚洲精品乱码| 国产精品日韩在线一区| 亚洲第一福利在线观看| 日韩av快播网址| 欧美成人自拍视频| 成人免费高清完整版在线观看| 国产成人精品视| 97涩涩爰在线观看亚洲| 国产日韩在线精品av| 高清欧美性猛交xxxx黑人猛交| 91网站在线免费观看| 亚洲精品日韩av| 97免费中文视频在线观看| 亚洲国产精品成人av| 高清一区二区三区四区五区| 欧美性精品220| 亚洲一区二区三区在线视频| 26uuu亚洲国产精品| 高清日韩电视剧大全免费播放在线观看| 亚洲精品美女免费| 日韩精品在线视频观看| 富二代精品短视频| 精品久久久久久中文字幕| 亚洲精品欧美极品| 精品欧美国产一区二区三区| 欧美在线视频免费观看| 久久久精品国产网站| 蜜臀久久99精品久久久无需会员| 欧美精品一区在线播放| 亚洲精品视频免费| 中文字幕日韩精品有码视频| 欧美一区二区三区精品电影| 亚洲电影免费观看高清完整版在线观看| 日韩精品一区二区三区第95| 日本欧美中文字幕| 亲爱的老师9免费观看全集电视剧| 久久久精品视频在线观看| 日韩美女写真福利在线观看| 国产成人在线播放| 国产小视频国产精品| 国产精品久久久久久久久久新婚| 中文字幕日本欧美| 国产精品久久色| 欧美国产日产韩国视频| 久久久国产精品亚洲一区| 久久中文字幕一区| 97在线观看免费高清| 久久久午夜视频| 国产精品三级美女白浆呻吟| 久久久久免费视频| 亚洲伊人久久大香线蕉av| 韩国v欧美v日本v亚洲| 日本精品一区二区三区在线| 日本精品一区二区三区在线播放视频| 国产精品白嫩初高中害羞小美女| 日韩精品视频在线观看网址| 欧美一级淫片丝袜脚交| 黑人巨大精品欧美一区免费视频| 一区二区三区视频在线| 久久精品国产亚洲一区二区| 日韩成人在线播放| 欧美成在线视频| 精品呦交小u女在线| 色偷偷偷综合中文字幕;dd| 日韩精品在线看| 2019中文字幕免费视频| 麻豆乱码国产一区二区三区| 亚洲一区www| 九九热这里只有精品6| 日韩电影中文字幕一区| 久久久久久久久久久免费| 亚洲人成网站色ww在线| 国产成人综合亚洲| 色99之美女主播在线视频| 国产综合福利在线| 亚洲91av视频| 欧美激情xxxxx| 久久久久久亚洲精品中文字幕| 日韩av三级在线观看| 国产一区二区在线免费视频| 免费91麻豆精品国产自产在线观看| 欧美色另类天堂2015| 国产ts一区二区| 亚洲电影免费观看高清完整版| 久久久久久亚洲精品不卡| 精品国偷自产在线视频| 亚洲一区美女视频在线观看免费| 日韩不卡中文字幕| 久久伊人91精品综合网站| 国产亚洲精品久久久久久牛牛| 中文在线资源观看视频网站免费不卡| 欧美电影免费观看网站| 91成人福利在线| 久久成人在线视频| 亚洲日本欧美日韩高观看| 国产精品久久久av久久久| 一本色道久久综合狠狠躁篇的优点| 亚洲黄色av网站| 日韩一区二区三区国产| 亚洲国产精品专区久久| 韩国一区二区电影| 久久成人一区二区| 国产精品自产拍在线观看中文| 国产香蕉精品视频一区二区三区| 国产亚洲一区精品| 国产精品天天狠天天看| 成人午夜在线影院| 91精品国产91久久久久久不卡| 日韩中文字幕av| 26uuu另类亚洲欧美日本老年| 亚洲免费视频网站| 成人国产精品av| 国产视频欧美视频| 亚洲福利视频久久| xvideos成人免费中文版| 日韩电视剧在线观看免费网站|