缓存穿透:大量查询数据库中不存在的数据,穿透redis到数据库中查询,导致数据库压力大,可以用布隆过滤器解决
缓存击穿:热门key过期,对于热点key的大量查询需要回数据库中查询,导致数据库崩溃,可以调整热点key的存活时间或者使用锁来解决问题
缓存雪崩:短时间内大量key值过期,大量查询需要回到数据库中查询,导致数据库压力大,redis压力大,应用压力大,恶性循环直到全部崩溃,可以通过将key值得存活时间设置为随机,这样就不会短时间内有大量key值过期
分布式锁:分布式情况下,而进程之间甚至可能都不在同一台物理机上,因此需要将标记存储在一个所有进程都能看到的地方,一个数据库正常上锁没办法让其他分布式数据库也上锁,所以我们需要分布式锁,redis可以被所有数据库共同使用,所以这里介绍如何通过redis实现分布式锁:使用set nx ex
这有两种问题:
问题一:锁过期释放了,业务还没执行完。假设线程a获取锁成功,一直在执行临界区的代码。但是100s过去后,它还没执行完。但是,这时候锁已经过期了,此时线程b又请求过来。显然线程b就可以获得锁成功,也开始执行临界区的代码。那么问题就来了,临界区的业务代码都不是严格串行执行的啦。
问题二:锁被别的线程误删。假设线程a执行完后,去释放锁。但是它不知道当前的锁可能是线程b持有的(线程a去释放锁时,有可能过期时间已经到了,此时线程b进来占有了锁)。那线程a就把线程b的锁释放掉了,但是线程b临界区业务代码可能都还没执行完呢。(可以通过将key的value设为每个线程的uuid,判断自身uuid和key的uuid,如果uuid不同就不能释放锁
问题三:但是这里判断与删除没有原子性,也有可能正要释放,但是时间到了自动释放,被其他线程抢了锁,你释放就会把其他线程的锁给释放了,可以用lua脚本解决)
redis实现分布式锁演变过程:
1.SETNX加锁 + EXPIRE设置过期时间:没有原子性
2.set < key> < value> nx ex < time>:解决加锁和设置过期时间的原子性,存在问题一,问题二
3.set < key> < uuid> nx ex < time>:解决问题二,问题一,问题三
4.set < key> < uuid> nx ex < time>+lua完成(判断加删除):解决问题三,存在问题一
5.开源框架Redisson:只要线程一加锁成功,就会启动一个watch dog看门狗,它是一个后台线程,会每隔10秒检查一下,如果线程1还持有锁,那么就会不断的延长锁key的生存时间。因此,Redisson就是使用Redisson解决了锁过期释放,业务没执行完问题,解决问题一
6.Redisson+Redlock:1到5都是单机redis实现分布式锁,redlock可以通过集群实现分布式锁,规则如下:
i.按顺序向5个master节点请求加锁根据设置的超时时间来判断,是不是要跳过该master节点。
ii.如果大于等于三个节点加锁成功,并且使用的时间小于锁的有效期,即可认定加锁成功啦。
iii.如果获取锁失败,解锁!