本文摘自PHP中文网,作者尚,侵删。

应用场景:
例如秒杀。瞬时大量写入订单到数据库,导致数据库无法及时响应。此时可以采用Redis做消息队列,把所有需要写入的数据先写入Redis消息队列中,然后同时在服务器开启php-cli进程循环读取队列中的数据,异步写入数据库。使用redis做消息队列可能会出现消息丢失的情况,因为没有消息接收的确认机制。大型程序,应该使用类似RabitMQ来做专业消息队列。
1、使用publish/subscribe方式作为消息队列
特点:一个消息发布者(生产者),可以对应多个消息订阅者(消费者)。当消息发布到消息队列的时候,所有消息订阅者都可以收到消息。适用于分布式消息分发。client以阻塞的方式等待publish端的消息。多个消费者不能加快消息消费速度。
消息生产:
1 2 | $params =json_encode([ 'x_uid' => $x_uid , 'phone' => $phone ]);
$redis ->publish( 'test' , $params );
|
消息消费(php-cli模式运行):
1 2 3 4 5 6 7 8 | $redis = new Redis(); $redis ->pconnect( '127.0.0.1' );
$redis ->subscribe( array ( 'test' ), 'callback' );
functioncallback( $redis , $chan , $msg ){
$params = json_decode( $msg ,true);
....
}
|
pconnect和connect区别:
connect:脚本结束之后连接就释放了。
pconnect:脚本结束之后连接不释放,连接保持在php-fpm进程中。
所以使用pconnect代替connect,可以减少频繁建立redis连接的消耗。
2、使用list作为redis消息队列
特点:一个消息生产者,对应一个消息消费者。多个消费者可以加快消息消费速度。
消息生产:
1 2 3 4 5 6 | $redis =newRedis();
$redis ->connect( '127.0.0.1' );
$list = json_encode([ 'x_uid' => $x_uid , 'phone' => $phone , 'goods_id' => $goodsId ,
'add_time' => time(), 'num_field' => $num_field ]);
$redis ->lpush( 'winer' , $list );
|
注意:brpop消费数据如果没有成功写入数据库,会导致数据丢失。强烈要求生产数据时,二次备份到redis或文件中。
消息消费(php-cli模式运行):
注意:MySQL不主动关闭连接的情况下,一次连接最长八小时后自动断开。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | <?php
$conn = mysqli_connect( "localhost" , "root" , "root" );
if (! $conn ){
die ( "连接数据库失败:" . mysqli_error());
}
mysqli_select_db( $conn , "api" );
mysqli_query( $conn , "set character set 'utf8'" );
mysqli_query( $conn , "set names 'utf8'" );
$redis =newRedis();
$redis ->connect( '127.0.0.1' ,6379);
$redis ->setOption(Redis::OPT_READ_TIMEOUT,-1);
echo 'Listening...' ;
$i =1;
while (true){
$data = $redis ->brpop( 'winer' ,0);
$info = json_decode( $data [1],true);
$x_uid = $info [ 'x_uid' ];
$phone = $info [ 'phone' ];
$goods_id = $info [ 'goods_id' ];
$add_time = $info [ 'add_time' ];
$num_field = $info [ 'num_field' ];
$sql = "insert into hd_hengda11_order (`x_uid`,`phone`,`goods_id`,`add_time`)
values ( $x_uid , $phone , $goods_id , $add_time )"
$re = mysqli_query( $conn , $sql );
echo $i . '_ok||' ;
$i ++;
}
?>
|
其他:
秒杀场景防止商品超卖:
1、数据库中设置商品数量为无符号型,即不允许负数。当更新商品数量到负数时,返回false。
2、商品数量存在Redis的list队列中,每次抢购就pop删除一个元素出队列。
1 2 3 4 | for ( $j =1; $j <=10; $j ++){ /设置商品数量为10
$re =Redis::lpush(gooods_count,1);
}
|
判断商品数量逻辑
1 2 3 4 5 | $count =Redis::lpop( 'gooods_count' );
if (! $count ){
return '已经抢光了哦' ;
}
|
更多Redis相关知识,请访问Redis使用教程栏目!
以上就是redis可以做消息队列吗的详细内容,更多文章请关注木庄网络博客!
相关阅读 >>
redis可以做消息队列吗
更多相关阅读请进入《redis可以做消息队列吗》频道 >>
机械工业出版社
本书主要讲述了数据模型、基于对象的数据库和XML、数据存储和查询、事务管理、体系结构等方面的内容。
转载请注明出处:木庄网络博客 » redis可以做消息队列吗