Redis常见数据结构使用场景小结

Java项目开发中,Redis经常作为缓存中间件的角色而被广泛使用,平时使用最多的操作就是对字符串类型进行set/get了,偶尔还会设置一些键的过期时间。有一天与旁边的老王闲聊,他突然说到一个问题,我们都知道Redis有5种常用的数据结构,但每种数据结构的具体使用场景谁能说出来多少呢?额,这个问题似乎道出了目前的一种现实状况,即难道我们仅仅把Redis当缓存数据库使用?没有点其他追求了?当然不能了。

问题描述Redis常用的数据结构有哪些?能说一下每种数据结构的使用场景吗?

Redis常用的数据结构有字符串类型(strings)散列类型(hashes)列表类型(lists)集合类型(sets)有序集合类型(sorted sets),每种数据结构类型的特点,用张图表示,如下:

在这里插入图片描述

1、字符串类型(strings)使用场景

基本格式:以set/get命令为例

127.0.0.1:6379> set testkey weixiangxiang
OK
127.0.0.1:6379> get testkey
“weixiangxiang”

常用命令:get/set/mget/mset/getset/del/incr/incrby/decr/decrby/setex/psetex等。

使用场景:数据缓存,计数器,分布式session等,这里提到的数据库默认是mysql。

缓存频繁读取但不经常修改的数据(或者称为热点数据)

逻辑:这就是项目中经常使用的功能,前端页面查询热点数据时,先从redis缓存中读取,读取到值就返回,读取不到再去数据库查询返回,同时将查询的数据缓存到redis一份保存,根据需求是否设置过期时间。

注意事项:为了方便,key-value中的值value通常存储的是序列化的json串。

记录网站被用户访问的次数,或网站中的商品被浏览的次数,或限制用户访问次数

逻辑:因为redis是基于内存操作,且网路请求模块使用的是单线程和IO多路复用技术,操作响应特别快,也无并发竞争等问题,相比于使用数据库频繁的去修改数据实现记录访问次数或浏览次数,redis更适合替代这类操作。

注意事项:记录用户访问或浏览次数,key-value中的key通常使用用户ID+网站地址组合而成的字符串,value则使用incr命令实现次数统计;限制用户访问次数的话,key-value中的key设置为用户的IP地址,value记录访问次数,并设置key的过期时间,当key未过期且value超过了访问频次的条件限制,禁止该IP用户访问(或提示xx秒后重试…)。

举例:如CSDN网站的Java专栏中某篇博客的点赞次数,浏览次数等。

在这里插入图片描述

实现分布式session,避免重新登录

逻辑:所谓分布式session,就是多个应用服务器共享一个session会话。当用户第一次登录时,将session会话文件存放在redis中,该redis可以独立于所有负载均衡服务器,也可以放在其中一台负载均衡服务器上,但所有应用所在的服务器连接的必须都是同一个redis服务器,保证所有的应用共享一个session会话,从而避免重新登录。

2、列表类型(lists)使用场景

基本格式:以lpush/lrange命令为例

127.0.0.1:6379> lpush demokey Weixiangxiang
(integer) 1
127.0.0.1:6379> lpush demokey Trump
(integer) 2
127.0.0.1:6379> lpush demokey Biden
(integer) 3
127.0.0.1:6379> lrange demokey 0 1
1)“Weixiangxiang”
2)“Trump”

常用命令:lpush/rpush/lpop/rpop/blpop/brpop/rpoppush/brpoppush/lrange/lindex/linsert/lset等。

使用场景:lists是一个元素有序的可重复的列表,可以实现消息队列MQ,栈,定时排行榜等。

实现消息队列MQ

逻辑:通过lpush命令从头部入队,通过rpop或brpop命令从尾部出队(符合先入先出的队列模式),反之,可以也通过rpush命令从尾部入队,通过lpop或blpop命令从头部出队。因此,Redis实现消息队列是通过一组 lpush/rpop/brpop 或 rpush/lpop/blpop 命令实现的。

第一种:非阻塞式(lpush + rpop)

说明:把lpush命令操作当作消息的生产者,rpop命令操作当作消息的消费者,举例说明:
在这里插入图片描述
第二种:阻塞式(lpush + brpop)

说明:brpop命令格式为brpop key [key …] timeout ,对于同一个Redis客户端,若多个键(如q1,q2)都有元素,则按照从左到右读取第一个键中的一个元素,借此特性可以实现区分优先级的任务队列,,举例说明:

在这里插入图片描述

注意事项:第一种如果消息生产者的生产速度大于消费者的消费速度,可能会引发消息积压的问题。另外,实现不停的监听且消费消息,需要不停的调用rpop操作,每调用一次都会发起一次连接,这会造成不必要的资源浪费,因此不推荐使用第一种非阻塞方式。

可分页的定时排行榜

逻辑:将每隔一段时间计算一次的排行榜存储在list列表中,在访问接口时,将page和size分页参数转化成lrange命令即可获取排行榜数据。

注意事项:lists类型适合定时更新的排行榜的实现,但不适合实现实时热榜。

举例:如网易云音乐的热歌TOP排行榜,每周四更新,将用户一周内的歌曲收听才计算一次。

在这里插入图片描述

3、散列类型(hashes)使用场景

基本格式:以hmset/hmget命令为例

127.0.0.1:6379> hmset testkey testfield1 tea testfield2 coffee testfield3 coke
OK
127.0.0.1:6379> hmget testkey testfield2 testfield3
1)“coffee”
2) redis coke"

常用命令:hget/hset/hmget/hmset/hgetall/hdel/hincrby/hkeys/hsetnx/hexists/hscan/hvals等。

使用场景:优化strings类型等。

对strings类型的key-value存储进行优化,尤其是多属性的value

逻辑:strings类型的key-value存储中,value通常是序列化的json串(比如商品对象字符串中有多个属性字段),如果频繁修改json串的某个属性,等于要修改整个对象,不灵活且效率低,而将这种模式改为hashes类型,用field存储字段名称,value存储字段名称对应的属性,只需要操作field即可修改某个属性了。

举例:可以参考我的另一篇博客,【记录】优化Redis存储

4、集合类型(sets)使用场景

基本格式:以sadd/smembers命令为例

127.0.0.1:6379> sadd testkey svp
(integer) 1
127.0.0.1:6379> sadd testkey mvp
(integer) 1
127.0.0.1:6379> sadd testkey vvp
(integer) 1
127.0.0.1:6379> smembers testkey
1)“mvp”
2)“svp”
3)“vvp”

常用命令:sadd/smembers/sdiff/scan/sinsert/srem/issmember等。

使用场景:sets是字符串的无序排列,基于此可以实现收藏夹功能。

歌曲或网页的收藏功能

逻辑:比如,听音乐时将喜欢的或感兴趣的歌曲可以添加到歌单中,浏览网页时将有用的网站加入收藏夹等等,这里key为用户ID,value则为歌曲ID或网址的集合。

举例:网易云音乐中我收藏的歌单。

在这里插入图片描述

5、有序集合类型(sorted sets)使用场景

基本格式:以zadd/zrange命令为例

127.0.0.1:6379> ZADD testkey 1 redis
(integer) 1
127.0.0.1:6379> ZADD testkey 2 mysql
(integer) 1
127.0.0.1:6379> ZADD testkey 3 oracle
(integer) 1
127.0.0.1:6379> ZADD testkey 3 oracle
(integer) 0
127.0.0.1:6379> ZADD testkey 4 oracle
(integer) 0
zrange testkey 0 10 WITHSCORES
1)“redis”
2)“1”
3)“mysql”
4)“2”
5)“oracle”
6)“4”

常用命令:zadd/zcan/zincrby/zcount/zcard/zrem/zrange/zrank等。

使用场景:与sets不同的是,sorted sets每个元素都会关联一个score属性,redis正是通过score来为集合中的成员进行从小到大的排序,可以实现实时排行榜,如小时榜,日榜,周榜等。

实时排行榜

逻辑:实现多种实时的榜单,比如小时榜、日榜榜、周榜等,可以用redis key存储榜单类型,score为点击量,value为事件id,用户每点击一个事件会更新redis数据,sorted set会依据score即点击量将事件id排序。

举例:如微博的1小时榜,24小时榜等。
在这里插入图片描述

小结:

至此,整理和分析了redis常用数据结构的应用场景,当然这里所罗列的场景并不能涵盖所有的了,关键之处是要熟悉redis的数据结构和相关命令的特征,这样才能选择合适的方式实现业务需求。
另外,像bitmaps这种结构,它是通过一个bit位来表示某个元素对应的值或者状态,特别适合实现用户签到、活跃用户/在线用户统计等需求,可以参考setbit、bitcount等相关命令;而对于用户人数超多的网站(几千万乃至上亿人数)统计在线人数的话,使用HyperLogLog再合适不过了,它是用来做基数统计的概率算法,优点是在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、且很小的,可以参考pfadd、pfcount等相关命令。

参考:

1. Redis 教程| 菜鸟教程
2. Redis中文官方网站之redis命令
3. 基于Redis实现排行榜周期榜与最近N期榜

猜你喜欢

转载自blog.csdn.net/qq_29119581/article/details/112460756