php 监听Redis订阅模式的通道是否开启
今天阅读一篇文章,是讲腾讯开源项目爱好正安正超,以文言文的形式书写,给人极度舒适感,感兴趣的朋友可以查阅:CDC达人:安正超
喜欢里面的一句话,送给调侃php的好事者:
超以 PHP 便宜而用之。是时,有好事者,于网络热议何语最佳。初学者常惑矣,问超当何择。超曰:皆器也,何谓最佳?PHP 宜初创而性能劣,C 则性能优而不易达,何为最佳?能成事者最佳。若以利向,均可获利,若以志向,均可精深。
如果以后还是走技术路线,开源和分享即是我的目标。
好了废话不多说,进入正题。
以下是Redis对发布/订阅( pub/sub)模式的介绍:
Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
Redis 客户端可以订阅任意数量的频道。
image
举个非常简单的例子:
subscribe.php
//监听者
$redis = new Redis();
$redis->connect('127.0.0.1',6379);
echo 'reading c1 ...\n';
//设置超时控制
$redis->setOption(Redis::OPT_READ_TIMEOUT,-1);
$redis->subscribe(['c1','c2'],function(Redis $instance, $channel, $message){
echo 'recieve message from '.$channel.':'.$message.'\n';
});
publish.php
<?php
//发布者
$redis = new Redis();
$redis->connect('127.0.0.1',6379);
$res = $redis->publish('c1','发布消息');
echo 'clents'.$res;
php subscribe.php 进程停留在当前命令框
php 执行另外一个publish.php 文件,则可查收到 ‘发布消息’的内容。
这样就实现了php 异步的处理。
什么场景下运用redis的发布、订阅功能?
关于订阅功能,可以在发送短信,邮件,和通知消息给第三方平台
比如传统的下单模式:
用户下单>创建订单->创建订单的详情->订单日志->短信通知(微信通知)
在消息通知中,如果网络延迟,或者第三方网络问题,导致下单超时,或者下单失败,这样用户的体验感就差了。
如果加入发布,订阅功能,即可解决这一不好的用户体验
创建订单时,发布一条消息给redis订阅的一个通道,让其异步执行,如果对发布、订阅有深厚的理解之后,掌握了异常处理,回滚机制之后甚至可以把订单详情,和订单日志加入订阅中。
虽说redis 的订阅功能如此之强大,但是redis 也不是专业做发布订阅的软件,在键值缓存中,redis 占很大的优势,因为redis自带没有像rabibitMQ对发布订阅应用场景这么广。
RabbitMQ和Redis的对比。
RabbitMQ和Redis都可以做队列,但是他们还是有区别的。比如,Redis的消息队列,如果在从队列pop出去的时候,worker处理失败的话,数据不会回到队列中,需要从业务中手动把失败的处理数据push到队列中;而RabbitMQ可以自动处理失败的worker使数据不丢失;RabbitMQ还可以保证数据在传输过程中持久化,在通道和队列中的数据可以设置为持久化。首先Redis严格来说并不是消息队列,它是一个内存数据库,不过因为其某些特性适合用来充当队列,所以也多被用于做简单的mq, Redis之父倒是开发了个真正的消息队列disque,有兴趣可以看看。
相比起Redis,RabbitMQ有更加完善的MQ机制,这里我们仅讨论消息的durable(持久性),后续一系列其他机制有时间再交流。
RabbitMQ有一个消息确认机制来保证消息的不丢失:客户端从队列中取出消息之后,可能需要一段时间才能处理完成,如果在这个过程中,客户端出错了,异常退出了,而数据还没有处理完成,那么非常不幸,这段数据就丢失了,因为RabbitMQ默认会把此消息标记为已完成,然后从队列中移除,消息确认是客户端从RabbitMQ中取出消息,并处理完成之后,会发送一个ack告诉RabbitMQ,消息处理完成,当RabbitMQ收到客户端的获取消息请求之后,或标记为处理中,当再次收到ack之后,才会标记为已完成,然后从队列中删除。当RabbitMQ检测到客户端和自己断开链接之后,还没收到ack,则会重新将消息放回消息队列,交给下一个客户端处理,保证消息不丢失,也就是说,RabbitMQ给了客户端足够长的时间来做数据处理。
如何监听redis订阅管道是否开启
有时候,可能会有很多原因,使订阅的通道停止了,但是程序还是一直publish 到订阅中,如果做了异常处理还好,但是我想即使订阅关掉了,我还执行程序,但是就会卡一点,检测到订阅关闭之后可以发送邮箱给管理人员,进行处理。
之前我查阅文档,好像没有这回事,如果有可以相告,所以我就想到以文件锁的形式来判断,订阅通道是否开启,因为订阅是长时间停驻在进程中。
在subscribe中添加:
加锁
$file = fopen(__DIR__.'lock.txt','w+');
flock($file,LOCK_EX|LOCK_NB);
publish 中检测,是否加锁,加锁程序订阅正在监听,无则反
检测
在publish.php 中添加
$file = fopen(__DIR__.'lock.txt', 'w+');
if (flock($file, LOCK_EX | LOCK_NB)) {
//订阅失败,直接执行程序,影响程序效率,发短信通知管理员开启订阅
} else {
//检测到订阅开启,放心交给订阅通道
}
如果对您有所帮助欢迎,欢迎关注!
网友评论