Redis应用场景
2016-02-16 00:00
525 查看
Redis应用场景
ScienJus• 2015年8月16日
•
0 Comments
自从第一次在项目中使用Redis后便深深地喜欢上了这个方便快速的NoSQL数据库,所以在很多需求中都会下意识的去寻找基于Redis的解决方案,在尝试后将这些使用场景记录下来希望能给大家带来帮助。
缓存
作为Key-Value形态的内存数据库,Redis最先会被想到的应用场景便是作为数据缓存。而使用Redis缓存数据非常简单,只需要通过string类型将序列化后的对象存起来即可,不过也有一些需要注意的地方:必须保证不同对象的key不会重复,并且使key尽量短,一般使用类名(表名)加主键拼接而成。
选择一个优秀的序列化方式也很重要,目的是提高序列化的效率和减少内存占用。
缓存内容与数据库的一致性,这里一般有两种做法:
只在数据库查询后将对象放入缓存,如果对象发生了修改或删除操作,直接清除对应缓存(或设为过期)。
在数据库新增和查询后将对象放入缓存,修改后更新缓存,删除后清除对应缓存(或设为过期)。
消息队列
Redis中list的数据结构实现是双向链表,所以可以非常便捷的应用于消息队列(生产者/消费者模型)。消息的生产者只需要通过lpush将消息放入list,消费者便可以通过rpop取出该消息,并且可以保证消息的有序性。如果需要实现带有优先级的消息队列也可以选择sorted set。而pub/sub功能也可以用作发布者/订阅者模型的消息。无论使用何种方式,由于Redis拥有持久化功能,也不需要担心由于服务器故障导致消息丢失的情况。时间轴(Timeline)
list作为双向链表,不光可以作为队列使用。如果将它用作栈便可以成为一个公用的时间轴。当用户发完微博后,都通过lpush将它存放在一个key为LATEST_WEIBO的list中,之后便可以通过lrange取出当前最新的微博。排行榜
使用sorted set和一个计算热度的算法便可以轻松打造一个热度排行榜,zrevrangebyscore可以得到以分数倒序排列的序列,zrank可以得到一个成员在该排行榜的位置(是分数正序排列时的位置,如果要获取倒序排列时的位置需要用zcard–zrank)。计数器
计数功能应该是最适合Redis的使用场景之一了,因为它高频率读写的特征可以完全发挥Redis作为内存数据库的高效。在Redis的数据结构中,string、hash和sorted set都提供了incr方法用于原子性的自增操作,下面举例说明一下它们各自的使用场景:如果应用需要显示每天的注册用户数,便可以使用string作为计数器,设定一个名为REGISTERED_COUNT_TODAY的key,并在初始化时给它设置一个到凌晨0点的过期时间,每当用户注册成功后便使用incr命令使该key增长1,同时当每天凌晨0点后,这个计数器都会因为key过期使值清零。
每条微博都有点赞数、评论数、转发数和浏览数四条属性,这时用hash进行计数会更好,将该计数器的key设为weibo:weibo_id,hash的field为like_number、comment_number、forward_number和view_number,在对应操作后通过hincrby使hash中的field自增。
如果应用有一个发帖排行榜的功能,便选择sorted set吧,将集合的key设为POST_RANK。当用户发帖后,使用zincrby将该用户id的score增长1。sorted set会重新进行排序,用户所在排行榜的位置也就会得到实时的更新。
好友关系
这个场景最开始是是一篇介绍微博Redis应用的PPT中看到的,其中提到微博的Redis主要是用在在计数和好友关系两方面上,当时对好友关系方面的用法不太了解,后来看到《Redis设计与实现》中介绍到作者最开始去使用Redis便是希望能通过set解决传统数据库无法快速计算集合中交集这个功能。后来联想到微博当前的业务场景,确实能够以这种方式实现,所以姑且猜测一下:对于一个用户A,将它的关注和粉丝的用户id都存放在两个set中:
A:follow:存放A所有关注的用户id
A:follower:存放A所有粉丝的用户id
那么通过sinter命令便可以根据A:follow和A:follower的交集得到与A互相关注的用户。当A进入另一个用户B的主页后,A:follow和B:follow的交集便是A和B的共同专注,A:follow和B:follower的交集便是A关注的人也关注了B。
分布式锁
在Redis 2.6.12版本开始,string的set命令增加了三个参数:EX:设置键的过期时间(单位为秒)
PX:设置键的过期时间(单位为毫秒)
NX | XX:当设置为NX时,仅当key存在时才进行操作,设置为XX时,仅当key不存在才会进行操作
由于这个操作是原子性的,可以简单地以此实现一个分布式的锁,例如:
set key "lock" EX 1 XX
如果这个操作返回false,说明key的添加不成功,也就是当前有人在占用这把锁。而如果返回true,则说明得了锁,便可以继续进行操作,并且在操作后通过del命令释放掉锁。并且即使程序因为某些原因并没有释放锁,由于设置了过期时间,该锁也会在1秒后自动释放,不会影响到其他程序的运行。
倒排索引
倒排索引是构造搜索功能的最常见方式,在Redis中也可以通过set进行建立倒排索引,这里以简单的拼音+前缀搜索城市功能举例:假设一个城市北京,通过拼音词库将北京转为beijing,再通过前缀分词将这两个词分为若干个前缀索引,有:北、北京、b、be…beijin和beijing。将这些索引分别作为set的key(例如:index:北)并存储北京的id,倒排索引便建立好了。接下来只需要在搜索时通过关键词取出对应的set并得到其中的id即可。
一些建议
Redis速度快是建立在内存数据库基础上的,但是一台服务器的内存要比磁盘金贵许多,所以在项目初期不要想什么都往Redis里放,这样当数据量上来后很快内存就会不够用,反而得不偿失。合理的利用有限的内存,将读(写)频繁的热数据放在Redis中才能更好感受到它带来的性能提升。Redis虽然提供了RDB和AOF两种持久化方式,但是普遍还是认为Redis的持久化并不是很靠谱。这也是我一直不敢尝试彻底的用Redis去实现第五点(好友关系)的原因。
虽然Redis在3.0之后才推出官方的集群方案,但是也有很多不错的开源方案,比如Codis。
相关文章推荐
- mongo实现消息队列
- SQL2005 性能监视器计数器错误解决方法
- SQL Server中的Forwarded Record计数器影响IO性能的解决方法
- 浅析SQL Server中的执行计划缓存(上)
- Enterprise Library for .NET Framework 2.0缓存使用实例
- PowerShell中编程清空IE缓存方法
- PowerShell中使用.NET将程序集加入全局程序集缓存
- C#中缓存的基本用法总结
- MySQL中实现高性能高并发计数器方案(例如文章点击数)
- 进程间通信之深入消息队列的详解
- 编程趣事:当下流行编程语言的”讨厌”程度排行榜
- wap开发中如何有效的利用缓存减少消息的传送量
- PHP基于文件存储实现缓存的方法
- smarty缓存用法分析
- 引用全局程序集缓存内的程序集的方法
- asp Response.flush 实时显示进度
- C#实现清除IE浏览器缓存的方法
- ASP.NET缓存管理的几种方法
- PHP文件缓存类实现代码
- 清除aspx页面缓存的程序实现方法