日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > php >内容正文

php

php生成 sku_高并发下,php与redis实现的抢购、秒杀功能

發(fā)布時(shí)間:2023/12/3 php 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 php生成 sku_高并发下,php与redis实现的抢购、秒杀功能 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

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

1 高并發(fā)對數(shù)據(jù)庫產(chǎn)生的壓力

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

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

重點(diǎn)在于第二個(gè)問題

常規(guī)寫法:

查詢出對應(yīng)商品的庫存,看是否大于0,然后執(zhí)行生成訂單等操作,但是在判斷庫存是否大于0處,如果在高并發(fā)下就會(huì)有問題,導(dǎo)致庫存量出現(xiàn)負(fù)數(shù)

<?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'";//解鎖 此時(shí)ih_store數(shù)據(jù)中g(shù)oods_id='$goods_id' and sku_id='$sku_id' 的數(shù)據(jù)被鎖住(注3),其它事務(wù)必須等待此次事務(wù) 提交后才能執(zhí)行 $rs=mysql_query($sql,$conn); $row=mysql_fetch_assoc($rs); if($row['number']>0){//高并發(fā)下會(huì)導(dǎo)致超賣$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('庫存不夠'); } ?>

優(yōu)化方案1:將庫存字段number字段設(shè)為unsigned,當(dāng)庫存為0時(shí),因?yàn)樽侄尾荒転樨?fù)數(shù),將會(huì)返回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('庫存減少成功'); }

優(yōu)化方案2:使用MySQL的事務(wù),鎖住操作的行

<?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 mysql_query("BEGIN"); //開始事務(wù) $sql="select number from ih_store where goods_id='$goods_id' and sku_id='$sku_id' FOR UPDATE";//此時(shí)這條記錄被鎖住,其它事務(wù)必須等待此次事務(wù)提交后才能執(zhí)行 $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");//事務(wù)提交即解鎖}else{ insertLog('庫存減少失敗');} }else{insertLog('庫存不夠');mysql_query("ROLLBACK"); } ?>

優(yōu)化方案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 "系統(tǒng)繁忙,請稍后再試";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);

優(yōu)化方案4:使用redis隊(duì)列,因?yàn)閜op操作是原子的,即使有很多用戶同時(shí)到達(dá),也是依次執(zhí)行,推薦使用(mysql事務(wù)在高并發(fā)下性能下降很厲害,文件鎖的方式也是)

先將商品庫存如隊(duì)列

<?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隊(duì)列庫存量 $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高并發(fā)測試

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

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

如搶購頁面做成靜態(tài)的,通過ajax調(diào)用接口

再如上面的會(huì)導(dǎo)致一個(gè)用戶搶多個(gè),思路:

需要一個(gè)排隊(duì)隊(duì)列和搶購結(jié)果隊(duì)列及庫存隊(duì)列。高并發(fā)情況,先將用戶進(jìn)入排隊(duì)隊(duì)列,用一個(gè)線程循環(huán)處理從排隊(duì)隊(duì)列取出一個(gè)用戶,判斷用戶是否已在搶購結(jié)果隊(duì)列,如果在,則已搶購,否則未搶購,庫存減1,寫數(shù)據(jù)庫,將用戶入結(jié)果隊(duì)列。

測試數(shù)據(jù)表

-- -- 數(shù)據(jù)庫: `big` ---- ---------------------------------------------------------- -- 表的結(jié)構(gòu) `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 ;-- -- 轉(zhuǎn)存表中的數(shù)據(jù) `ih_goods` --INSERT INTO `ih_goods` (`goods_id`, `cat_id`, `goods_name`) VALUES (1, 0, '小米手機(jī)');-- ---------------------------------------------------------- -- 表的結(jié)構(gòu) `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 ;-- -- 轉(zhuǎn)存表中的數(shù)據(jù) `ih_log` ---- ---------------------------------------------------------- -- 表的結(jié)構(gòu) `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 ;-- -- 轉(zhuǎn)存表中的數(shù)據(jù) `ih_order` ---- ---------------------------------------------------------- -- 表的結(jié)構(gòu) `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 ;-- -- 轉(zhuǎn)存表中的數(shù)據(jù) `ih_store` --INSERT INTO `ih_store` (`id`, `goods_id`, `sku_id`, `number`, `freez`) VALUES (1, 1, 11, 500, 0); 以上內(nèi)容希望幫助到大家,很多PHPer在進(jìn)階的時(shí)候總會(huì)遇到一些問題和瓶頸,業(yè)務(wù)代碼寫多了沒有方向感,不知道該從那里入手去提升,對此我整理了一些資料,包括但不限于:分布式架構(gòu)、高可擴(kuò)展、高性能、高并發(fā)、服務(wù)器性能調(diào)優(yōu)、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql優(yōu)化、shell腳本、Docker、微服務(wù)、Nginx等多個(gè)知識(shí)點(diǎn)高級進(jìn)階干貨需要的可以免費(fèi)分享給大家,需要請戳這里鏈接 或 者關(guān)注咱們下面的知乎專欄PHP架構(gòu)師圈子?zhuanlan.zhihu.com

總結(jié)

以上是生活随笔為你收集整理的php生成 sku_高并发下,php与redis实现的抢购、秒杀功能的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产激情四射 | h色视频在线观看 | 久久久天堂 | 国产男女视频在线观看 | 人人妻人人澡人人爽人人dvd | 最新视频–x99av | 国产一级在线播放 | 日本jizzjizz | 日本护士体内she精2xxx | 亚洲欧美精品aaaaaa片 | 无码人妻精品中文字幕 | 特级毛片爽www免费版 | 日韩黄色免费网站 | 亚洲精品成人无码熟妇在线 | 日本www免费 | 久久91亚洲精品中文字幕奶水 | 亚洲av无码一区二区三区在线 | 在线国产黄色 | 美女被叉叉的影院 | 公侵犯人妻一区二区 | 色噜噜在线观看 | 亚日韩欧美 | 日韩 欧美 精品 | 殴美毛片 | 麻豆av导航 | 欧美日韩成人在线播放 | 在线你懂的视频 | 男人操女人视频网站 | 欧美国产精品一区二区 | 欧美做受69 | 精品国产一区二区三区久久狼黑人 | 国产精品久久久久久精 | 亚洲最新在线视频 | 国产极品一区二区 | 双性尿奴穿贞c带憋尿 | 黄色网久久| av成人 | 永久国产 | 免费一级一片 | 日本黄色免费大片 | 年代下乡啪啪h文 | 国产男女猛烈无遮挡免费视频动漫 | 操女人免费视频 | 九九天堂 | 久久精品国产成人av | 超碰人人爱人人 | 综合精品久久 | 精品人妻无码一区二区三区换脸 | 国产欧美精品一区二区在线播放 | 欧美顶级少妇做爰 | 精品色| 巨大乳の揉んで乳榨り奶水 | 麻豆黄色网 | 999国产精品亚洲77777 | 中文字幕第12页 | 国产极品在线播放 | 男男野外做爰全过程69 | 欧美草b | 婷色 | 韩国精品在线观看 | 国产在线成人 | 可以免费看av的网址 | 六月久久 | 国产精品一线 | 嫩草视频在线观看视频 | 另类欧美亚洲 | 国产视频日韩 | 青青草原综合网 | 欧美精品一区二区性色a+v | 涩涩网站在线观看 | 黄色av中文字幕 | 久久网址 | 国产伦乱 | www.com亚洲 | 国产精品无码一区二区无人区多人 | 青青草自拍偷拍 | 中文字幕在线观看线人 | 久久人妻精品白浆国产 | 女人和拘做爰正片视频 | av卡一卡二| 综合xx网 | 国产伦精品一区二区三区视频痴汉 | 狠狠看 | 欧美理论在线 | 国产极品在线播放 | 奶波霸巨乳一二三区乳 | 亚洲h视频| 国产欧美精品一区二区 | 女人被狂躁c到高潮 | 男女互插视频 | 日韩大尺度视频 | 少妇大叫太粗太大爽一区二区 | 黄a大片| 大胸美女无遮挡 | 国产精品污www在线观看 | www.国产视频 | 黄色一级大片在线免费看国产一 | 欧美色婷婷 | 九九热精品视频在线播放 |