我们都知道Redis支持5种不同的数据类型、但是在我们的日常开发过程中,用的最多的是String类型。当存一个字段属性时,我们使用String,当存储一个对象时,我们使用Gson转换成一个Json字符串去存储。但是针对Redis的五种数据类型,有很多业内的一些常用的使用场景整理。
1、String类型
常用指令汇总:
- 添加数据:set key value
- 获取数据:get key
- 删除数据:del key
- 添加多个数据:mset key1 valueq key2 value2 …
- 获取多个数据:mget key1 key2 ...
- 获取数据字符个数(字符串长度)strlen key
- 追加信息到原始信息后部(如果原始信息存在就追加,否则新建)append key value
业务场景使用:
1.自增主键,例如MySQL的自增主键获取、
- incr key //自增1
- incrby key increment //增加指定数值
- incrbyfloat key increment //增加一个浮点数
2. String时效性处理
- 场景一:“某某综艺”,启动海选投票,只能通过微信投票,每个微信号每4个小时只能投1票。
- 场景二:电商商家开启热门商品推荐,热门商品不能一直处于热门期,每种商品热门期维持3天,3天后自动取消热门
- 场景三:新闻网站会出现热点新闻,热点新闻最大的特征是对时效性,如何自动控制热点新闻的时效性
解决方案:
给用户设置一个唯一的id,并为其设置一个有效时长,当时间已经超过设定时间后将id删除。
redis 控制数据的生命周期,通过数据是否失效控制业务行为,适用于所有具有时效性限定控制的操作。
setex key seconds value //增加、修改键值对并为其设定生命周期
psetex key milliseconds value //功能与上面一直,秒的单位不同
String类型使用注意事项:
- string在redis内部存储默认就是一个字符串,当遇到增减类操作incr,decr时会转成数值型进行计算
- redis所有的操作都是原子性的,采用单线程处理所有业务,命令是一个一个执行的,因此无需考虑并发带来的数据影响。
- 按数值进行操作的数据,如果原始数据不能转成数值,或超过了redis数值上线范围,将会报错。9223372036854775807 (java中long型数据最大值,Long.MAX_VALUE)
- 表示运行结果是否成功(integer)0 –> false 失败(integer)1 –> true 成功
- 表示运行结果值(integer)3 –> 3 3个integer)1 –> 1 1个 数据未获取到
- (nil)等同于nul
2、Hash数据类型
概述:
如果说String类型,一个Key对应一个对象的字段,那么使用Hash就可以存储整个对象,当然这个存储的键值对是有上限的。合理的使用Hash类型,可以避免没必要的内存消耗。其中对象的字段名为Filed,属性为Value,其中Value只能存储String类型。
常用指令汇总:
- 添加修改数据:hset key field value
- 获取数据:hget key field hgetall key
- 删除数据: hdel key field1 [field2]
- 添加多个数据:hmset key field1 value1 field2 calue2
- 获取多个数据:hget key field1 field2...
- 获取Hash表中的数量:hlen key
- 获取哈希表中是否存在指定的字段:hexists key field
-
获取哈希表中所有的字段名和字段值:hkeys key //字段名 hvals key //字段值
-
设置指定字段的数值数据增加指定范围的值:hincrby key field increment hincrbyfloat key field increment
业务场景使用
1.电商网站购物车的设计与实现。
购物车的缓存,我们使用淘宝时,还是比较常用到购物车页面,需要对购物车数据进行缓存的案例就可以用到Hash类型。其中,将用户Id:作为Key。商品Id作为Field字段,数量作为Value信息。
具体的解决方案:
- 以客户Id作为Key。将购物车中所有的信息Hash存储,不同的商品ID对应不同的Field。
- 将商品ID作为feild,购买数量做为Value存储
- 添加商品,在hash中追加不同的feild。
- 更改数量: 自增/自减 更改Value值
当前仅仅是将数据存储到redis中,并没有起到加速的所用,因为我们仅仅查询到了用户的id和商品的id,显示的时候显示的用户名和商品的名称,商品信息还需要二次查询数据库。
每条购物车中的商品记录保存成两条field
field1 专用于保存购买数量
1、命名格式:商品id:nums
2、保存数据:数值
field2 专用于保存购物车中显示的信息,包含文字描述,图片地址,所属商家信息等等
1、命名格式:商品id:info
2、保存数据:json
2.抢购、激活码、限时发放优惠券等场景的应用
案例分析:
例如双11期间。商家做活动,限时发放优惠卷。有30、50、100面额的优惠券各100张
具体的解决方案:
- 以商家id作为key
- 将参与抢购的商品id作为field
- 将参与抢购的商品数量作为对应的value
- 抢购时使用降至的方式控制产品数量
Has类型使用注意事项:
- hash类型下的value只能存储字符串,不允许存储其他类型数据,不存在嵌套现象。如果数据未获取到,对应的值为(nil)
- 每个hash可以存储2的32次方-1个键值对
- hash类型十分贴近对象的数据存储形式,并且可以灵活添加删除对象属性。但hash设计不是为了存储大量对象的,切记不可滥用,更不可以将hash作为对象列表使用
- hgetall操作可以获取全部属性,如果内部fiekd过多,遍历整体数据效率就会很低,有可能成为数据访问瓶颈。
3、List数据类型
概述:
List数据类型类似于Java中LinkedList的数据结构,是一个双向的链表结构,支持从头部或者尾部添加或者删除数据。 也类似于Java栈,对于进入list中的数据,有严格的顺序FIFO,先进先出。
常用指令汇总:
- 添加/修改数据: lpush key value1 [value2] 从list左边插入数据 rpush key value1 [value2] 从list右边插入数据
- 获取数据:lrange key start stop //获取从左数第start到stop个元素,从0开始
lindex key index //查询第i个元素
llen key //list的长度 - 获取并移除数据:lpop key //获取并删除左边第一个元素
rpop key //获取并删除右边第一个元素 - 规定时间内获取并移除数据:blpop key1 [key2] timeout
brpop key1 [key2] timeout
业务场景使用
1.微信朋友圈点赞,要求按照点赞顺序显示点赞好友信息。
如果取消点赞,移除对应好友信息。
解决方案:移除制定的数据:
lrem key count value //count为移除的数量,value为移除哪个值
2.业务场景-最新消息的展示
- twitter、新浪微博、腾讯微博中个人用于的关注列表需要按照用户的关注顺序进行展示,粉丝列表需要将最近关注的粉丝列在前面
- 新闻、资讯类网站如何将最新的新闻或资讯按照发生的事件顺序展示
- 企业运营过程中,系统将产生出大量的运营数据,如何保障堕胎服务器操作日志的统一顺序输出?
具体解决方案:
- 依赖list的数据具有顺序的特征对信息进行管理
- 使用队列模型解决多路信息汇总合并的问题
- 使用栈模型解决最新消息的问题
List类型数据操作注意事项
- list 中保存的数据都是string类型的,数据总容量式是有限的,最多232-1个元素(4294967295)
- list具有索引的概念,但是操作数据时候通常以队列的形式进行入队出队操作,或以栈的形式进入栈出栈的操作
- 获取全部数据操作结束索引设置为-1
- list 可以对数据进行分页操作,通过第一页的信息来自list,第2页及更多的信息通过数据库的形式加载。
4、Set数据类型
概述:
Set类型类似Java中HashSet。与Hash类型的存储结构一致,唯一的区别在于、Set只存储key值,即只保留feild,其中最重要的属性就是不允许有重复feild存在。
常用指令汇总:
- 添加数据: sadd key menber1 [member2]
- 获取全部数据:smembers key
- 删除数据:srem key member1 [member2]
- 获取集合数据总量:scard key
- 判断集合中是否包含指定数据 sismember key member
业务场景使用
1.随机操作数据
每位用户首次使用进入头条时候会设置3项爱好的内容,但是后期为了增加用户的活跃度,兴趣点,必须让用户对其他信息类别逐渐产生兴趣,增加客户留存度,如何实现?
业务分析
- 系统分析出各个分类的最新或最热点信息条目并组织成set集合
- 随机挑选其中部分信息
- 配合用户关注信息分类中的热点信息组织展示的全信息集合
解决方案
- 随机获取集合中指定数量的数据 srandmember key [count
2.业务场景-共同好友
解决方案
- 求两个集合的交、并、差集
sinter key1 [key2] //交集
sunion key1 [key2] //并集
sdiff key1 [key2] //差集(key1有但是key2没有的)
- 求两个集合的交、并、差集并存储到指定集合中
sinterstore destination key1 [key2]
sunionstore destination key1 [key2]
sdiffstore destination key1 [key2]
- 将指定数据从原始集合移动到目标集合中
smove source destination member
3.业务场景-同类型不重复数据的合并操作
解决方案
依赖set集合数据不重复的特征,依赖set集合hash存储结构特征完成数据过滤与快速查询
- 根据用户id获取用户所有角色
- 根据用户所有角色获取用户所有操作权限放入set集合
- 根据用户所有觉得获取用户所有数据全选放入set集合
4.set业务场景-访问量统计去重
解决方案
针对不同的统计类型有不同的数据存储方式:
- 利用set集合的数据去重特征,记录各种访问数据
- 建立string类型数据,利用incr统计日访问量(PV)
- 建立set模型,记录不同cookie数量(UV)
- 建立set模型,记录不用IP数量(IP)
5、set业务场景-黑白名单
解决方案
- 基于经营战略设定问题用户发现、鉴别规则
- 周期性更行满足规则的用户黑名单,加入set集合
- 用户行为信息达到后与黑名单进行比比对,确认行为去向
- 黑名单过滤IP地址:应用于开放游客访问权限的信息源
- 黑名单过滤设备信息:应用于限定访问设备的信息源
- 黑名单过滤用户:应用于基于访问权限的信息源
Set类型数据操作的注意事项
- set类型不允许数据重复,如果添加的数据在set中已经存在,将只保留一份
- set虽然与hash的存储结构相同,但是无法启用hash中存储值的空间
5、sorted_set类型
概述:
sorted_set其实就是一张有序的Set类型,我可以利用有序这个特性,来合理的使用、
常用指令汇总:
- 添加数据:zadd key score1 member1 [score2 member2]
- 获取全部数据:zrange key start stop [WITHSCORES]//按照从小到大的顺序,加上 WITHSCORES,就会带上scores一起显示
zrevrange key start stop [WITHSCORES]//按照从大到小的顺序 - 删除数据:zrem key member [member …]
- 按条件获取数据://查询scores在某个范围内的值 zrangebyscore key min max [WITHSCORES] [LIMIT] //查询key某个索引范围内的值 zrevrangebyscore key max min [WITHSCORES]
业务场景分析:
1.业务场景- 建立排序依据
解决方案
- 获取数据对应的索引(排名)
zrank key member //正数第几位
zrevrank key member //倒数第几位
- score 值获取与修改
zscore key member //获取
zincrby key increment member //score递增 increment
2.业务场景-会员短期体验之过期失效
解决方案
- 对于基于时间线限定的任务处理,将处理时间记录为score值,利用排序功能区分处理的先后顺序
- 记录下一个要处理的事件,当对比系统时间发现当然仍后到期后移除redis中的记录,并记录下一个要处理的时间
- 当新任务加入时,判定并更新当前下一个要处理的任务时间
- 为提升sorted_set的性能,通常将任务根据特征存储成若干个sorted_set.例如1小时内,1天内,年度等,操作时逐渐提升,将即将操作的若干个任务纳入到1小时内处理队列中
- time命令获取当前系统时间
6.五种类似数据的总结
Redis的应用场景
总结一
计数器
可以对 String 进行自增自减运算,从而实现计数器功能。Redis 这种内存型数据库的读写性能非常高,很适合存储频繁读写的计数量。
缓存
将热点数据放到内存中,设置内存的最大使用量以及淘汰策略来保证缓存的命中率。
会话缓存
可以使用 Redis 来统一存储多台应用服务器的会话信息。当应用服务器不再存储用户的会话信息,也就不再具有状态,一个用户可以请求任意一个应用服务器,从而更容易实现高可用性以及可伸缩性。
全页缓存(FPC)
除基本的会话token之外,Redis还提供很简便的FPC平台。以Magento为例,Magento提供一个插件来使用Redis作为全页缓存后端。此外,对WordPress的用户来说,Pantheon有一个非常好的插件 wp-redis,这个插件能帮助你以最快速度加载你曾浏览过的页面。
查找表
例如 DNS 记录就很适合使用 Redis 进行存储。查找表和缓存类似,也是利用了 Redis 快速的查找特性。但是查找表的内容不能失效,而缓存的内容可以失效,因为缓存不作为可靠的数据来源。
消息队列(发布/订阅功能)
List 是一个双向链表,可以通过 lpush 和 rpop 写入和读取消息。不过最好使用 Kafka、RabbitMQ 等消息中间件。
分布式锁实现
在分布式场景下,无法使用单机环境下的锁来对多个节点上的进程进行同步。可以使用 Redis 自带的 SETNX 命令实现分布式锁,除此之外,还可以使用官方提供的 RedLock 分布式锁实现。
其它
Set 可以实现交集、并集等操作,从而实现共同好友等功能。ZSet 可以实现有序性操作,从而实现排行榜等功能。
总结二
Redis相比其他缓存,有一个非常大的优势,就是支持多种数据类型。
数据类型说明string字符串,最简单的k-v存储hashhash格式,value为field和value,适合ID-Detail这样的场景。list简单的list,顺序列表,支持首位或者末尾插入数据set无序list,查找速度快,适合交集、并集、差集处理sorted set有序的set
其实,通过上面的数据类型的特性,基本就能想到合适的应用场景了。
string——适合最简单的k-v存储,
类似于memcached的存储结构,短信验证码,配置信息等,就用这种类型来存储。
hash——一般key为ID或者唯一标示,
value对应的就是详情了。如商品详情,个人信息详情,新闻详情等。
list——因为list是有序的,
比较适合存储一些有序且数据相对固定的数据。如省市区表、字典表等。因为list是有序的,适合根据写入的时间来排序,如:最新的***,消息队列等。
set——可以简单的理解为ID-List的模式,
如微博中一个人有哪些好友,set最牛的地方在于,可以对两个set提供交集、并集、差集操作。例如:查找两个人共同的好友等。
Sorted Set——是set的增强版本,
增加了一个score参数,自动会根据score的值进行排序。比较适合类似于top 10等不根据插入的时间来排序的数据。
如上所述,虽然Redis不像关系数据库那么复杂的数据结构,但是,也能适合很多场景,比一般的缓存数据结构要多。了解每种数据结构适合的业务场景,不仅有利于提升开发效率,也能有效利用Redis的性能。
参考文章:
https://blog.csdn.net/zzu_seu/article/details/106323114
https://blog.csdn.net/ThinkWon/article/details/103522351
注:文中所有的应用场景都截取于上篇博客。在加上一点自己的理解。