Redis 应用场景
2016-05-29 00:00
344 查看
摘要: Redis的一些应用场景
必须保证不同对象的key不会重复,并且使key尽量短,使用使用类名(表名)加主键拼接而成。
选择一个优秀的序列化方式也很重要,目的是提高序列化的效率和减少内存占用。
缓存内容与数据库的一致性,这里一般有两种做法:
只在数据库查询后将对象放入缓存,如果对象发生了修改或删除操作,直接清除对应缓存(或设为过期)
在数据库新增和查询后将对象放入缓存,修改后更新缓存,删除后清除对应缓存(或设为过期)。
如果应用需要显示每天的注册用户数,便可以使用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 [b]吧,将集合的key设为POST_RANK[/b]。当用户发帖后,使用zincrby将该用户id的score增长1. **sorted set **会重新进行排序,用户所在排行榜的位置也就会得到实时的更新。
scienjus博主猜测说:
对于一个用户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。
EX : 设置键的过期时间(单位为秒)
PX : 设置键的过期时间(单位为毫秒)
NX | XX :当设置为 NX 时,仅当key存在时才进行操作,设置为XX时,仅当key不存在才会进行操作。
由于这个操作是原子性的,可以简单地以此实现一个分布式锁,例如:
**set key "lock" EX 1 XX
如果这个操作返回false, 说明key的添加不成功,说明key的添加不成功,也就是当前有人在占用这把锁。而如果返回true,则说明得了锁,便可以继续操作 ,并且在操作后通过del命令释放掉锁。并且即使程序因为某些原因并没有释放锁,由于设置了过期时间,该锁也会在1秒后自动释放,不会影响到其他程序的运行。
假设一个城市 北京,通过拼音词库将北京转为beijing,再通过前缀分词将这两个词分为若干个前缀索引,有:北、北京、b、be…beijin和beijing。将这些索引分别作为set的key(例如:index:北)并存储北京的id,倒排索引便建立好了。接下来只需要在搜索时通过关键词取出对应的set并得到其中的id即可
Redis虽然提供了RDB和AOF两种持久化方式,但是普遍还是认为Redis的持久化并不是很靠谱。这也是我一直不敢尝试彻底的用Redis去实现第五点(好友关系)的原因。
虽然Redis在3.0之后才推出官方的集群方案,但是也有很多不错的开源方案,比如Codis。
转自http://www.scienjus.com/redis-use-case/
Redis应用场景
缓存
作为Key-Value形态的内存数据库,Redis最先会被想到的应用场景便是作为数据缓存。而使用Redis缓存数据非常简单,只需要通过String类型将序列化后的对象存起来即可,不过也有一些注意的地方。必须保证不同对象的key不会重复,并且使key尽量短,使用使用类名(表名)加主键拼接而成。
选择一个优秀的序列化方式也很重要,目的是提高序列化的效率和减少内存占用。
缓存内容与数据库的一致性,这里一般有两种做法:
只在数据库查询后将对象放入缓存,如果对象发生了修改或删除操作,直接清除对应缓存(或设为过期)
在数据库新增和查询后将对象放入缓存,修改后更新缓存,删除后清除对应缓存(或设为过期)。
127.0.0.1:6379> set CACHE_KEY cacheData #新增 OK 127.0.0.1:6379> set CACHE_KEY updataCacheData #修改 OK 127.0.0.1:6379> get CACHE_KEY "updataCacheData" 127.0.0.1:6379> expire CACHE_KEY 1 #设置1秒后过期 (integer) 1 127.0.0.1:6379> ttl CACHE_KEY #查看还有多少时间过期 -1永不过期,-2过期 (integer) -2 127.0.0.1:6379> del CACHE_KEY #删除 (integer) 0 127.0.0.1:6379> exists CACHE_KEY #是否存在 (integer) 0 127.0.0.1:6379>
消息队列
Redis中的list的数据结构实现是双向链表,所以可以非常便捷的应用于消息队列(生产者/消费者模型)。消息的生产者只需要通过lpush将消息放入list,消费者可以通过rpop取出该消息,并且可以保证消息的有序性。如果需要实现带有优先级的消息队列也可以选择sorted set。 而pub/sub功能也可以用作发布者/订阅者模型的消息。无论使用何种方式,由于Redis用于持久化功能,也不需要担心由于服务器故障导致消息丢失的情况。127.0.0.1:6379> lpush QUEUE_KEY queueV01 queueV02 queueV03 #生产者(放入) (integer) 3 127.0.0.1:6379> rpop QUEUE_KEY #消费者 (取出) "queueV01" 127.0.0.1:6379> rpop QUEUE_KEY "queueV02" 127.0.0.1:6379> rpop QUEUE_KEY "queueV03" 127.0.0.1:6379> rpop QUEUE_KEY (nil) 127.0.0.1:6379> ================ #Zset(sorted set)带有优先级的消息的队列 127.0.0.1:6379> zadd ZQUEUE_KEY 60 v1 70 v2 80 v3 90 v4 #zset 是使用score来设置优先级的 (integer) 4 127.0.0.1:6379> zrange ZQUEUE_KEY 0 -1 1) "v1" 2) "v2" 3) "v3" 4) "v4" 127.0.0.1:6379> zrange ZQUEUE_KEY 0 -1 withscores 1) "v1" 2) "60" 3) "v2" 4) "70" 5) "v3" 6) "80" 7) "v4" 8) "90" 127.0.0.1:6379> zrangebyscore ZQUEUE_KEY 60 90 1) "v1" 2) "v2" 3) "v3" 4) "v4"
时间轴(Timeline)
list作为双向链表,不光可以作为队列使用。如果将它用做栈便可以成为一个公用的时间轴。当用户发完微博后,都通过lpush将它存放在一个key为LAST_WEIBO 的list中,之后便可以通过lrange取出当前最新的微博。127.0.0.1:6379> lpush LAST_WEIBO wb1 wb2 wb3 wb4 wb5 (integer) 5 127.0.0.1:6379> lrange LAST_WEIBO 2 4 1) "wb3" 2) "wb2" 3) "wb1" 127.0.0.1:6379> lrange LAST_WEIBO 0 -1 1) "wb5" 2) "wb4" 3) "wb3" 4) "wb2" 5) "wb1"
排行榜
使用sorted set 和一个计算热度的算法便可以轻松打造一个热度排行榜,zrevrangebyscore可以得到以分数倒序排列的序列,zrank可以得到一个成员在该排行榜的位置(是分数正序排列时的位置,如果要获取倒序排列时的位置需要用zcard-zrank)。计数器
计数功能应该是最适合Redis的使用场景之一了,因为它高频率读写的特征可以完全发挥Redis作为内存数据库的高效。在Redis的数据结构中,String、hash和sorted set [b]都提供了incr[/b]方法用于原子性的自增操作,下面举例说明一下它们各自的使用场景:如果应用需要显示每天的注册用户数,便可以使用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自增。
127.0.0.1:6379> hset weibo weibo_id 111111 (integer) 1 127.0.0.1:6379> hget weibo weibo_id "111111" 127.0.0.1:6379> hmset 111111 like_number 23 comment_number 46 forward_number 14 view_number 96 OK 127.0.0.1:6379> hkeys 111111 1) "like_number" 2) "comment_number" 3) "forward_number" 4) "view_number" 127.0.0.1:6379> hincrby 111111 like_number 1 (integer) 24 127.0.0.1:6379> hmget 111111 like_number comment_number forward_number view_number 1) "24" 2) "46" 3) "14" 4) "96" 127.0.0.1:6379> hincrby 111111 comment_number 3 (integer) 49 127.0.0.1:6379> hmget 111111 like_number comment_number forward_number view_number 1) "24" 2) "49" 3) "14" 4) "96" 127.0.0.1:6379>
如果应用有一个发帖排行榜的功能,便选择sorted set [b]吧,将集合的key设为POST_RANK[/b]。当用户发帖后,使用zincrby将该用户id的score增长1. **sorted set **会重新进行排序,用户所在排行榜的位置也就会得到实时的更新。
好友关系
新浪微博Redis应用分享中使用的,微博的Redis主要是用在计数和好友关系两方面,《Redis设计与实现》中作者最开始就是希望set解决传统数据库无法快速计算集合中交集这个功能。scienjus博主猜测说:
对于一个用户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。
127.0.0.1:6379> sadd A_FOLLOWER C E F (integer) 3 127.0.0.1:6379> SADD A_FOLLOW B C D (integer) 3 127.0.0.1:6379> SADD B_FOLLOWER A C F (integer) 3 127.0.0.1:6379> SADD B_FOLLOW C D (integer) 2 127.0.0.1:6379> SINTER A_FOLLOW A_FOLLOWER 1) "C" 127.0.0.1:6379> SINTER A_FOLLOW B_FOLLOW 1) "D" 2) "C" 127.0.0.1:6379> SINTER A_FOLLOW B_FOLLOWER 1) "C" 127.0.0.1:6379>
分布式锁
在Redis 2.6.12版本开始,String的set命令增加了三个参数:EX : 设置键的过期时间(单位为秒)
PX : 设置键的过期时间(单位为毫秒)
NX | XX :当设置为 NX 时,仅当key存在时才进行操作,设置为XX时,仅当key不存在才会进行操作。
由于这个操作是原子性的,可以简单地以此实现一个分布式锁,例如:
**set key "lock" EX 1 XX
如果这个操作返回false, 说明key的添加不成功,说明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。
转自http://www.scienjus.com/redis-use-case/
相关文章推荐
- redis学习一 ------ redis安装
- spring boot + redis 实现session共享
- Redis学习笔记(二)快速掌握命令行
- Redis java调用API
- 管中窥豹之Redis源码分析<一>
- Redis 集群解决方案 Codis
- virtualbox上安装centos6.5以及安装Java,redis,hadoop等等常用开发工具
- Redis未授权访问漏洞
- redis解决单点故障HA(高可用)主从复制
- php redis操作类
- redis cluster install
- redis的部署
- 【转】Redis 集群之路由
- Redis主从复制
- spring boot + redis 实现session共享
- spring boot + redis 实现session共享
- 【转】Redis的Java客户端Jedis的八种调用方式(事务、管道、分布式)介绍
- redis消息发送与订阅
- Windows下使用Redis(一)安装使用
- 快速安装redis