您的位置:首页 > 数据库 > Redis

Redis 应用场景

2016-05-29 00:00 344 查看
摘要: Redis的一些应用场景

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的数据结构中,Stringhashsorted 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:followA:follower的交集得到与A相互关注的用户。当A进入另一个用户B的主要后,A:followB:follow 的交集便是A和B的共同专注,A:followB: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版本开始,Stringset命令增加了三个参数:

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/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: