1、我看你做的项目中,都用到了redis,你在最近的项目中哪些场景使用了redis呢?
2、缓存穿透
布隆过滤器的误判现象
Redisson和Guava都对布隆过滤器进行了实现
3、缓存击穿
互斥锁,就是一个线程来修改,并占据了锁,另外其他的线程想要访问必须拿到锁,否则就休眠重试,等到修改线程结束后把锁释放了,缓存中也就有新的数据,这个时候其他线程也可以拿到数据了。
设置逻辑过期,没有那么的强一致性,但是整体性能 很高,先让线程去拿老的数据,另外开一个线程去更新数据,其他线程来了也会第一时间拿到老的数据
4、缓存雪崩
5、MySQL怎么跟Redis保持一致?
第一种方式:延时双删
先删除缓存,还是先修改数据库?都会有问题
先删缓存在改数据库的情况
正常情况:
异常情况:初始: 缓存是20,数据库是10,线程1是修改操作,线程1先把20的缓存删除掉了,线程2查询不到缓存,接着查数据库查到了10,把10写入到了缓存中,然后线程2又把数据库给更新为20,现在缓存是10,数据库却是20
先操作数据库再删缓存的情况
正常情况
异常情况:
延时的原因是因为数据库是主从的,延时一段时间保证从库已经完成了主库发来的更改
第二种方案 可以使用共享锁+排他锁的方案来解决缓存一致性的问题
第三种方案 异步通知保证数据的最终一致性
6、Redis的持久化
7、Redis的过期策略
惰性删除
定期删除
8、Redis的数据淘汰策略
9、分布式锁
分布式锁的使用场景:集群情况下的定时任务、抢单、幂等性等场景
lock.tryLock(第一个参数表示等待锁的最大尝试时间,第二个参数表示锁的自动释放时间(此时看门狗就不会生效了,因为redisson认为你自己有控制锁时长的能力,第三个参数是时间单位)),加锁、设置过期时间等操作都是基于LUA脚本完成的
9.1、Redisson是可重入锁吗?
10、Redis的集群方案
11、Redisson获取锁的源码分析
11.1、redissonClient.getLock
getLock的过程就是对底层的数据做一些准备工作,这个时候锁还没有放到redis中去
11.2、lock.lock()
执行完lua脚本后,在redis里就有锁了
11.3、锁的续期
看门狗续期
每 过期时间/3 时间段过后,就会对锁进行一个续期
11.4、锁的释放
11.5、Redisson是可重入锁吗?
第一次上锁redis中的状态:
第二次上锁redis中的状态:
然后第一次释放锁:
然后第二次释放锁:
11.6、实现分布式锁需要注意哪些问题?
11.6.1、不是原子操作
获取锁+设置过期时间写成一行
11.6.2、没有释放锁
设置过期时间 + 手动释放来保证锁一定会被释放
11.6.3、释放了锁,但是业务还没执行完
锁过期时间30s,但是业务执行了35s,另外的线程就可以拿到锁,可能造成数据的不一致
业务没执行完,就续期
11.6.4、释放了别人的锁
- 可以加锁的时候给key加一个UUID
- 释放锁之前判断是否还是当前线程
-
if (lock.isHeldByCurrentThread()) { lock.unlock(); }
11.6.5、大量请求竞争锁失败
- 重试
- 让业务执行时间尽可能短
- 限流