搶購、秒殺是如今很常見的乙個應用場景,主要需要解決的問題有兩個: 1 高併發對資料庫產生的壓力 2 競爭狀態下如何解決庫存的正確減少("超賣"問題) 對於第乙個問題,已經很容易想到用快取來處理搶購,避免直接運算元據庫,例如使用redis。 重點在於第二個問題 優化方案1:將庫存欄位number欄位設為unsigned,當庫存為0時,因為字段不能為負數,將會返回false(略) 優化方案2:使用的事務,鎖住操作的行
<?php$conn=mysql_connect("localhost","big","123456");
if(!$conn)
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()
//記錄日誌
function insertlog($event,$type=0)
//模擬下單操作
//庫存是否大於0
mysql_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) where sku_id='$sku_id'";
$store_rs=mysql_query($sql,$conn);
if(mysql_affected_rows())else
}else
?>
優化方案3:使用非阻塞的檔案排他鎖
<?php$conn=mysql_connect("localhost","root","123456");
if(!$conn)
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()
//記錄日誌
function insertlog($event,$type=0)
$fp = fopen("lock.txt", "w+");
if(!flock($fp,lock_ex | lock_nb))
//下單
$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) where sku_id='$sku_id'";
$store_rs=mysql_query($sql,$conn);
if(mysql_affected_rows())else
}else
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++)
echo $redis->llen('goods_store');
?>
搶購、描述邏輯
<?php
$conn=mysql_connect("localhost","big","123456");
if(!$conn)
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()
//記錄日誌
function insertlog($event,$type=0)
//模擬下單操作
//下單前判斷redis佇列庫存量
$redis=new redis();
$result=$redis->connect('127.0.0.1',6379);
$count=$redis->lpop('goods_store');
if(!$count)
//生成訂單
$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- where sku_id='$sku_id'";
$store_rs=mysql_query($sql,$conn);
if(mysql_affected_rows())else
上述只是簡單模擬高併發下的搶購,真實場景要比這複雜很多,很多注意的地方
如搶購頁面做成靜態的,通過ajax呼叫介面
再如上面的會導致乙個使用者搶多個,思路:
需要乙個排隊佇列和搶購結果佇列及庫存佇列。高併發情況,先將使用者進入排隊佇列,用乙個執行緒迴圈處理從排隊佇列取出乙個使用者,判斷使用者是否已在搶購結果佇列,如果在,則已搶購,否則未搶購,庫存減1,寫資料庫,將使用者入結果佇列。
Redis高併發和高可用
如何保證 redis 的高併發和高可用?redis 的主從複製原理能介紹一下麼?redis 的哨兵原理能介紹一下麼?其實問這個問題,主要是考考你,redis 單機能承載多高併發?如果單機扛不住如何擴容扛更多的併發?redis 會不會掛?既然 redis 會掛那怎麼保證 redis 是高可用的?其實針...
PHP和Redis實現在高併發下的搶購及秒殺功能
搶購 秒殺是平常很常見的場景,面試的時候面試官也經常會問到,比如問你 中的搶購秒殺是怎麼實現的等等。搶購 秒殺實現很簡單,但是有些問題需要解決,主要針對兩個問題 一 高併發對資料庫產生的壓力 二 競爭狀態下如何解決庫存的正確減少 超賣 問題 第乙個問題,對於php來說很簡單,用快取技術就可以緩解資料...
php 高併發餘額正確 PHP高併發處理方案
web資源防盜煉 盜鏈是什麼,為什麼要防?由於別人盜鏈你的資源會加重你的伺服器負擔,所以我們需要防止,而且會影響統計 防盜鍊是什麼?有哪幾種方式?防止別人通過一些技術手段繞過本站的資源展示頁,盜用本站資源,讓繞開本站資源展示頁面的資源鏈結失效 大大減輕伺服器壓力 防盜煉的工作原理 location ...