Redis这样用

  • 一、String类型
    • 1. 对String类型的理解
    • 2. 常用命令如下
    • 3. 应用场景
      • ① 分布式锁
      • ② 缓存设计
      • ③ 全局唯一序列号、计数器(value为Numbers类型)
      • ④ 判断大数据量包含(在线用户数量统计、布隆过滤器)(bit类型)
  • 二、hash哈希结构
    • 1. 对hash结构的理解
    • 2. 常用命令
    • 3. 应用场景
      • ① 缓存设计
      • ② 购物车实现
  • 三、List结构
    • 1. 对list结构的理解
    • 2. 常用命令
    • 3. 应用场景
      • ① 消息队列实现
      • ② 关注的最新消息列表(微信朋友圈、抖音我的关注的视频)
  • 四、Set数据结构
    • 1. 对Set结构的理解
    • 2. 常用命令
    • 3. 应用场景
      • ① 抽奖活动(刷礼物抽奖/拼多多抽奖)
      • ② 打卡/点赞/签到
      • ③ 共同关注/商品推荐 模型
      • ④ 商品筛选
  • 五、Sorted Set数据结构
    • 1. 理解
    • 2. 常用命令
    • 3. 应用场景
      • ① 单日排行榜/微博热搜
      • ② 周榜/月榜/年榜

Redis,全称REmote DIctionary Server,是由K-V组织起来的数据结构,其有8种数据类型,其中常用的有5种,分别是 StringHashListSetSorted Set

一、String类型

1. 对String类型的理解

你可以将redis的String类型理解为Java中的HashMap,如下:

HashMap<String, Object>
· key 为字符串类型
· value 可以是如下类型String类型Numbers数值类型bit类型(位数组)

2. 常用命令如下

set key value      --存入一个字符串键
setnx key value    --存入key不存在的字符串键, 若key存在, 则存入失败
get key            --获取指定key的字符串
mset k1 v1 k2 v2   --批量存入字符串键
mget k1 k2         --批量获取指定key的字符串del key            --删除指定key-value

3. 应用场景

① 分布式锁

  • 分布式锁1:
setnx lockObj true   //获取锁
del lockObj          //释放锁

但是可能获取锁后由于某种原因没能释放锁就会导致死锁

  • 分布式锁2:
// 获取锁, 参数EX过期时间, NX相当于setnx:set not existed
set lockObj true EX 100 NX
del lockObj      //释放锁

但是可能拿到锁的线程还未执行完就释放了锁,最终导致两个线程共同执行一段代码 不安全
优化: 设置后台线程,检测当前线程是否执行完,如果未执行完就到了过期时间那么给锁续期

② 缓存设计

通常我们需要对数据库表中的热点数据进行缓存

  • 方式一: 将一个对象转为json格式,然后以String的方式存入Redis,但是当我们需要对对象的某个属性进行修改时,我们需要先将对象取出,然后再反序列化为java bean,然后set值,再序列化为json,再放入Redis。但是这样做是比较麻烦的

  • 方式二: 用一个合理的key设计并配置批处理set与get

例如 {表明}:{PK}:{字段名} PK为表中数据的唯一标识
mset user:1:name zhangsan user:1:age 18
mset user:2:name lisi user:2:age 19

当我们取值的时候就可以通过关键PK取,那么修改也可以直接替换

③ 全局唯一序列号、计数器(value为Numbers类型)

  • 计数器
            采用如下原子操作命令
incr key           --自增1
decr key           --自减1
incrby key incrs   --在原来基础上加incrs
decrby key decrs   --在原来基础上减decrs

利用上述命令可以实现访问量业务或是接口频率限制等

  • 全局序列实现
            在分库分表或者分布式系统中,想要保证全局唯一序列,可以利用redis的自增操作,通常情况下会从redis中通过incrby命令拿一段序列,存到当前服务的内存中,用完了再去取,而非每次需要序列时都去redis执行incr操作,这是为了减少跟redis的交互,减少网络IO。

④ 判断大数据量包含(在线用户数量统计、布隆过滤器)(bit类型)

bitmap      ---------     [0][0][1][0][1][0][0]
getbit key offset         --获取key下标为offset的值
setbit key offset         --设置key下表为offset的值
bitcount key start end    --统计key从start到end位置设置为1的数量
bitops op destkey [key..] --对多个key进行位运算 op(and/or/xor/not)(与或异或非)
  • 在线用户数量统计

用户主键为自增,我们可以用主键作为bitmap的下表,当用户上线,将其置为1,用户下线置为0,用bitcount userOnline即可统计出在线用户数量;此种方式是非常节省内存的,一位即可表示一位用户,那么1KB就可以标记8 * 1024个用户。此外还有很多应用场景,比如验证码、限时活动等业务,在这里就不再列举。

二、hash哈希结构

1. 对hash结构的理解

依旧可以理解为Java中的HashMap
HashMap<String, HashMap<String, Object>>
属于三维数据结构, key为String类型, value可以理解为存放的是一个对象, 可以通过属性对值进行操作

2. 常用命令

hset key field value     --存入一个key filed散列结构
hsetnx key field value   --同hset, 若存在则操作失败
hget key field           --获取指定key的field的值
hmset k1 f1 v1 k2 f2 v2  --批量存入
hget k1 f1 k2 f2         --批量获取
hdel key field           --删除指定key的field
hincrby key field incrs  --对指定的key的field的值加incrs

3. 应用场景

① 缓存设计

String数据类型也可以用于缓存,比如将对象序列化放入缓存,或者是利用上述第二种方式设计,我们会发现,其实hash结构跟String类型的第二种设计方式很类似,但是为什么还要用hash结构呢?

  • 1)可以用一个key将一整个对象或者是相关的一部分数据聚集起来,便于管理
  • 2)可以减少内存/IO/CPU的消耗

因为一些ttl的扫描或者更新,redis内部都是对key进行扫描监控的,如果string类型的第二种方式设计缓存,那么一个对象无疑需要存很多个key,如此一来就比较消耗IO/COU与内存,而hash结构会将String类型的第二种方式的很多个key聚集没一个key,redis内部只要对一个key进行扫描监控即可,这也是hash结构的主要优势
注意: 但是在某些场景,散列结构是代替不了String结构的,

  • 例如二进制bit类型,hash不支持bitmap
  • 例如当我们需要考量缓存设计当中,数据分布的时候,散列结构就不合适了,key较少 数据太聚集

② 购物车实现

只保存购物车商品数据的逻辑关系

// 添加
hincrby {userId}:shoppingCart {goodsId} {count} //userId用户的购物车的goodsId的商品添加了count件
// 查询
hget {userId}:shoppingCart

三、List结构

1. 对list结构的理解

// 可以理解为
HashMap<String, List<Object>>

2. 常用命令

Redis的List是有序的,类似于Java中的队列,又能像Java中的List一样用下标取值,只不过Redis的List有正负下标。

常用0到-1表示列表中的所有值,1到1表示下表为1的值,结合下面的命令可以按下标取单个值或多个值

lpush key value            #往key的列表中左边放入一个元素, key不存在则新建
rpush key value            #往key的列表右边放入一个元素
lpop key                   #从key的列表左边弹出一个元素
rpop key                   #从key的列表右边弹出一个元素
lrange key start end       #获取列表键从start到end下表的元素, 如果start=end, 那就是取一个元素
blpop key[key...] timeout  #阻塞地从key的列表键最左端弹出一个元素, 若列表没元素, 则等待t秒, 若t为0, 则一直等待
brpop key[key...] timeout  #同上, 只不过从最右端弹出一个元素

3. 应用场景

① 消息队列实现

生产者在List左端lpush生产,消费者从List右端brpop,让timeout为0,一直等待List中的消息。
        但在数据可靠性以及如何防止消息丢失上还是有诟病的,只能说redis在缓存方面有优势,其他的还是交给专用组件去做比较好。

② 关注的最新消息列表(微信朋友圈、抖音我的关注的视频)

以下仅表示数据的逻辑关系,具体实现还要具体思考,但可以借鉴
        当你抖音关注的人发了视频,或者你微信的朋友发了动态,那么将消息id从你的消息列表左侧推入,当你上线,或者是浏览的时候,会从最左侧拿到最新数据,如果数据量较大,再进行分页设计

# 消息保存
lpush {userId}:msgList {msgid}
# 获取最新消息, 下面命令可以拿到最新的10条消息
lrange {userId}:msgList 0 10

四、Set数据结构

1. 对Set结构的理解

// 可以理解为
HashMap<String, HashSet>

2. 常用命令

sadd key member[member...]  --往集合key中存放元素, 若key不存在则新建
srem key member[member...]  --从集合key中删除元素
smembers key                --获取集合key中所有的元素
scard key                   --获取集合key中所有元素的个数
sismember key member        --判断member是否存在于集合key中
srandmember key [count]     --从集合key中随机选出count个元素, 但不删除
spop key [count]            --从集合key中弹出count个元素并删除

3. 应用场景

① 抽奖活动(刷礼物抽奖/拼多多抽奖)

抽奖活动有很多种,常见的有给主播刷礼物,主播会让你参与抽奖活动,抽到的用户将会获得奖品,这是针对用户抽奖,另一种是针对商品,比如拼多多,转动转盘,抽到什么,额…其实也不给什么。可以参考如下逻辑

sadd activeKey userId  # 将满足条件的用户添加到activeKye的活动集合中
smembers activeKey     # 获取所有满足条件的用户, 然后随机滚动或转动圆盘
# 获取中奖名单
spop activeKey [count] 或者 srandmembers activeKey [count]

像随机的抽奖活动都可以用这种方式实现,但是,你有没有发现拼多多,你每次抽奖都会抽到指定的那个,或者某个人给主播刷了很多礼物,那么我就想让他中奖概率很大,那怎么办呢??我也在思考ing…

② 打卡/点赞/签到

用户1005点赞8888帖子 sadd like:8888 1005
用户1005取消8888帖子的点赞 srem like:8888 1005
检查1005用户是否点赞过 sismember like:8888 1005
获取8888帖子的点赞数 scard like:8888
获取帖子8888的点赞用户 smembers like:8888

③ 共同关注/商品推荐 模型

共同关注模型以及商品推荐模型依赖于set集合的计算,即交集、并集与差集,Redis也给我们提供了命令,如下:

sinter key[key...]  --交集
sunion key[key...]  --并集
sdiff  key[key...]  --差集

共同关注模型如抖音里的共同好友,或者是你可能感兴趣的人,又或者是你关注的人也关注了谁。如下:

  • 张三:zhangKey 关注了 {li, wang, zhao}
  • 李四:liKey 关注了 {zhang, wang, zhao, tian}
  • 王五:wangKey 关注了 {zhang, li, zhao, tian}
  • 当张三打开李四的抖音主页
  • 张三和李四的共同关注则为 sinter zhangKey liKey --> {wang, zhao}
  • 张三关注的人也关注了他, 这实际上是对张三关注列表的一个遍历, 判断张三关注的人的关注列表里是否包含李四sismember wangKey lisismember zhaoKey li
  • 张三可能认识的人, 即张三关注的人的关注列表可能有张三认识的, 所以在这就是李四关注的, 但是张三没有关注的, 可能就是张三认识的人, 所以取张三关注列表与李四关注列表的差集即可 sdiff zhangKey liKey

④ 商品筛选

每个商品入库的时候即会建立他的静态标签列表,例如品牌、尺寸、处理器、内存大小…每个标签都作为一个key,在每个标签中添加元素例如

sadd brand::apple iphone12
sadd screenSize::5.6-6.0 iphone12
sadd os::ios iphone12
...

那么当我选了筛选条件以后,后台只需要对这个集合做一个交集即可获得筛选后的结果

sinter brand::apple screenSize::5.6-6.0 os::ios --> {iphone12}

五、Sorted Set数据结构

1. 理解

Sorted Set又叫ZSet,其一个成员是由分值与元素组成的,分值是用来排序的。跟List一样,有正负下标,0到-1依旧表示所有元素。
zadd key score element[...]

2. 常用命令

zadd key score element[...]              --往有序集合key中存入元素, 若不存在则新建
zrem key element[element...]             --从有序集合key中删除元素
zscore key element                       --获取有序集合key中element元素的score
zincrby key incrment element             --对有序集合key中的element元素的score加incrment
zcard key                                --获取有序集合key中元素的个数
zrange key start end  [withscores]       --正序获取有序集合key从start到end的元素
zrevrange key start end   [withscores]   --倒叙获取有序集合key从start到end的元素
zunionstore destkey numkeys key[key...]  --并集计算
zinterstore destkey numkeys key[key...]  --交集计算

命令应用

// 向工资最高的人的有序集合假如三个元素, 每个元素的分值为工资, 紧跟的是人的姓
zadd "工资最高的人" 100000 wang 20000 li 3000 zhao
// 倒序取出所有元素, 排在第一位的便是工资最高的人
zrevrange "工资最高的人" 0 -1

3. 应用场景

① 单日排行榜/微博热搜

点击量490万可以作为ZSet元素的分值score,新闻的id可以作为ZSet元素的element,当新闻被点击一次,我就对对应的新闻id的score进行+1操作,最终正序获取前几个就是热搜。命令使用如下:

// 新闻点击量, key为hotnew:当前日期(年月日)  单日排行榜
// 点击一次, 就加一次, 不存在则创建
zincry hotnews:{date} 1 {newsID}
// 获取前6位作为热搜数据
zrevrange hotnews:{date} 0 5

② 周榜/月榜/年榜

通过ZSet的并集操作即可实现,7天为周榜,4周为月榜,12个月为年棒

以上内容便是Redis在互联网行业的应用,这篇文章应该能帮助你更加理解Redis的数据结构,以及每种数据结构都有什么用处,也拓展了你的见识,面试有可能会问到哦~~

面试干货10——聊一聊Redis的应用吧!(实现分布式锁、缓存、抽奖、热搜、点赞、商品筛选..)相关推荐

  1. redis实现轮询算法_【07期】Redis中是如何实现分布式锁的?

    点击上方"Java面试题精选",关注公众号 面试刷图,查缺补漏 分布式锁常见的三种实现方式: 数据库乐观锁: 基于Redis的分布式锁: 基于ZooKeeper的分布式锁. 本地面 ...

  2. java 通过redis实现倒计时_突破Java面试(42) - Redis amp; ZooKeeper两种分布式锁实现的优劣...

    0 Github 1 面试题 一般实现分布式锁都有哪些方式?使用redis如何设计分布式锁?使用zk来设计分布式锁可以吗?这两种分布式锁的实现方式哪种效率比较高? 2 考点分析 一般先问问你zk,然后 ...

  3. 基于redis集群实现的分布式锁,可用于秒杀,定时器。

    在分布式系统中,经常会出现需要竞争同一资源的情况,使用redis可以实现分布式锁. 前提:redis集群已经整合项目,并且可以直接注入JedisCluster使用: @Autowiredprivate ...

  4. Redis 基础 - 优惠券秒杀《分布式锁(初级)》

    参考 Redis基础 - 基本类型及常用命令 Redis基础 - Java客户端 Redis 基础 - 短信验证码登录 Redis 基础 - 用Redis查询商户信息 Redis 基础 - 优惠券秒杀 ...

  5. 基于Redis(setnx)实现分布式锁

    什么是分布式锁? 分布式锁是控制分布式系统或不同系统之间共同访问共享资源的一种锁实现,如果不同的系统或同一个系统的不同主机之间共享了某个资源时,往往需要互斥来防止彼此干扰来保证一致性. 分布式锁需要具 ...

  6. Redis 实现优惠券秒杀、分布式锁、消费队列

    文章目录 一.全局唯一ID 1.1 为啥需要全局唯一ID 1.2 全局ID生成器 1.3 全局唯一ID生成策略 二.实现优惠卷秒杀下单 2.1 优惠卷表结构 2.2 秒杀功能实现 三.超卖问题 四.实 ...

  7. 【面试题】Redis中是如何实现分布式锁的

    分布式锁常见的三种实现方式: 数据库乐观锁: 基于Redis的分布式锁: 基于ZooKeeper的分布式锁. Redis的分布式锁 Redis要实现分布式锁,以下条件应该得到满足 互斥性:在任意时刻, ...

  8. Redis系列教程(八):分布式锁的由来、及Redis分布式锁的实现详解

    在很多场景中,我们为了保证数据的最终一致性,需要很多的技术方案来支持,比如分布式事务.分布式锁等.那具体什么是分布式锁,分布式锁应用在哪些业务场景.如何来实现分布式锁呢?今天来探讨分布式锁这个话题. ...

  9. 使用 Redis的SETNX命令实现分布式锁

    SETNX命令简介 SETNX key value 将key的值设为value,并且仅当key不存在. 若给定的key已经存在,则SETNX不做任何操作. SETNX 是SET if Not eXis ...

最新文章

  1. 使用内存映射文件来提高你程序的性能
  2. 《JavaScript面向对象精要》——第1章 原始类型和引用类型1.1 什么是类型
  3. 【AOP 面向切面编程】Android Studio 使用 AspectJ 监控方法运行 ( 定义连接点注解 | 定义 Aspect 切面 | 定义切入点 | 逐个处理切入点的各个连接点 )
  4. 操作系统实验报告12:线程2
  5. 自定义parallelStream的thread pool
  6. poj1743 Musical Theme
  7. javascript中的Base64.UTF8编码与解码详解
  8. 蓝桥杯历届试题----分糖果(模拟)
  9. 【云小课】基础服务第25课 容灾演练:平时多练兵,急时保可用!
  10. python如何爬取sci论文_通过爬虫确定SCI期刊的发表周期
  11. 一个人长途自驾旅行需要注意什么?
  12. 整理了10个行业的30份可视化大屏模板,可直接拿走套用
  13. 一元多项式计算器_人教版初中数学七年级上册——去括号、去分母解一元一次方程公开课优质课课件教案视频...
  14. 手机自动化测试IDE --手把手教你用Airtest模拟器来连接手机
  15. 我的世界服务器怎么弄vip系统,我的世界vip插件怎么用?我的世界vip插件使用方法...
  16. php进度台帐管理系统,捷雅途 - 工程量0号台账管理系统快速操作说明
  17. Android 图片裁剪
  18. 齐齐哈尔大学计算机考研论坛,2020年一志愿报考齐齐哈尔大学硕士研究生进入复试的考生名单...
  19. jiathis jia.js Eval 解密 解密出来的代码
  20. 前端基础——数组的方法

热门文章

  1. 三论计算机专业本科该如何学习——三要,三不要
  2. linux mips 启动分析,Linux/MIPS启动分析
  3. 【MySQL】入门基础(一)
  4. centos 自建网盘 nextcloud
  5. 网上图书商城视频教程day03
  6. ES 搜索优化测试 - indexSort 对检索性能提升50%
  7. eoc拨号失败服务器无响应,联通广电EOC合作技术方案建议书
  8. html+css制作扑克牌小胡桃展开特教
  9. 大计基编程题(第十周)
  10. SQL之子查询(2)