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

2022-08-14 04:18:11 字數 3446 閱讀 1350

搶購、秒殺是如今很常見的乙個應用場景,主要需要解決的問題有兩個: 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 ...