内存

比如要推送一条全局消息,如果真的给所有用户都推送一遍的话,那么会占用很大的内存,实际上不管粘性有多高的产品,活跃用户同全部用户比起来,都会 小很多,所以如果只处理登录用户的话,那么至少在内存消耗上是相当划算的,至于未登录用户,可以推迟到用户下次登录时再处理,如果用户一直不登录,就一了 百了了。

队列

当大量用户同时登录的时候,如果全部都即时处理,那么很容易就崩溃了,此时可以使用一个队列来保存待处理的登录用户,如此一来顶多是反应慢点,但不会崩溃。

Redis的LIST数据类型可以很自然的创建一个队列,代码如下:

<?php$redis = new Redis;
$redis->connect('/tmp/redis.sock');$redis->lPush('usr', <USRID>);while ($usr = $redis->rPop('usr')) {var_dump($usr);
}?>

出于类似的原因,我们还需要一个队列来保存待处理的消息。当然也可以使用LIST来实现,但LIST只能按照插入的先后顺序实现类似FIFO或LIFO形式的队列,然而消息实际上是有优先级的:比如说个人消息优先级高,全局消息优先级低。此时可以使用ZSET来实现,它里面分数的概念很自然的实现了优先级。

不过ZSET没有原生的POP操作,所以我们需要模拟实现,代码如下:

<?phpclass RedisClient extends Redis
{const POSITION_FIRST = 0;const POSITION_LAST = -1;public function zPop($zset){return $this->zsetPop($zset, self::POSITION_FIRST);}public function zRevPop($zset){return $this->zsetPop($zset, self::POSITION_LAST);}private function zsetPop($zset, $position){$this->watch($zset);$element = $this->zRange($zset, $position, $position);if (!isset($element[0])) {return false;}if ($this->multi()->zRem($zset, $element[0])->exec()) {return $element[0];}return $this->zsetPop($zset, $position);}
}?>

模拟实现了POP操作后,我们就可以使用ZSET实现队列了,代码如下:

<?php$redis = new RedisClient;
$redis->connect('/tmp/redis.sock');$redis->zAdd('msg', <PRIORITY>, <MSGID>);while ($msg = $redis->zRevPop('msg')) {var_dump($msg);
}?>

推拉

以前微博架构中推拉选择的问题已经被大家讨论过很多次了。实际上消息通知系统和微博差不多,也存在推拉选择的问题,同样答案也是类似的,那就是应该 推拉结合。具体点说:在登陆用户获取消息的时候,就是一个拉消息的过程;在把消息发送给登陆用户的时候,就是一个推消息的过程。

速度

假设要推送一百万条消息的话,那么最直白的实现就是不断的插入,代码如下:

<?phpfor ($msgid = 1; $msgid <= 1000000; $msgid++) {$redis->sAdd('usr:<USRID>:msg', $msgid);
}?>

Redis的速度是很快的,但是借助PIPELINE,会更快,代码如下:

<?phpfor ($i = 1; $i <= 100; $i++) {$redis->multi(Redis::PIPELINE);for ($j = 1; $j <= 10000; $j++) {$msgid = ($i - 1) * 10000 + $j;$redis->sAdd('usr:<USRID>:msg', $msgid);}$redis->exec();
}?>

说明:所谓PIPELINE,就是省略了无谓的折返跑,把命令打包给服务端统一处理。

前后两段代码在我的测试里,使用PIPELINE的速度大概是不使用PIPELINE的十倍。

查询

我们用Redis命令行来演示一下用户是如何查询消息的。

先插入三条消息,其<MSGID>分别是1,2,3:

redis> HMSET msg:1 title title1 content content1
redis> HMSET msg:2 title title2 content content2
redis> HMSET msg:3 title title3 content content3

再把这三条消息发送给某个用户,其<USRID>是123:

redis> SADD usr:123:msg 1
redis> SADD usr:123:msg 2
redis> SADD usr:123:msg 3

此时如果简单查询用户有哪些消息的话,无疑只能查到一些<MSGID>:

redis> SMEMBERS usr:123:msg
1) "1"
2) "2"
3) "3"

如果还需要用程序根据<MSGID>再来一次查询无疑有点低效,好在Redis内置的SORT命令可以达到事半功倍的效果,实际上它类似于SQL中的JOIN:

redis> SORT usr:123:msg GET msg:*->title
1) "title1"
2) "title2"
3) "title3"
redis> SORT usr:123:msg GET msg:*->content
1) "content1"
2) "content2"
3) "content3"

SORT的缺点是它只能GET出字符串类型的数据,如果你想要多个数据,就要多次GET:

redis> SORT usr:123:msg GET msg:*->title GET msg:*->content
1) "title1"
2) "content1"
3) "title2"
4) "content2"
5) "title3"
6) "content3"

很多情况下这显得不够灵活,好在我们可以采用其他一些方法平衡一下利弊,比如说新加一个字段,冗余保存完整消息的序列化,接着只GET这个字段就OK了。

实际暴露查询接口的时候,不会使用PHP等程序来封装,因为那会成倍降低RPS,推荐使用Webdis,它是一个Redis的Web代理,效率没得说。

redis的消息队列相关推荐

  1. Redis做消息队列,香吗?

    来自:架构师修行之路 菜菜哥,我刚做完了一个订单系统,感觉很简单呀 说说看,大量的订单状态怎么处理的? 我设计的时候可是考虑了这一点,所以用了异步处理,采用了MQ 那用的什么MQ呢,透露一下呗 我用的 ...

  2. 【springboot】【redis】springboot+redis实现发布订阅功能,实现redis的消息队列的功能...

    springboot+redis实现发布订阅功能,实现redis的消息队列的功能 参考:https://www.cnblogs.com/cx987514451/p/9529611.html 思考一个问 ...

  3. PHP + Redis 实现消息队列

    Redis做消息队列的好处在于它的轻量级,高并发,延迟敏感,应用场景有 即时数据分析.秒杀计数器.缓存等 Redis做消息队列待解决的问题: 1.消息的可靠性: 没有相应的机制保证消息的消费,当消费者 ...

  4. ​redis实现消息队列

    redis是一个开源的key-value存储系统.与Memcached类似,Redis将大部分数据存储在内存中,支持的数据类型包括:字符串.哈希表.链表.集合.有序集合以及基于这些数据类型的相关操作. ...

  5. 用redis实现消息队列(实时消费+ack机制)【转】

    用redis实现消息队列(实时消费+ack机制) java queue 消息队列 redis 消息队列 首先做简单的引入. MQ主要是用来: 解耦应用. 异步化消息 流量削峰填谷 目前使用的较多的有A ...

  6. 使用Redis 实现消息队列

    一 .为什么要用Redis实现轻量级MQ? MQ的主要作用: 应用解耦 异步化消息 流量削峰填谷 目前使用比较多的是ActiveMQ . RabbitMQ . ZeroMQ . Kafka . Met ...

  7. 【BCVP】实现基于 Redis 的消息队列

    聆听自己的声音 如果自己学不动了,或者感觉没有动力的时候,看看书,听听音乐,跑跑步,休息两天,重新出发,偷懒虽好,可不要贪杯. 话说上回书我们说到了,Redis的使用修改<[BCVP更新]Sta ...

  8. 程序员过关斩将--redis做消息队列,香吗?

    菜菜哥,我刚做完了一个订单系统,感觉很简单呀 说说看,大量的订单状态怎么处理的? 我设计的时候可是考虑了这一点,所以用了异步处理,采用了MQ 那用的什么MQ呢,透露一下呗 我用的redis做的MQ,很 ...

  9. c#进阶(4)—— Redis 用于消息队列的存储

    1.参考的博文 a : http://www.cnblogs.com/lori/archive/2012/04/12/2443708.html -- 主要的实现思路 b:  http://www.cn ...

  10. Redis异步消息队列

    一.异步消息队列介绍 个人认为消息队列的主要特点是异步处理,主要目的是减少请求响应时间和解耦.所以主要的使用场景就是将比较耗时而且不需要即时(同步)返回结果的操作作为消息放入消息队列.同时由于使用了消 ...

最新文章

  1. mysql字段名与关键字冲突(near to:syntax error)
  2. 使用WinSCP在WIndows与树莓派之间传递文件
  3. kafka与zookeeper版本对应关系表
  4. 【Tools】MarkDown教程(六)-Markdown Reference
  5. qt显示echart_Qt配置,载入html,Echart, 交互
  6. 计算机视觉论文-2021-06-28
  7. 全员5G!iPhone 12系列终于来了:没有阉割,售价依旧5499元起!
  8. JavaScript高级程序设计(2)在HTML中使用JavaScript
  9. 微软十大软件开发英雄评选
  10. Leetcode每日一题:122.best-time-to-buy-and-sell-stock-ii(买股票的最佳时机Ⅱ)
  11. C语言-指针的比较/指针加减
  12. 160505、oracle 修改字符集 修改为ZHS16GBK
  13. OSPF P2MP 扩展知识
  14. word2019每页设置不同页眉
  15. IP协议的详细知识总结
  16. SCI论文撰写——Conclusion
  17. 别再说不会分析多选题了!这6种方法解决你的烦恼!
  18. html标签属性可以省略,html部分---通用标签与属性;
  19. Dynamics 365 for Phone 使用Xrm.Device.captureImage获取照片
  20. Word 无法打开该文件,因为文件格式与文件扩展名不匹配。

热门文章

  1. 高标准生产车间空压站油水环保处理设备 ows.01275.00.00
  2. 使用中科大源安装python库
  3. 进程超时,设置进程超时时间
  4. 替换空格(Java)
  5. 美股创历史新高,巴菲特却继续减持,他葫芦里卖的是什么药?
  6. 使你成为高手 HTC手机指令大全全覆盖
  7. VGGNet网络模型
  8. Mac照片后期处理软件软件:Capture One 21 Pro
  9. 8.final、权限、内部类、引用类型
  10. 短视频为什么要坚持原创?如何创作原创短视频内容