PHP使用Redis實現消息隊列
阿新 • • 發佈:2018-01-15
.com 正在 res mys ++ 簡單的 root order 訪問
消息隊列可以使用MySQL來實現,可以參考博客PHP使用MySQL實現消息隊列,雖然用MySQL可以實現,但是一般不這麽用,因為MySQL的數據都存在硬盤中,而從硬盤中對MySQL的操作,I/O花費的代價很大,所以一般使用緩存來實現,因為緩存的數據是在內存中,訪問內存的速度遠快於訪問硬盤的速度。另一方面,Redis有list類型的數據結構,非常適合做消息隊列。
這裏舉一個很簡單的秒殺例子:秒殺的名額只有5個,即消息隊列的長度為5,名額已經滿了之後,通知後來的人已經秒殺結束。然後後臺會從消息隊列中讀取數據,然後將數據存到數據庫中。因為消息隊列長度只有5個,而且秒殺的那短短1,2秒並沒有直接操作數據庫,所以對於數據庫來說,並沒有什麽壓力。
先看一下數據庫表(seckill)的結構:
mysql> desc seckill; +----------+---------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------+---------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | order_id | int(11) | NO | | NULL | | | mobile | int(8) | YES | | 8888888 | | +----------+---------+------+-----+---------+----------------+ 3 rows in set (0.11 sec)
然後是進行秒殺的用戶程序(user.php),為了模擬,這裏使用for循環來實現在短時間內發起大量的請求,但是要知道這是不準確的。
<?php $redis=new Redis(); $redis->connect("127.0.0.1",6379); $key="seckill"; for($i=0;$i<10;$i++){ $order_id=rand(100000,999999); $mobile=rand(11111111,99999999); $value=$order_id."#".$mobile;//連接之後作為值 if($redis->llen("seckill") <5 ){ echo "秒殺成功,訂單號為$order_id, 手機號為$mobile\n"; $redis->lpush($key,$value); } else { echo "秒殺已經結束\n"; } } ?>
運行結果:
[root@localhost ~]# php user.php 秒殺成功,訂單號為643275, 手機號為50104929 秒殺成功,訂單號為393012, 手機號為31213041 秒殺成功,訂單號為994790, 手機號為23107569 秒殺成功,訂單號為186135, 手機號為36549273 秒殺成功,訂單號為821972, 手機號為11217760 秒殺已經結束 秒殺已經結束 秒殺已經結束 秒殺已經結束 秒殺已經結束
然後是後臺程序將redis中訂單讀出,處理後存進數據庫。
<?php $redis=new Redis(); $redis->connect("127.0.0.1",6379); $pdo=new PDO("mysql:host=localhost;dbname=test","root","root"); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $stmt=$pdo->prepare("insert into seckill(id,order_id,mobile) values(?,?,?)"); $key="seckill"; while($redis->llen($key)){ //因為消息隊列中添加消息是使用lpush,所以這裏使用rpop $order=$redis->rpop($key); list($order_id,$mobile)=explode("#",$order); echo "正在處理訂單$order_id\t"; try{ $res=$stmt->execute(array(null,$order_id,$mobile)); if(!$res){ throw new PDOException("wrong"); } } catch (PDOException $e){ echo $e->getMessage(); echo "訂單處理失敗\n"; $redis->rpush($key,$order_id."#".$mobile);//將數據恢復達到隊列中 continue; } echo "訂單處理完成\n"; } ?>
運行:
[root@localhost ~]# php consumer.php 正在處理訂單643275 訂單處理完成 正在處理訂單393012 訂單處理完成 正在處理訂單994790 訂單處理完成 正在處理訂單186135 訂單處理完成 正在處理訂單821972 訂單處理完成
查看數據庫:
mysql> select * from seckill; +----+----------+----------+ | id | order_id | mobile | +----+----------+----------+ | 1 | 643275 | 50104929 | | 2 | 393012 | 31213041 | | 3 | 994790 | 23107569 | | 4 | 186135 | 36549273 | | 5 | 821972 | 11217760 | +----+----------+----------+ 5 rows in set (0.00 sec)
PHP使用Redis實現消息隊列