Redis各个数据类型的使用场景
Redis列表命令
使用场景String
常规key-value缓存应用;
常规计数:微博数,粉丝数等。
hash
存储部分变更的数据,如用户信息等。
list
Redis的list是每个子元素都是String类型的双向链表,可以通过push和pop操作从列表的头部或者尾部添加或者删除元素,这样List即可以作为栈,也可以作为队列。
使用list可以构建队列系统,使用sorted set甚至可以构建有优先级的队列系统。
比如:将Redis用作日志收集器
实际上还是一个队列,多个端点将日志信息写入Redis,然后一个worker统一将所有日志写到磁盘。
//把当前登录人添加到链表里ret = r.lpush("login:last_login_times", uid)//保持链表只有N位ret = redis.ltrim("login:last_login_times", 0, N-1)//获得前N个最新登陆的用户Id列表last_login_list = r.lrange("login:last_login_times", 0, N-1)
- 1
- 2
- 3
- 4
- 5
- 6
在Redis中我们的最新微博ID使用了常驻缓存,这是一直更新的。但是做了限制不能超过5000个ID,因此获取ID的函数会一直询问Redis。只有在start/count参数超出了这个范围的时候,才需要去访问数据库。
系统不会像传统方式那样“刷新”缓存,Redis实例中的信息永远是一致的。SQL数据库(或是硬盘上的其他类型数据库)只是在用户需要获取“很远”的数据时才会被触发,而主页或第一个评论页是不会麻烦到硬盘上的数据库了。
set
案例:
在微博应用中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。Redis还为集合提供了求交集、并集、差集等操作,可以非常方便的实现如共同关注、共同喜好、二度好友等功能,对上面的所有集合操作,你还可以使用不同的命令选择将结果返回给客户端还是存集到一个新的集合中。
//book表存储book名称set book:1:name "The Ruby Programming Language"set book:2:name "Ruby on rail"set book:3:name "Programming Erlang"//tag表使用集合来存储数据,因为集合擅长求交集、并集sadd tag:ruby 1sadd tag:ruby 2sadd tag:web 2sadd tag:erlang 3//即属于ruby又属于web的书? inter_list = redis.sinter("tag:web", "tag:ruby")//即属于ruby,但不属于web的书? diff_list = redis.sdiff("tag:ruby", "tag:web")//属于ruby和属于web的书的合集? union_list = redis.sunion("tag:ruby", "tag:web")
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
这个使用Redis的set数据结构最合适了,只需要不断地将数据往set中扔就行了,set意为集合,所以会自动排重。
sorted set
这个需求与上面需求的不同之处在于,前面操作以时间为权重,这个是以某个条件为权重,比如按顶的次数排序,这时候就需要我们的sorted set出马了,将你要排序的值设置成sorted set的score,将具体的数据设置成相应的value,每次只需要执行一条ZADD命令即可。
//将登录次数和用户统一存储在一个sorted set里zadd login:login_times 5 1zadd login:login_times 1 2zadd login:login_times 2 3//当用户登录时,对该用户的登录次数自增1ret = r.zincrby("login:login_times", 1, uid)//那么如何获得登录次数最多的用户呢,逆序排列取得排名前N的用户ret = r.zrevrange("login:login_times", 0, N-1)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 列出前100名高分选手 - 列出某用户当前的全球排名
模式是这样的,每次获得新得分时,我们用这样的代码:
ZADD leaderboard <score> <username>
- 1
得到前100名高分用户很简单:
ZREVRANGE leaderboard 0 99
- 1
ZRANK leaderboard <username>
- 1
比如你可以把上面说到的sorted set的score值设置成过期时间的时间戳,那么就可以简单地通过过期时间排序,定时清除过期数据了,不仅是清除Redis中的过期数据,你完全可以把Redis里这个过期时间当成是对数据库中数据的索引,用Redis来找出哪些数据需要过期删除,然后再精准地从数据库中删除相应的记录。
来自Redis在Google Group上的一个问题,有一位同学发贴求助,说要解决如下的一个问题:他有一个IP范围对应地址的列表,现在需要给出一个IP的情况下,迅速的查找到这个IP在哪个范围,也就是要判断此IP的所有地。这个问题引来了Redis作者Salvatore Sanfilippo(@antirez)的回答。解答如下:
例如有下面两个范围,10-20和30-40
- A_start 10, A_end 20
- B_start 30, B_end 40
我们将这两个范围的起始位置存在Redis的sorted set数据结构中,基本范围起始值作为score,范围名加start和end为其value值:
redis 127.0.0.1:6379> zadd ranges 10 A_start1redis 127.0.0.1:6379> zadd ranges 20 A_end1redis 127.0.0.1:6379> zadd ranges 30 B_start1redis 127.0.0.1:6379> zadd ranges 40 B_end1
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
现在我需要查找15这个值在哪一个范围中,只需要进行如下的zrangbyscore查找:
redis 127.0.0.1:6379> zrangebyscore ranges (15 +inf LIMIT 0 11) "A_end"
- 1
- 2
查找的结果是A_end,由于所有值是按顺序排列的,所以可以判定15是在A_start到A_end区间上,也就是说15是在A这个范围里。至此大功告成。
当然,如果你查找到的是一个start,比如咱们用25,执行下面的命令:
redis 127.0.0.1:6379> zrangebyscore ranges (25 +inf LIMIT 0 11) "B_start"
- 1
- 2
当然,这个例子仅适用于类似上面的IP范围查找的案例,因为这些值范围之间没有重合。如果是有重合的情况,这个问题本身也就变成了一个一对多的问题。
Pub/Sub
比如很多用Pub/Sub构建的实时聊天系统的例子。
更多免费技术资料可关注:annalin1203