php redis實現秒殺功能

主要針對併發狀況下,經過redis的分佈式鎖和隊列的方式進行處理的代碼git

Queue:{商品ID}:   數據類型是有序集合(zset),成員是用戶ID,score是用戶入隊的時間戳github

Lock:Queue:{商品ID}: 數據類型是字符串(string),存儲的是該鎖的過時時間redis

goods:{商品ID}:stock: 存儲的是商品的庫存數量併發

簡單介紹demo代碼中的實現思路:分佈式

將當前秒殺的商品id做爲一個隊列名稱this

$queue_name = 「Queue:{商品ID}」;blog

對$queue_name進行加鎖隊列

    經過setnx(知足原子性)實現加鎖  :$redis->setnx("Lock:Queue:{商品ID}",  $expire time)ip

    加鎖成功,給該鎖設置一個過時時間,主要是爲了防止死鎖字符串

    若是加鎖失敗,經過設置休眠時間,進行循環請求

加鎖成功後,判斷隊列中的成員數是否超過指定的大小

$count = $this->redis->zCard("Queue:{$name}");
if($count >=  $this->redis->get("goods:{$name}:stock")) {
    $this->lockModel->unlock("Queue:$name");
    return '超過指定集合數量';
}

 判斷用戶ID是否存在隊列中,如不存在則加入隊列(score:存入的是當前時間戳 )

if (false === $this->redis->zScore("Queue:$name", $user_id)) {
    $this->redis->zAdd("Queue:$name", $score, $user_id);
}

入隊成功,進行解鎖$redis->del("Lock:Queue:{商品ID}");提示用戶搶購成功。成功的用戶會跳轉到確認購買的頁面,點擊確認後纔會生成訂單、出隊等後續操做

ps: 針對多個帳號,一次性發送多個請求能夠經過ip的訪問頻率的限制來預防

參考文章:http://blog.jobbole.com/95156/

demo代碼的下載地址:https://github.com/Ritajiajia/redis_test/tree/master/test/seckill

相關文章
相關標籤/搜索