国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 語言 > PHP > 正文

php和redis實現秒殺活動的流程

2024-05-05 00:10:22
字體:
來源:轉載
供稿:網友

1 說明

前段時間面試的時候,一直被問到如何設計一個秒殺活動,但是無奈沒有此方面的實際經驗,所以只好憑著自己的理解和一些資料去設計這么一個程序

主要利用到了redis的string和set,string主要是利用它的k-v結構去對庫存進行處理,也可以用list的數據結構來處理商品的庫存,set則用來確保用戶進行重復的提交

其中我們最主要解決的問題是

-防止并發產生超搶/超賣

2 流程設計

php,redis,秒殺活動

3 代碼

3.1 服務端代碼

class MiaoSha{ const MSG_REPEAT_USER = '請勿重復參與'; const MSG_EMPTY_STOCK = '庫存不足'; const MSG_KEY_NOT_EXIST = 'key不存在'; const IP_POOL = 'ip_pool'; const USER_POOL = 'user_pool'; /** @var Redis */ public $redis; public $key; public function __construct($key = '') {  $this->checkKey($key);  $this->redis = new Redis(); //todo 連接池  $this->redis->connect('127.0.0.1'); } public function checkKey($key = '') {  if(!$key) {   throw new Exception(self::MSG_KEY_NOT_EXIST);  } else {   $this->key = $key;  } } public function setStock($value = 0) {  if($this->redis->exists($this->key) == 0) {   $this->redis->set($this->key,$value);  } } public function checkIp($ip = 0) {  $sKey = $this->key . self::IP_POOL;  if(!$ip || $this->redis->sIsMember($sKey,$ip)) {   throw new Exception(self::MSG_REPEAT_USER);  } } public function checkUser($user = 0) {  $sKey = $this->key . self::USER_POOL;  if(!$user || $this->redis->sIsMember($sKey,$user)) {   throw new Exception(self::MSG_REPEAT_USER);  } } public function checkStock($user = 0, $ip = 0) {  $num = $this->redis->decr($this->key);  if($num < 0 ) {   throw new Exception(self::MSG_EMPTY_STOCK);  } else {   $this->redis->sAdd($this->key . self::USER_POOL, $user);   $this->redis->sAdd($this->key . self::IP_POOL, $ip);   //todo add to mysql   echo 'success' . PHP_EOL;   error_log('success' . $user . PHP_EOL,3,'/var/www/html/demo/log/debug.log');  } } /**  * @note:此種做法不能防止并發  * @func checkStockFail  * @param int $user  * @param int $ip  * @throws Exception  */ public function checkStockFail($user = 0,$ip = 0) {  $num = $this->redis->get($this->key);  if($num > 0 ){   $this->redis->sAdd($this->key . self::USER_POOL, $user);   $this->redis->sAdd($this->key . self::IP_POOL, $ip);   //todo add to mysql   echo 'success' . PHP_EOL;   error_log('success' . $user . PHP_EOL,3,'/var/www/html/demo/log/debug.log');   $num--;   $this->redis->set($this->key,$num);  } else {   throw new Exception(self::MSG_EMPTY_STOCK);  } }}

 

3.2 客戶端測試代碼

function test(){ try{  $key = 'cup_';  $handler = new MiaoSha($key);  $handler->setStock(10);  $user = rand(1,10000);  $ip = $user;  $handler->checkIp($ip);  $handler->checkUser($user);  $handler->checkStock($user,$ip); } catch (/Exception $e) {  echo $e->getMessage() . PHP_EOL;  error_log('fail' . $e->getMessage() .PHP_EOL,3,'/var/www/html/demo/log/debug.log'); }}function test2(){ try{  $key = 'cup_';  $handler = new MiaoSha($key);  $handler->setStock(10);  $user = rand(1,10000);  $ip = $user;  $handler->checkIp($ip);  $handler->checkUser($user);  $handler->checkStockFail($user,$ip); //不能防止并發的 } catch (/Exception $e) {  echo $e->getMessage() . PHP_EOL;  error_log('fail' . $e->getMessage() .PHP_EOL,3,'/var/www/html/demo/log/debug.log'); }}

 

4 測試

測試環境說明

  • ubantu16.04
  • redis2.8.4
  • php5.5

在服務端代碼里面我們有兩個函數分別是checkStock和checkStockFail,其中checkStockFail不能在高并發的情況下效果很差,不能在redis層面保證庫存為0的時候終止操作。

我們利用ab工具進行測試

其中 www.hello.com 是配置的虛擬主機名稱 flash-sale.php 是我們腳本的名稱

#第1種情況 500并發下 用客戶端的test2()去執行 ab -n 500 -c 100 www.hello.com/flash-sale.php

 

log日志的記錄結果:

php,redis,秒殺活動

#第2種情況 5000并發下 用客戶端的test2()去執行 ab -n 5000 -c 1000 www.hello.com/flash-sale.php

 

log日志的記錄結果:

php,redis,秒殺活動

#第3種情況 500并發下 用客戶端的test()去執行 ab -n 500 -c 100 www.hello.com/flash-sale.php

log日志的記錄結果:

php,redis,秒殺活動

#第4種情況 5000并發下 用客戶端的test()去執行 ab -n 5000 -c 1000 www.hello.com/flash-sale.php

 

log日志的記錄結果:

php,redis,秒殺活動

5 總結

我們從日志中可以很明顯的看出第3、4中情況下,可以保證商品的數量總是我們設置的庫存值10,但是在情況1、2下,則產生了超賣的現象

redis來控制并發主要是利用了其api都是原子性操作的優勢,從checkStock和checkStockFail中可以看出,一個是直接decr對庫存進行減一操作,所以不存在并發的情況,但是另一個方法是將庫存值先取出做減一操作然后再重新賦值,這樣的話,在并發下,多個進程會讀取到多個庫存為1的值,因此會產生超賣的情況

以上所述是小編給大家介紹的php和redis實現秒殺活動的流程,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對VeVb武林網網站的支持!
如果你覺得本文對你有幫助,歡迎轉載,煩請注明出處,謝謝!


注:相關教程知識閱讀請移步到PHP教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表

圖片精選

主站蜘蛛池模板: 白朗县| 苍梧县| 武邑县| 互助| 南涧| 双峰县| 张家港市| 依安县| 仪陇县| 永登县| 双辽市| 郴州市| 轮台县| 紫金县| 宜城市| 竹溪县| 商河县| 周宁县| 上思县| 翁牛特旗| 大安市| 遵义市| 南漳县| 沧源| 拜泉县| 石狮市| 水富县| 宁河县| 甘洛县| 苏州市| 武宣县| 财经| 凭祥市| 邵阳县| 镇平县| 临清市| 顺平县| 开化县| 八宿县| 兴宁市| 常熟市|