使用过redis做异步队列么,你是怎么用的?有什么缺点?
Redis设计主要是用来做缓存的,但是由于它自身的某种特性使得它可以用来做消息队列。
它有几个阻塞式的API可以使用,正是这些阻塞式的API让其有能力做消息队列;
另外,做消息队列的其他特性例如FIFO(先入先出)也很容易实现,只需要一个list对象从头取数据,从尾部塞数据即可;
Redis能做消息队列还得益于其list对象blpop brpop接口以及Pub/Sub(发布/订阅)的某些接口,它们都是阻塞版的,所以可以用来做消息队列。(List : lpush / rpop)
方式一:生产者与消费者模式
使用list结构作为队列,rpush生产消息,lpop消费消息,当lpop没有消息的时候,要适当sleep一会再重试。
或者,不用sleep,直接用blpop指令,在没有消息的时候,它会阻塞住直到消息到来。
具体文章可查看:PHP与redis队列实现电商订单自动确认收货
方式二:发布订阅者模式
使用pub/sub主题订阅者模式,可以实现1:N的消息队列。
基于事件的系统中,Pub/Sub是目前广泛使用的通信模型,它采用事件作为基本的通信机制,提供大规模系统所要求的松散耦合的交互模式:订阅者(如客户端)以事件订阅的方式表达出它有兴趣接收的一个事件或一类事件;发布者(如服务器)可将订阅者感兴趣的事件随时通知相关订阅者。
消息发布者,即publish客户端,无需独占链接,你可以在publish消息的同时,使用同一个redis-client链接进行其他操作(例如:INCR等)
消息订阅者,即subscribe客户端,需要独占链接,即进行subscribe期间,redis-client无法穿插其他操作,此时client以阻塞的方式等待“publish端”的消息;这一点很好理解,因此subscribe端需要使用单独的链接,甚至需要在额外的线程中使用。
redis做异步队列的缺点
在消费者下线的情况下,生产的消息会丢失。此场景,建议用MQ。
使用MQ可查看:在分布式系统上,你是如何处理数据的一致性的
下面用代码实际实现,用发布订阅者模式,给大家讲解讲解
消息订阅者subscribe.php
<?php
ini_set('default_socket_timeout', -1); //php配置设置不超时
$redis = new Redis();
$redis->connect("127.0.0.1",6379);
//$redis->setOption(Redis::OPT_READ_TIMEOUT, -1); //redis方式设置不超时,推荐
$redis->subscribe(['chan'],'callback'); //callback为回调函数名称
//$redis->subscribe(['chan'],array(new TestCall(),'callback') ); //如果回调函数是类中的方法名,这样写
// 回调函数,这里写处理逻辑
function callback($instance, $channelName, $message)
{
echo $channelName, "==>", $message, PHP_EOL;
//$instance,即为上面创建的redis实例对象,在回调函数中,默认的这个参数就是,因此不需专门传参。 这里除了SUBSCRIBE、PSUBSCRIBE、UNSUBSCRIBE、PUNSUBSCRIBE这4条命令之外其它命令都不能使用
//如果要使用redis中的其他命令,这样实现
$newredis = new Redis();
$newredis->connect("127.0.0.1", 6379);
echo $newredis->get('test') . PHP_EOL;
$newredis->close();
//可以根据$channelName, $message,处理不同的业务逻辑
switch($chan) {
case 'chan-1':
...
break;
case 'chan-2':
...
break;
}
switch($message) {
case 'msg1':
...
break;
case 'msg2':
...
break;
}
}
subscribe.php中设置不超时
方法1:ini_set('default_socket_timeout', -1);
方法2:$redis->setOption(Redis::OPT_READ_TIMEOUT, -1);
如果不设置不超时,60s后会报一个错误
PHP Fatal error: Uncaught RedisException: read error on connection to 127.0.0.1:6379 in subscribe.php:6
方式一的实现,是通过临时修改ini的配置值,default_socket_timeout默认为60s,default_socket_timeout是socket流的超时参数,即socket流从建立到传输再到关闭整个过程必须要在这个参数设置的时间以内完成,如果不能完成,那么PHP将自动结束这个socket并返回一个警告。
方式二是通过修改redis的配置项,因此仅对redis连接生效,相对于方式1,不会产生意外的对其他方法的影响。
消息发布者publish.php
<?php
$redis = new Redis();
$redis->connect("127.0.0.1",6379);
$redis->publish('chan','this is a message');
批量订阅
redis的psubscribe支持通过模式匹配的方式实现批量订阅,订阅方式
$redis->psubscribe(['my*'],'psubscribe'); //回调函数写函数名
或者
$redis->psubscribe(['my*'],array(new TestCall(),'psubscribe')); //回调函数为类中的方法,类名写你自己定义的类
subscribe.php
<?php
//ini_set('default_socket_timeout', -1); //不超时
$redis = new Redis();
$redis->connect("127.0.0.1",6379);
$redis->setOption(Redis::OPT_READ_TIMEOUT, -1);
//匹配方式1:发布可用$redis->publish('mymest','this is a message');
//$redis->psubscribe(['my*'],'psubscribe');
//匹配方式2:发布可用$redis->publish('mydest','this is a message');
//$redis->psubscribe(['my?est'],'psubscribe');
//匹配方式3:发布可用$redis->publish('myaest','this is a message');或$redis->publish('myeest','this is a message');
$redis->psubscribe(['my[ae]est'],'psubscribe');
function psubscribe($redis, $pattern, $chan, $msg) {
echo "Pattern: $pattern\n";
echo "Channel: $chan\n";
echo "Payload: $msg\n";
}
模式匹配规则
支持以下几种,以hello举例:
h?llo subscribes to hello, hallo and hxllo
h*llo subscribes to hllo and heeeello
h[ae]llo subscribes to hello and hallo, but not hillo
特殊字符用\转义
pubsub方法介绍
public function pubsub( $keyword, $argument )
pubsub获取pub/sub系统的信息,$keyword可用为"channels", "numsub", 或者"numpat",三种,传入不同的keyword返回的数据不同
* $redis->pubsub('channels'); // All channels 获取所有的频道,返回数组
* $redis->pubsub('channels', '*pattern*'); // Just channels matching your pattern,返回符合匹配模式的频道
* $redis->pubsub('numsub', array('chan1', 'chan2')); // Get subscriber counts for 'chan1' and 'chan2' //返回每个订阅频道的数量,返回数组
* $redis->pubsub('numpat'); // Get the number of pattern subscribers 获取模式匹配方式的订阅
使用过redis做异步队列么,你是怎么用的?有什么缺点?的更多相关文章
- 使用过 Redis 做异步队列么,你是怎么用的?
答:一般使用 list 结构作为队列,rpush 生产消息,lpop 消费消息.当 lpop 没有 消息的时候,要适当 sleep 一会再重试. 如果对方追问可不可以不用 sleep 呢? list ...
- Redis除了做缓存--Redis做消息队列/Redis做分布式锁/Redis做接口限流
1.用Redis实现消息队列 用命令lpush入队,rpop出队 Long size = jedis.lpush("QueueName", message);//返回存放的数据条数 ...
- 程序员过关斩将--redis做消息队列,香吗?
Redis消息队列 在程序员这个圈子打拼了太多年,见过太多的程序员使用redis,其中一部分喜欢把redis做缓存(cache)使用,其中最典型的当属存储用户session,除此之外,把redis作为 ...
- Redis 做消息队列
一般来说,消息队列有两种场景,一种是发布者订阅者模式,一种是生产者消费者模式.利用redis这两种场景的消息队列都能够实现.定义: 生产者消费者模式:生产者生产消息放到队列里,多个消费者同时监听队列, ...
- RabbitMQ跟Redis做消息队列的区别
区别 https://www.zhihu.com/question/20795043 https://blog.csdn.net/dd18709200301/article/details/79077 ...
- Redis做消息队列
1.连接从Redis中获取日志文件并存储到ES中 [root@Logstash ~]# vim /usr/local/logstash/config/redis.conf input { be ...
- 使用Redis做消息队列
基于内存的单线程数据库,使Redis的线程安全性极高.而Redis的双向链表数据类型(List)天生就可作为消息队列存储消息. 在这里就不说消息队列的等等一些优点.但是补充一下Redis的List类型 ...
- Redis做消息队列文章两篇
介绍:http://www.cnblogs.com/lhfcws/p/3732535.html 具体做法:http://shift-alt-ctrl.iteye.com/blog/1867454 另外 ...
- 使用Redis Stream来做消息队列和在Asp.Net Core中的实现
写在前面 我一直以来使用redis的时候,很多低烈度需求(并发要求不是很高)需要用到消息队列的时候,在项目本身已经使用了Redis的情况下都想直接用Redis来做消息队列,而不想引入新的服务,kafk ...
随机推荐
- 11.3 free:查看系统内存信息
free命令用于显示系统内存状态,具体包括系统物理内存.虚拟内存.共享内存和系统缓存等. free命令的参数选项及说明 -b 以Byte为单位显示内存的使用情况 -m 以MB为单位显示内存 ...
- linux 解压总结
tar解压 gz解压 bz2等各种解压文件使用方法 .tar 解包:tar xvf FileName.tar 打包:tar cvf FileName.tar DirName (注:tar是打包,不是压 ...
- 继承(extends), 多态 , 抽象(abstract)接口() 易混难点解析
特性 java是单继承的,一个类直接继承的父类只能有唯一的一个 java中父类可以有多个子类 Object是所有类的父类,一个类没有父类则默认继承Object; 继承中的重写 子类重写方法访问权限不能 ...
- 五:.net core(.NET 6)使用Autofac实现依赖注入
Autofac的简单使用: 由于将来可能引用很多包,为了保持统一队形,我们再新建一个类库项目Wsk.Core.Package,当做包的引用集合: 删掉Class1,把Wsk.Core.Wsk.Core ...
- 如何在Linux中自动删除或清理/tmp文件夹内容?
每个Linux系统都有一个名为的目录/tmp,该目录已挂载了单独的文件系统. 它具有称为tmpfs的特殊文件系统.这是一个虚拟文件系统,操作系统将在系统引导时自动挂载/tmp挂载点. 如果要根据应用程 ...
- 开放式神经网络交换-ONNX(下)
开放式神经网络交换-ONNX(下) 计算节点由名称.它调用的算子operator的名称.命名输入的列表.命名输出的列表和属性列表组成. 输入和输出在位置上与算子operator输入和输出相关联.属性通 ...
- mysql 高级和 索引优化,目的:查的好,查的快,性能好
1-事物隔离级别: 更新丢失, 并发情况下,对同一字段进行更新,就会出现更新丢失,采用乐观锁,比较版本号或时间戳可解决 读未提交 解决了更新丢失但是会引起脏读, 二个session.sessionA中 ...
- android小技巧之点击两次退出活动
通常在主活动中可以设置连击退出程序,下面通过代码来实现这一功能: @Override//按两次back键退出public boolean onKeyDown(int keyCode, KeyEvent ...
- 【NX二次开发】 获取产品曲面上多个点对应的面的垂直矢量!
说明:选择一个产品面,选择面上的点,生成点在此面上的法线反向,生成直线.生成矢量的起点坐标,和矢量方向信息.可用于三坐标测量,如果需要可以自己编个插件用! 效果图: 源码: //----------- ...
- 【C++】Vector判断元素是否存在,去重,求交集,求并集
1 #include <iostream> 2 #include <vector> 3 #include <algorithm> //sort函数.交并补函数 4 ...