php+redis实现消息队列

队列的概念

  • 1、是队列结构的中间件
  • 2、消息放入后不需要立即处理
  • 3、由订阅者/消费者按顺序处理

队列原理

也是解耦的原理:业务系统和队列处理系统没有关系

一个写(业务系统),一个读(队列管理系统)。写的只管往队列里写,别的不用操心,读的能不能读完和写的也没有关系

同样,读的只管从队列里往外读,来活儿就干,没活儿歇着

实现介质

  • 1、使用mysql:可靠性高,易实现,速度慢
  • 2、使用redis:速度快,单条大消息包时效率低
  • 3、使用更专业的第三方类库:专业性强,可靠,学习成本高。

消息队列

是在消息的传输过程中保存消息的容器。消息队列管理器在将消息从它的源中继到它的目标时充当中间人。队列的主要目的是提供路由并保证消息的传递;如果发送消息时接收者不可用,消息队列会保留消息,直到可以成功地传递它

应用场景:异步处理,应用解耦,流量削锋和消息通讯四个场景

1、异步处理

场景说明:用户注册后,需要发注册邮件和注册短信。

注解:自行考虑ajax中的异步。

2、应用解耦

一般订单系统和库存系统是一体的,但是如果一方出现问题,那么这个订单就失败了。

订单系统:用户下单后,订单系统完成持久化处理,将消息写入消息队列,返回用户订单下单成功。
库存系统:订阅下单的消息,采用拉/推的方式,获取下单信息,库存系统根据下单信息,进行库存操作。
假如:在下单时库存系统不能正常使用。也不影响正常下单,因为下单后,订单系统写入消息队列就不再关心其他的后续操作了。实现订单系统与库存系统的应用解耦。

注解:感觉特别像行为驱动,消息队列中存储的就是每个行为

3、流量消锋(一般在秒杀或团抢活动中使用广泛)

注解:一般秒杀时订单会特别的多,但是数据库无法一次性的处理这么多,所以可以先存在消息队列中,无论我进的速度多快,出的速度都是一定的。不知道算不算属于漏斗模型的一部分

php的redis扩展:https://github.com/phpredis/phpredis

  • 1)redis函数rpush,lpop
  • 2).Linux的crontab

创建demo.php和index.php

<?php

$redis = new Redis();

$redis->connect('127.0.0.1',6379);

$password = '123456';

$redis->auth($password);

$arr = array('h','e','l','l','o','w','o','r','l','d');

foreach($arr as $k=>$v){

  $redis->rpush("mylist",$v);

}

<?php

$redis = new Redis();

$redis->connect('127.0.0.1',6379);

$password = '123456';

$redis->auth($password);

//list类型出队操作

$value = $redis->lpop('mylist');

if($value){

 echo "出队的值".$value;

}else{

  echo "出队完成";

}

?>

建立定时任务

*/1 * * * * root php /wwwroot/workplace/redis/index.php

*/3 * * * * root php /wwwroot/workplace/redis/demo.php

关于秒杀

秒杀是我们常见的一个应用场景,主要需要解决的两个问题,一个是高并发对数据库产生的压力,另一个是正确的减少库存的问题,即超卖问题。

下面是我总结的几种方案:

  • 优化方案一:将库存字段number字段设为unsigned,当库存为0时,因为字段不能为负数,将会返回false。
  • 优化方案二:使用mysql的事物锁,锁住要操作的行。
  • 优化方案三:使用非堵塞的文件排它锁
  • 优化方案四:使用redis队列,因为POP操作是原子的即使有很多用户同时到达,也是依次执行。

当然真实的秒杀场景没有说的这么简单,比这复杂的多,有很多需要注意的地方,比如抢购页面做成静态页,通过ajax调用接口。

还有一种场景,可能会出现一个用户抢多个秒杀商品的结果,这时候我们就需要一个排队队列,一个抢购结果队列,以及一个库存队列,循环处理从排队队列中取出一个用户,判断用户是否已经在抢购结构队列里面,相当于一个过滤,如果已经在结果队列里面,则表示已抢购,反之,表示未抢购,库存减1。

建议:
  • 1.秒杀这种活动不会经常出现,可以使用一台专门的服务器只做秒杀。
  • 2.Mysql事物在高并发下,性能下降很厉害,文件锁的方式也是如此,推荐使用redis队列来实现。

推荐
坚持原创技术分享,您的支持将鼓励我继续创作!