Redis的应用场景汇总

Redis应用场景

Redis做为一个非关系型数据库,除了在访问速度上拥有显著优点外,其自己支持的多种数据类型也很是有用,能覆盖系统开发中的不少应用场景。下面列举的场景有的是从网上其余人的博客里看到的,有的本身开发时尝试过的一些解决方案后记录下来的,但愿能给之后的开发带来启发。面试

在说应用场景前先说一些是否以为使用Redis的建议算法

使用建议

  • Redis 速度快是创建在内存数据库基础上的,可是一台服务器的内存要比磁盘金贵许多,因此在项目初期不要想什么都往 Redis 里放,这样当数据量上来后很快内存就会不够用,反而得不偿失。合理的利用有限的内存,将读(写)频繁的热数据放在 Redis 中才能更好感觉到它带来的性能提高。
  • Redis 虽然提供了RDBAOF两种持久化方式,可是广泛仍是认为 Redis 的持久化并非很靠谱。很是重要的数据不要依赖Redis来开发,或者最起码不要只在Redis中持久化
  • MySQL通过不断优化性能已经很是好,因此MySQL提供的数据结构和访问效率能知足的需求的状况下不要引入Redis,多引入一个组件就多一个可能的故障节点,尤为在保持数据一致性的场景中数据(好比用户余额)应该只放在数据库中,除非你知道怎么解决考系统的分布式事务。

缓存

做为Key-Value形态的内存数据库,Redis 最早会被想到的应用场景即是做为数据缓存。而使用 Redis 缓存数据很是简单,只须要经过string类型将序列化后的对象存起来便可,不过也有一些须要注意的地方:数据库

  • 必须保证不一样对象的 key 不会重复,而且使 key 尽可能短,通常使用类名(表名)加主键拼接而成。
  • 选择一个优秀的序列化方式也很重要,目的是提升序列化的效率和减小内存占用。
  • 缓存内容与数据库的一致性,这里通常有两种作法:缓存

    1. 只在数据库查询后将对象放入缓存,若是对象发生了修改或删除操做,直接清除对应缓存(或设为过时)。
    2. 在数据库新增和查询后将对象放入缓存,修改后更新缓存,删除后清除对应缓存(或设为过时)。

消息队列

Redis 中list的数据结构实现是双向链表,因此能够很是便捷的应用于消息队列(生产者 / 消费者模型)。消息的生产者只须要经过lpush将消息放入 list,消费者即可以经过rpop取出该消息,而且能够保证消息的有序性。若是须要实现带有优先级的消息队列也能够选择sorted set。而pub/sub功能也能够用做发布者 / 订阅者模型的消息。不管使用何种方式,因为 Redis 拥有持久化功能,也不须要担忧因为服务器故障致使消息丢失的状况。服务器

时间轴(Timeline)

list做为双向链表,不光能够做为队列使用。若是将它用做栈即可以成为一个公用的时间轴。当用户发完微博后,都经过lpush将它存放在一个 key 为LATEST_WEIBOlist中,以后即可以经过lrange取出当前最新的微博。数据结构

循环链表

list 还能够做为循环链表使用 RPOPLPUSH source destination分布式

命令 RPOPLPUSH 在一个原子时间内,执行如下两个动做:性能

  • 将列表 source 中的最后一个元素(尾元素)弹出,并返回给客户端。
  • source 弹出的元素插入到列表 destination ,做为 destination 列表的的头元素。

若是 sourcedestination 相同,则列表中的表尾元素被移动到表头,并返回该元素,能够把这种特殊状况视做列表的旋转(rotation)操做。优化

好比有个进程来完成派单任务,须要将用户发送过来的申请依次派发给工做人员,那么就能够把工做人员的身份标示维护在循环列表中,从列表尾部读取每次读取身份标示后相应的标示都会被放到列表头如此循环往复。设计

排行榜

使用sorted set和一个计算热度的算法即可以轻松打造一个热度排行榜,zrevrangebyscore能够获得以分数倒序排列的序列,zrank能够获得一个成员在该排行榜的位置(是分数正序排列时的位置,若是要获取倒序排列时的位置须要用zcard-zrank)。

计数器

计数功能应该是最适合 Redis 的使用场景之一了,由于它高频率读写的特征能够彻底发挥 Redis 做为内存数据库的高效。在 Redis 的数据结构中,stringhashsorted set都提供了incr方法用于原子性的自增操做,下面举例说明一下它们各自的使用场景:

  • 若是应用须要显示天天的注册用户数,即可以使用string做为计数器,设定一个名为REGISTERED_COUNT_TODAY的 key,并在初始化时给它设置一个到凌晨 0 点的过时时间,每当用户注册成功后便使用incr命令使该 key 增加 1,同时当天天凌晨 0 点后,这个计数器都会由于 key 过时使值清零。
  • 每条微博都有点赞数、评论数、转发数和浏览数四条属性,这时用hash进行计数会更好,将该计数器的 key 设为weibo:weibo_idhash的 field 为like_numbercomment_numberforward_numberview_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:followA:follower的交集获得与 A 互相关注的用户。当 A 进入另外一个用户 B 的主页后,A:followB:follow的交集即是 A 和 B 的共同专一,A:followB:follower的交集即是 A 关注的人也关注了 B。

分布式锁

在 Redis 2.6.12 版本开始,stringset命令增长了三个参数:

  • EX:设置键的过时时间(单位为秒)
  • PX:设置键的过时时间(单位为毫秒)
  • NX | XX:当设置为NX时,仅当 key 存在时才进行操做,设置为XX时,仅当 key 不存在才会进行操做

    因为这个操做是原子性的,能够简单地以此实现一个分布式的锁,例如:

set key "lock" EX 1 XX

若是这个操做返回false,说明 key 的添加不成功,也就是当前有人在占用这把锁。而若是返回true,则说明得了锁,即可以继续进行操做,而且在操做后经过del命令释放掉锁。而且即便程序由于某些缘由并无释放锁,因为设置了过时时间,该锁也会在 1 秒后自动释放,不会影响到其余程序的运行。

倒排索引

倒排索引是构造搜索功能的最多见方式,在 Redis 中也能够经过set进行创建倒排索引,这里以简单的拼音 + 前缀搜索城市功能举例:

假设一个城市北京,经过拼音词库将北京转为beijing,再经过前缀分词将这两个词分为若干个前缀索引,有:北京bbebeijinbeijing。将这些索引分别做为set的 key(例如:index:北)并存储北京的 id,倒排索引便创建好了。接下来只须要在搜索时经过关键词取出对应的set并获得其中的 id 便可。

我的能力局限目前只知道这些数据类型的应用场景,若是各位有其余场景的应用经验欢迎交流补充,另外面试时被问到为什么使用Redis不要简单的说由于快, 若是在系统中只使用了缓存这一个应用场景那么最起码能够提供一些MySQL的QPS和Redis的QPS数据或者程序在Redis使用先后的平均响应时长来印证你的观点。

相关文章
相关标签/搜索