设为首页 收藏本站
查看: 839|回复: 0

[经验分享] Redis消息通知系统的实现

[复制链接]

尚未签到

发表于 2015-7-21 13:21:15 | 显示全部楼层 |阅读模式
Redis消息通知系统的实现


Posted on 2012-02-29 by 老王 http://huoding.com/2012/02/29/146

  最近忙着用Redis实现一个消息通知系统,今天大概总结了一下技术细节,其中演示代码如果没有特殊说明,使用的都是PhpRedis扩展来实现的。
  

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

队列
  当大量用户同时登录的时候,如果全部都即时处理,那么很容易就崩溃了,此时可以使用一个队列来保存待处理的登录用户,如此一来顶多是反应慢点,但不会崩溃。
  Redis的LIST数据类型可以很自然的创建一个队列,代码如下:


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


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


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

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


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


  说明:所谓PIPELINE,就是省略了无谓的折返跑,把命令打包给服务端统一处理。
  前后两段代码在我的测试里,使用PIPELINE的速度大概是不使用PIPELINE的十倍。

查询
  我们用Redis命令行来演示一下用户是如何查询消息的。
  先插入三条消息,其分别是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
  再把这三条消息发送给某个用户,其是123:

redis> SADD usr:123:msg 1
redis> SADD usr:123:msg 2
redis> SADD usr:123:msg 3
  此时如果简单查询用户有哪些消息的话,无疑只能查到一些:

redis> SMEMBERS usr:123:msg
1) "1"
2) "2"
3) "3"
  如果还需要用程序根据再来一次查询无疑有点低效,好在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代理,效率没得说。
  …
  最近Tumblr发表了一篇类似的文章:Staircar: Redis-powered notifications,介绍了他们使用Redis实现消息通知系统的一些情况,有兴趣的不妨一起看看。

==========================================

Web应用中的轻量级消息队列



原文地址:http://hi.baidu.com/thinkinginlamp/blog/item/27a18202578f3d054bfb511f.html

Web应用中为什么会需要消息队列?主要原因是由于在高并发环境下,由于来不及同步处理,请求往往会发生堵塞,比如说,大量的insert,update之类的请求同时到达mysql,直接导致无数的行锁表锁,甚至最后请求会堆积过多,从而触发too many connections错误。通过使用消息队列,我们可以异步处理请求,从而缓解系统的压力。在Web2.0的时代,高并发的情况越来越常见,从而使消息队列有成为居家必备的趋势,相应的也涌现出了很多实现方案,像Twitter以前就使用RabbitMQ实现消息队列服务,现在又转而使用Kestrel来实现消息队列服务,此外还有很多其他的选择,比如说:ActiveMQ,ZeroMQ等。
上述消息队列的软件中,大多为了实现AMQP,STOMP,XMPP之类的协议,变得极其重量级,但在很多Web应用中的实际情况是:我们只是想找到一个缓解高并发请求的解决方案,不需要杂七杂八的功能,一个轻量级的消息队列实现方式才是我们真正需要的。
第一感觉是能不能使用memcached来实现消息队列?稍加考虑后就会发现它不合适,因为memcached仅仅支持键值方式的操作,没有排序之类的功能,所以如果要用它来实现消息队列,则必须自己通过某个键来保存数组形式的队列,不过这样的话,在操作队列的时候很容易丢失数据,比如说我们要添加一个消息,则需先取出现有队列,然后把消息保存到队列尾部,最后保存队列,单纯使用memcached的话,由于我们无法保证整个过程的原子性,所以当处理若干个并发请求时,各个请求间可能会互相覆盖,丢失数据就在所难免(新的memcached扩展一定程度上能缓解这个问题)。另外,memcached只是内存键值缓存而已,一旦宕机,数据就消失了。
memcacheq的出现解决了上面的问题,它在memcached的基础上实现了消息队列,以php客户端为例:
消息从尾部入栈:memcache_set
消息从头部出栈:memcache_get
memcacheq依附于memcached之上,所以你可以通过现有的memcached工具来操作它,这无疑是它的一大优势,但它也有一个很大的缺点,那就是memcacheq本身的开发维护似乎并不活跃,如果遇到问题的话,你很可能需要自己动手解决。
目前看来,我更推荐下面这种解决方案,那就是redis,如果不了解,可以参考我以前的文章,表面上看,redis和memcached差不多,也是键值操作,但是redis本身实现了list,相关操作也可以保证是原子的,所以可以很自然的通过list来实现消息队列:
消息从尾部进队列:RPUSH
消息从头部出队列:LPOP
redis本身虽然是一个新项目,但很有朝气,开发维护也很活跃,如果你的下一个Web应用里需要使用轻量级的消息队列,不妨使用它,顺便说一句,redis里还有set结构,可以用来实现一个高效能的tag系统。
此外,还有不少其他的选择可供尝试,比如说MySQL第三方的Q4M引擎,通过扩展SQL语法来操作消息队列,也是一个不错的选择。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-89113-1-1.html 上篇帖子: redis--使用redis-rdb-tools分析redis的内存使用情况 下篇帖子: java操作redis
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表