主要針對併發狀況下,經過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