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

首頁 > 數據庫 > Redis > 正文

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

2020-03-17 12:39:46
字體:
來源:轉載
供稿:網友

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

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實現高并發下的搶購、秒殺功能的實例全部內容了,希望大家多多支持VEVB武林網~


注:相關教程知識閱讀請移步到Redis頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产日韩av在线| 精品久久久999| 亚洲成人激情在线观看| 久久久999精品免费| 日本欧美在线视频| 久久躁日日躁aaaaxxxx| 日韩在线视频免费观看高清中文| 国产亚洲精品美女久久久| 亚洲欧美国产一区二区三区| 狠狠综合久久av一区二区小说| 日韩成人高清在线| 51精品在线观看| 国产视频精品免费播放| 亚洲精品永久免费精品| 日韩av一区二区在线观看| 亚洲最大激情中文字幕| 欧美日韩国产123| 在线观看欧美日韩| 国产精品男人的天堂| 这里只有精品丝袜| 日韩电影大全免费观看2023年上| 亚洲电影免费观看高清完整版在线观看| 亚洲伊人一本大道中文字幕| 欧美激情视频一区二区| 亚洲国产精品久久| 97涩涩爰在线观看亚洲| 91视频国产一区| 久久免费观看视频| 欧美理论在线观看| 国产精品人成电影在线观看| 隔壁老王国产在线精品| 成人网页在线免费观看| 久久国产精品网站| 欧美亚洲在线播放| 欧美日韩电影在线观看| 国产精品亚洲欧美导航| 69国产精品成人在线播放| 欧美亚洲国产成人精品| 狠狠操狠狠色综合网| 久久99久久99精品免观看粉嫩| 精品美女永久免费视频| 久久97久久97精品免视看| 精品国产一区av| 欧美疯狂xxxx大交乱88av| 欧美黑人性生活视频| 欧美性猛交xxxx黑人猛交| 亚洲美女av网站| 日本精品视频在线| 久久久免费精品| 中文字幕精品一区二区精品| 91精品视频观看| 欧美成人sm免费视频| 久久综合免费视频| 久久男人资源视频| 91亚洲人电影| 美女视频久久黄| 日本成人免费在线| 午夜精品在线观看| www.亚洲免费视频| 国产欧美在线看| 欧美三级欧美成人高清www| 日韩免费看的电影电视剧大全| 日韩欧美亚洲成人| 一区二区三区四区在线观看视频| 亚洲性猛交xxxxwww| 欧美国产精品人人做人人爱| 欧美区二区三区| 国产精品永久免费观看| 青草热久免费精品视频| 亚洲一区二区三| 亚洲国产精品久久久久秋霞不卡| 国产专区欧美专区| 欧美日韩成人在线播放| 91在线国产电影| 亚洲级视频在线观看免费1级| 久99九色视频在线观看| 国产精品福利在线| 午夜精品久久久久久久99热浪潮| 午夜精品一区二区三区在线视频| 欧美在线视频观看免费网站| 日韩av一卡二卡| 91av在线网站| 国产精品第一第二| 亚洲sss综合天堂久久| 午夜精品福利电影| 中文字幕亚洲综合久久| 亚洲国产精品美女| 国产精品免费久久久久影院| 久久婷婷国产麻豆91天堂| 国产成人综合亚洲| 中文字幕在线看视频国产欧美在线看完整| 久久视频在线观看免费| 日韩精品中文字幕视频在线| 日韩国产精品视频| 亚洲国产精品女人久久久| 亚洲精品一区二区网址| 久久成人精品电影| 国产欧美精品一区二区三区-老狼| 亚洲欧美成人网| 久久久久久九九九| 秋霞av国产精品一区| 中文字幕久久久av一区| 亚洲精品成人久久| 国产精品综合不卡av| 国产乱肥老妇国产一区二| 九九热精品视频| 第一福利永久视频精品| 日韩av不卡电影| 亚洲老头同性xxxxx| 91精品久久久久久久久不口人| 亚洲精品网站在线播放gif| 亚洲精品电影在线观看| 亚洲小视频在线| 国产丝袜一区二区三区免费视频| 日韩大胆人体377p| 日韩高清免费在线| 黄色成人在线免费| 日韩a**中文字幕| 亚洲国产欧美一区二区丝袜黑人| 欧美亚洲激情视频| 欧美一区三区三区高中清蜜桃| 91网在线免费观看| 国产精品偷伦一区二区| 中文字幕精品网| 色妞欧美日韩在线| 国产一区二区三区高清在线观看| 欧美日韩亚洲高清| 亚洲理论电影网| 成人久久一区二区三区| 亚洲桃花岛网站| 成人国产精品久久久久久亚洲| 亚洲欧美视频在线| 欧美高清不卡在线| 国产精品www色诱视频| 91精品在线播放| 国自产精品手机在线观看视频| 欧美成人中文字幕| 日韩精品亚洲元码| 精品偷拍一区二区三区在线看| 日韩av在线精品| 亚洲精品一区二区网址| 日本精品久久久久久久| 日韩第一页在线| 欧美极品美女视频网站在线观看免费| 92裸体在线视频网站| 2019亚洲男人天堂| 国产精品揄拍一区二区| 亚洲一区二区少妇| 91久久精品国产91久久性色| 中文字幕亚洲图片| 亚洲最大的成人网| 久久久精品一区| 欧美性开放视频| 欧美黑人视频一区| 岛国视频午夜一区免费在线观看| 国产成人精彩在线视频九色| 成人国产精品日本在线| 98精品国产高清在线xxxx天堂| 色999日韩欧美国产| 亚洲精品456在线播放狼人| 亚洲另类激情图| 亚洲一区二区中文| 欧美成人午夜免费视在线看片| 午夜精品视频网站|