Redis面试汇总笔记

       在两个月前的学习中,我看过一个redis相关的讲解视频,是一个叫诸葛的老师,其中分为几层进行讲述,分别是数据类型、分布式锁、redis常见问题等。当时有记录一些内容,下面将按照顺序进行分享。

(一)常见的数据类型

       结合视频的内容,通过一张结构图来展示各个数据类型之间的关系:
在这里插入图片描述
       常见的数据类型一般都是图上的几种:String、Hash、List、Set、有序集合Set。

(1)String

常用操作
1)字符串常用操作

set key value;
mset key valye [key value …]; //批量存储字符串键值对
setnx key value; //存入一个不存在的字符串键值对
get key [key …];
del key [key …];
expire key seconds //设置一个键的过期时间

2)原子加减

incr key //将key中存储的数字加1
decr key //将key中存储的数字减1
incrby key increment //将key所存储的值加上increment
decrby key decrement //将key所存储的值减去decrement

3)分布式锁

setnx [key] true //返回1代表取锁成功,返回0代表获取锁失败
del [key] //释放锁,即删除锁
set [key] true ex 10nx //防止程序意外终止导致死锁,即设置过期时间

同时还可以存储对象数据,不过需要将对象数据转Json数据格式。

应用场景
1)计数器

incr article:readcount:{文章id} //针对文章id的阅读值,做原子性的+1操作
get article:readcount:{文章id} //获取阅读数

2)分布式系统全局序列号

increby orderid 100 //redis批量生成序列号提升性能
解释:一次操作取100个编号,利用自增部分来使用编号。从性能角度分析,原来是操作100次redis进行取值,现在只需要操作一次,从而实现性能提升。

(2)Hash

常用操作:

hset key field value //存储一个hash表key的值
hsetnx key key field value //存储一个不存在的hash表的值
hmset key field value [field value …] //在一个哈希表中存储多个键值对
hget key field //获取哈希表中key对应的field键值
hmget key field [key field …] //批量获取哈希表中的key对应的多个field键值
hdel key field [field …] //删除
hlen key //返回哈希表中key对应的field的数量
hgetall key //返回哈希表中key中所有的键值
hincrby key field increment //为哈希表中的key的field键的值加上增量increment

应用场景:
1)电商购物车

①以用户id为key
②商品id为field
③商品数量为value

2)购物车操作

①添加商品->hset cart:1001 10088 1
②增加数量->hincrby cart:1001 10088 1
③商品总数->hlen cart:1001
④删除商品->hdel cart:1001 10088
⑤获取购物车所有商品->hgetall cart:1001

(3)List

常用操作:

lpush key value [value …] //将一个或多个值value插入key列表的表头(最左边)
rpush key valye [value …] //将一个或多个值value插入key列表的表胃(最右边)
lpop key //移除并返回key列表的头元素
rpop key //移除并返回key列表的尾元素
lrange key start top //返回列表key中指定区间内的元素,区间以偏移量start和stop指定。(分正向索引和负向索引)
blpop key [key …] timeout //从key列表表头弹出一个元素,若列表中没有元素,阻塞等待timeout秒,如果timeout=0,一直阻塞等待
brpop key [key …] timeout //从key列表表尾弹出一个元素,若列表中没有元素,阻塞等待timeout秒,如果timeout=0,一直阻塞等待

常用的分布式数据结构:

Stack(栈) = lpush + lpop = FILO
Queue(队列) = lpush + rpop = FIFO
Blocking MQ(阻塞队列) = lpush + brpop

应用场景:
1)微博和微信公众号消息流
       诸葛老师关注了Caoz,备胎说车等大V。
①CaoZ发微博,消息id为10018

lpush msg:{诸葛老师-ID} 10018

②备胎说车发微博,消息id为10086

lpush msg{诸葛老师-id} 10086

③查看最新微博消息

lrange msg:{诸葛老师-id} 0 4

解释:可能存在关注同一个人,但是接收到新推送的消息存在延迟,因为底层实现排队发送,比如优先发送在线人员,在发送不在线的。

(4)Set

常用操作:
(后续补充)

应用场景:
1)抽奖程序(微信小程序等)

2)微信微博点赞、收藏、标签

3)集合操作实现电商商品筛选

集合的运算(实现关注模型)
1)交集
{a,b,c} {a,c} => {a,c}
2)差集
{a,b,c} {b,d,f,g} => {a,c}
3)并集
{a,b,c} {c,d,f,g} => {a,b,c,d,f,g}

(5)有序Set

常用操作:
(后续补充)

应用场景:
1)实现热榜排行前十等

底层实现结构:
1)压缩列表
(后续补充)

2)跳表
       当压缩列表达到一个大小时,会从压缩列表转化为跳表。跳表结构有点类似mysql底层数据结构,B+tree,即冗余排好序的序号作为结点头部,利用多路查询树的结构进行设计。

(二)分布式锁

(1)基于原生的redis命令setnx

       在redis中,基于setnx命令的操作,就可以实现分布式锁相关业务,与在Java中的redistemplate中是使用setIfAbsent是一致的。

(2)基于redission组件

       该组件就是基于一系列的分布式场景设置了许多类型的锁,比如基础的同步锁,读写锁等,读者可以自行探讨。
分布式锁的设计理念:
①对缓存内存进行设置(单值设置,如果存在多个线程进行设置时,只有一个线程能设置成功,其他线程失败);
②设置缓存失效时间;(解决因程序出错,导致死锁的问题)
③通过lua代码实现一个锁续命操作,底层成为看门狗,负责检测当前锁是否失效,如果没有,则重新设置锁的过期时间;注:lua代码的执行是一个原子性操作,意味着有么就全部操作正常,要么就全部操作失败;(确保原子性)

(三)缓存问题

       当业务代码涉及到先查询缓存,如果存在,则取出redis中的缓存值,并且返回,否则查询数据库,取到对应内容,再设置到缓存中,并且返回,此时就会出现下述前三个问题。

(1)缓存击穿(缓存失效)

解释:也叫热点Key问题,就是一个被高并发访问并且缓存重建业务较复杂(意味着对数据库压力相对较大)的key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的压力,导致数据库服务挂掉(可以理解为redis的缓存暂时没有,此时高并发情况下,所有线程进到接口时,都会判断当前redis缓存不存在,因此会有大量的请求访问数据库)。
解决方法:
1、互斥锁:当同个业务不同线程访问redis未命中时,先获取一把互斥锁,然后进行数据库操作,此时另外一个线程未命中时,拿不到锁,等待一段时间后重新查询缓存,此时之前的线程已经重新把数据加载到redis之中了,线程二就直接缓存命中。这样就不会使得大量访问进入数据库。

(2)缓存穿透

解释:有一个商品被删掉了,但是在高并发情况下,首先去检查缓存,此时发现缓存没有,就去查询数据库,此时还是查询不到,然后就返回不了任何数据。
解决方案:当查询到数据库发现不存在时,可以设置一个空值,就可以避免所有请求直接访问数据库,减轻数据库压力。

(3)缓存雪崩

解释:当缓存在同一时间内大部分失效,此时导致所有的请求访问接口时,会同时访问数据库,造成数据库服务访问压力过大。
解决方法:在设置过期时间时,利用固定时间+随机数时间进行设置,避免同一时间大面积缓存失效。

(4)缓存和数据库双写不一致的问题

(后续补充)

(5)缓存数据冷热分离

解释:由于redis的资源有限,不可能将所有的数据都防止缓存中,因此只需要装热数据缓存在redis中即可,冷数据失效。具体实现原理为设置缓存过期时间即可。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值