内容简介:Redis作为一个非关系型数据库,除了在访问速度上拥有显著优势外,其本身支持的多种数据类型也非常有用,能覆盖系统开发中的很多应用场景。下面列举的场景有的是从网上其他人的博客里看到的,有的自己开发时尝试过的一些解决方案后记录下来的,希望能给以后的开发带来启发。在说应用场景前先说一些是否觉得使用Redis的建议作为
Redis作为一个非关系型数据库,除了在访问速度上拥有显著优势外,其本身支持的多种数据类型也非常有用,能覆盖系统开发中的很多应用场景。下面列举的场景有的是从网上其他人的博客里看到的,有的自己开发时尝试过的一些解决方案后记录下来的,希望能给以后的开发带来启发。
在说应用场景前先说一些是否觉得使用 Redis 的建议
使用建议
-
Redis 速度快是建立在内存数据库基础上的,但是一台服务器的内存要比磁盘金贵许多,所以在项目初期不要想什么都往 Redis 里放,这样当数据量上来后很快内存就会不够用,反而得不偿失。合理的利用有限的内存,将读(写)频繁的热数据放在 Redis 中才能更好感受到它带来的性能提升。
-
Redis 虽然提供了
RDB
和AOF
两种持久化方式,但是普遍还是认为 Redis 的持久化并不是很靠谱。非常重要的数据不要依赖Redis来开发,或者最起码不要只在Redis中持久化 -
MySQL经过不断优化性能已经非常好,所以 MySQL 提供的数据结构和访问效率能满足的需求的情况下不要引入Redis,多引入一个组件就多一个可能的故障节点,尤其在保持数据一致性的场景中数据(比如用户余额)应该只放在数据库中,除非你知道怎么解决好系统的分布式事务。
缓存
作为 Key-Value
形态的内存数据库,Redis 最先会被想到的应用场景便是作为数据缓存。而使用 Redis 缓存数据非常简单,只需要通过 string
类型将序列化后的对象存起来即可,不过也有一些需要注意的地方:
-
必须保证不同对象的 key 不会重复,并且使 key 尽量短,一般使用类名(表名)加主键拼接而成。
-
选择一个优秀的序列化方式也很重要,目的是提高序列化的效率和减少内存占用。
-
缓存内容与数据库的一致性,这里一般有两种做法:
-
只在数据库查询后将对象放入缓存,如果对象发生了修改或删除操作,直接清除对应缓存(或设为过期)。
-
在数据库新增和查询后将对象放入缓存,修改后更新缓存,删除后清除对应缓存(或设为过期)。
消息队列
Redis 中 list
的数据结构实现是双向链表,所以可以非常便捷的应用于消息队列(生产者 / 消费者模型)。消息的生产者只需要通过 lpush
将消息放入 list,消费者便可以通过 rpop
取出该消息,并且可以保证消息的有序性。如果需要实现带有优先级的消息队列也可以选择 sortedset
。而 pub/sub
功能也可以用作发布者 / 订阅者模型的消息。无论使用何种方式,由于 Redis 拥有持久化功能,也不需要担心由于服务器故障导致消息丢失的情况。
时间轴(Timeline)
list
作为双向链表,不光可以作为队列使用。如果将它用作栈便可以成为一个公用的时间轴。当用户发完微博后,都通过 lpush
将它存放在一个 key 为 LATEST_WEIBO
的 list
中,之后便可以通过 lrange
取出当前最新的微博。
循环链表
list
还可以作为循环链表使用 RPOPLPUSH source destination
命令 RPOPLPUSH
在一个原子时间内,执行以下两个动作:
-
将列表
source
中的最后一个元素(尾元素)弹出,并返回给客户端。 -
将
source
弹出的元素插入到列表destination
,作为destination
列表的的头元素。
如果 source
和 destination
相同,则列表中的表尾元素被移动到表头,并返回该元素,可以把这种特殊情况视作列表的旋转(rotation)操作。
比如有个进程来完成派单任务,需要将用户发送过来的申请依次派发给工作人员,那么就可以把工作人员的身份标示维护在循环列表中,从列表尾部读取每次读取身份标示后相应的标示都会被放到列表头如此循环往复。
排行榜
使用 sortedset
和一个计算热度的算法便可以轻松打造一个热度排行榜, zrevrangebyscore
可以得到以分数倒序排列的序列, zrank
可以得到一个成员在该排行榜的位置(是分数正序排列时的位置,如果要获取倒序排列时的位置需要用 zcard
- zrank
)。
计数器
计数功能应该是最适合 Redis 的使用场景之一了,因为它高频率读写的特征可以完全发挥 Redis 作为内存数据库的高效。在 Redis 的数据结构中, string
、 hash
和 sortedset
都提供了 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 自增。 -
如果应用有一个发帖排行榜的功能,便选择
sortedset
吧,将集合的 key 设为POST_RANK
。当用户发帖后,使用zincrby
将该用户 id 的 score 增长 1。sortedset
会重新进行排序,用户所在排行榜的位置也就会得到实时的更新。
好友关系
这个场景最开始是是一篇介绍微博 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 不存在才会进行操作由于这个操作是原子性的,可以简单地以此实现一个分布式的锁,例如:
如果这个操作返回 false
,说明 key 的添加不成功,也就是当前有人在占用这把锁。而如果返回 true
,则说明得了锁,便可以继续进行操作,并且在操作后通过 del
命令释放掉锁。并且即使程序因为某些原因并没有释放锁,由于设置了过期时间,该锁也会在 1 秒后自动释放,不会影响到其他程序的运行。
倒排索引
倒排索引是构造搜索功能的最常见方式,在 Redis 中也可以通过 set
进行建立倒排索引,这里以简单的拼音 + 前缀搜索城市功能举例:
假设一个城市 北京
,通过拼音词库将 北京
转为 beijing
,再通过前缀分词将这两个词分为若干个前缀索引,有: 北
、 北京
、 b
、 be
… beijin
和 beijing
。将这些索引分别作为 set
的 key(例如: index:北
)并存储 北京
的 id,倒排索引便建立好了。接下来只需要在搜索时通过关键词取出对应的 set
并得到其中的 id 即可。
个人能力局限目前只知道这些数据类型的应用场景,如果各位有其他场景的应用经验欢迎交流补充,另外面试时被问到为何使用Redis不要简单的说因为快, 如果在系统中只使用了缓存这一个应用场景那么最起码可以提供一些MySQL的QPS和Redis的QPS数据或者程序在Redis使用前后的平均响应时长来印证你的观点。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Android编程权威指南(第2版)
Bill Phillips、Chris Stewart、Brian Hardy、Kristin Marsicano / 王明发 / 人民邮电出版社 / 2016-5 / 109.00 元
Big Nerd Ranch是美国一家专业的移动开发技术培训机构。本书主要以其Android训练营教学课程为基础,融合了几位作者多年的心得体会,是一本完全面向实战的Android编程权威指南。全书共34章,详细介绍了8个Android 应用。通过这些精心设计的应用,读者可掌握很多重要的理论知识和开发技巧,获得最前沿的开发经验。 如果你熟悉Java语言,或者了解面向对象编程,那就立刻开始And......一起来看看 《Android编程权威指南(第2版)》 这本书的介绍吧!