黑马java八股文全集
目录
redis篇:
缓存穿透:
缓存击穿:
缓存雪崩:
缓存一致性:
为应对面试,特此开始总结java八股文,此篇长期更新,目标在九月之前刷完黑马八股文
redis篇:
缓存穿透:
缓存穿透是指有人恶意攻击数据库,大量访问不存在的数据,数据库查询不到数据也不会直接写入缓存,就会导致每次都查数据库。
有两种实现方案:
第一种的话是在缓存中缓存空数据,这样当访问打过来的时候可以直接返回null,就不用再走数据库
第二种的话是在缓存之前添加一个布隆过滤器,布隆过滤器主要是判断一个元素在不在集合当中,当时用的是redisson实现的布隆过滤器,他是首先会初始化一个大数组,将数组都置为0,然后将缓存的数据根据3次哈希值的计算,对数组取模然后找到数组的下标,将数组的0变为1,然后你要查询的话就可以根据三次哈希值计算计算出数组的下标然后查找出存不存在这个元素,但是也是有缺点的,就是会有误判率,但是一般我们的误判率不会超过百分之一,这样项目也能承受这种并发
缓存击穿:
给一个热点key设置了过期时间,当key过期时刚好有大量并发请求过来,这样的请求就会压垮数据库
有两种解决方案:
第一种就是分布式锁,当一个线程进来之后会获取这个分布式锁,获取到锁之后在数据库重建缓存数据,然后写入缓存,最后释放锁,然后这时候如果有别的请求进来的话首先会获取锁,但是由于另一个线程已经获取到锁了,这个线程就会获取锁失败。然后这个线程会一直尝试获取锁,当缓存写入完成并且释放锁之后,这个线程才会命中数据
第二种的话是逻辑过期,就是给数据维护一个过期时间的字段,然后线程进来会判断这个字段是不是会过期,如果过期的话会获取一个分布式锁,然后在本线程新开一个线程并且在本线程直接返回旧数据,让新线程重建缓存数据然后同步到缓存,然后释放锁,在这个线程获取锁到释放锁之前别的线程会直接返回旧数据,等到缓存重建完成并且释放锁后会返回新数据
分布式锁的解决方案一致性比较强,逻辑过期解决方案对性能要求高
缓存雪崩:
缓存雪崩是同一时间大量key过期或者Redis服务宕机,导致大量请求压垮数据库
有四种解决方案:
第一种是给不同的key设置不同的过期时间
第二种是降级限流策略
第三种是给Redis设置集群模式,哨兵模式
第四种是给业务添加多级缓存
缓存三兄弟可以都可以用限流作为保底策略
缓存一致性:
当修改了数据库的数据同时也要更新缓存的数据,缓存和数据库的数据要保持一致
读数据:缓存命中直接返回,缓存没有命中查询数据库,如果有查询数据库并写入缓存
无论是先修改数据库还是先删除缓存都会让数据库,有脏数据的风险
所以有三种解决放案
第一种是分布式锁在读的时候添加共享锁(readlock),加锁之后其他线程可以共享读操作,但是不允许写操作,然后在写数据的时候添加排他锁(writelock),会阻塞其他线程读写操作
第二种是通过mq当写入数据库数据的时候通过mq在两个服务之间去发布消息然后监听消息去更新缓存(需要保证mq的可靠性),对于业务代码有侵入
第三种是通过阿里的Canal进行异步通知,是通过mysql的主从同步来实现的,canal可以监听mysql的binlog日志,当数据库写入数据的时候canal可以通知数据变更情况然后更新缓存,这种对业务代码零侵入
以上是redis和mysql的数据进行同步的方案,强一致性的的方案就是加共享锁(读的时候禁止写)和排他锁(写的时候禁止读和写),异步的方式就是通过mq去监听数据库然后推送消息更新缓存,但是这种对业务代码有侵入,还有一种是通过canal的方式进行监听mysql的binlog(二进制日志),然后通知数据变更情况更新缓存