java笔记--Redis常见问题

Redis的常见问题:

1、缓存穿透:

缓存穿透就是有人故意搞你,搞一些不存在的key出来,这样肯定不会命中redis了,就会进数据库,数据库又没数据,不会记录到缓存,然后就崩了;

解决方案:

  • 加载空值,通过加载空值的方式,让别人的恶意访问,可以在缓存就被拦住,不进入数据库; 这个却缺点在于大量的空数据可能会导致内存被无效占用,而且短时间内这些key可能就是废的;
  • 布隆过滤器:就是搞一个bitmap,预热数据,将所有的有的key去进行预热加载到布隆过滤器中,通过几次hash算法预热(就是把bitmap中的算出来的位置1),后来的访问,会先经过布隆过滤器,再进入redis访问;如果一个访问的key没法按要求命中bitmap中的1值,那就认为他不在缓存中,就返回空了。

在这里插入图片描述

优点就是解决了大量缓存空值的问题,缺点就是有可能导致误判,(某个key要的这些位,刚好被别的key给置1了)

2、缓存击穿:

缓存击穿就是一个热点key,突然失效,导致大量请求进入数据库;

解决方案:

  • 通过互斥锁的方式,只让第一个获得锁的线程去数据库查数据,然后写入缓存,其他线程先休眠一会儿,再去读缓存;这种方式还行;
  • 设置逻辑过期,就是实际是永久key
3、缓存雪崩:

缓存雪崩就是一堆key设置的过期时间是一样的,某一个时间大量的key过期了,导致大量的请求访问到数据库上;或者redis宕机也会导致这种情况。

解决方案:

  • 第一种的话,就是给每个key的过期时间配上一个随机值,打散不同key的过期时间;
  • 第二种的话,就要看redis的部署机制了,暂时不会
4、双写一致:

这里有两种很有意思的,就是不单单是先删缓存还是先修改数据库的问题;

如果删除了缓存 Redis,还没有来得及写库 MySQL,另一个线程就来读取,发现缓存为空,则去数据库中读取数据写入缓存,此时缓存中为脏数据

如果先写了库,在删除缓存前,写库的线程宕机了,没有删除掉缓存,则也会出现数据不一致情况。就算没有宕机,在数据库完成写操作时,其他线程的读取,也是旧的数据;

弱一致性的解决方案:

延迟双删:

​ 在上面的业务场景中,一个读数据请求,一个写数据请求。当写数据请求把缓存删了之后,读数据请求,可能把当时从数据库查询出来的旧值,写入缓存当中。为了避免这一情况,我们可以在请求在写完数据库之后,把缓存重新删一次(这里需要延时一会儿,因为延时是为了避免我们在第一次的删缓存的时候,读请求进入数据库读的旧数据写到缓存中,这个步奏导致的读脏数据)。这样子的话,后来的读请求总会在写请求完成之后加载最新的数据到缓存中

定时任务:

时不时拉拉数据库的数据来更新缓存中的数据。

消息队列:

利用消息队列的高可用性,删除数据库之后,将消息放入消息队列,让消息队列发消息去完成缓存的更新;

canal中间件:

利用数据库的binlog日志;检测其中的数据更新语句和数据定义语句,如果发生这类事件,就通知缓存更新;

5、持久化

关于持久化,主要有两种机制,RDB和AOF ; 手动刷盘有两个命令 , 一个是save 在主进程将数据刷盘,这种方式的坏处是在刷盘过程中,会影响别的进程进行读取操作 ; 一个是bgsave , 这个是执行fork操作开启一个新的进程去进行刷盘;在bgsave的模式下,读取操作和刷盘操作可以同时进行,这样怎么保证他的一致性,不会出现脏读问题呢? 这里在Redis中采用了CopyAndWrite的方式来进行控制,就是在刷盘的时候,如果有写的请求进来,会先把旧的数据进行一个拷贝,形成一个副本,然后读写操作去操作副本;

RDB是记录系统当前的物理信息,将数据的快照给记录到磁盘中。RDB的刷盘策略是 通过时间和修改次数同时来进行判断是否需要刷盘。 优点:大数据的恢复比AOF快 ; 缺点:在fork过程中产出的写数据,不会记录到快照中,而是在副本里面,这时候如果服务宕机数据就会丢失;

AOF方式工作机制很简单,redis会将每一个收到的写命令都通过write函数追加到文件中。默认情况下Redis没有开启AOF方式的持久化。 AOF的刷盘策略,一个是每次接收到新的写请求,就去刷一次盘,一个是定时刷,比如一秒一次、

6、数据过期策略

这里这个策略是指数据过期了的话,会怎么处理;
一种是懒惰型的,就是只有当访问了某个数据,发现它过期了,redis才将他释放 ; 这个有个致命的坏处就是,如果一个key一直不被访问,那么就会导致它一直占用内存,无法释放。
一种是定时任务,我们每隔一段时间,就去主动对所有的数据,进行一个检查,如果过期了,就进行删除。

7、数据淘汰策略

这里主要是和 Redis内存满了的情况相关;满了才要进行一些淘汰;

Redis内存不足的缓存淘汰策略提供了8种。
noeviction:当内存使用超过配置的时候会返回错误,不会驱逐任何键。 这个是默认的配置;
allkeys-lru:加入键的时候,如果过限,首先通过LRU算法驱逐最久没有使用的键。
volatile-lru:加入键的时候如果过限,首先从设置了过期时间的键集合中驱逐最久没有使用的键。
allkeys-random:加入键的时候如果过限,从所有key随机删除。
volatile-random:加入键的时候如果过限,从过期键的集合中随机驱逐。
volatile-ttl:从配置了过期时间的键中驱逐马上就要过期的键。
volatile-lfu:从所有配置了过期时间的键中驱逐使用频率最少的键。
allkeys-lfu:从所有键中驱逐使用频率最少的键。

LRU:最近最少使用 —看一个时间区间的使用频率 LFU : 最不经常使用 —就是看最后一次是什么时候用

8、分布式锁(AP)

通过setnx 命令实现 , redisson对其进行了优化,完善了很多功能;
关于锁释放的问题,首先肯定要一个过期时间,来避免在宕机的情况下,没有人释放锁。这时候又有新的问题出现了,那就是如果我任务没执行完呢,锁就过期了怎么办? 那肯定是给锁续期 , Redisson就做了一个看门狗的设计,完成对锁的续期任务。每隔(releaseTime/3)就给锁做一次续期; 加锁和设置过期时间等操作都是通过lua脚本完成,这样能保证原子性。

Redisson提供的分布式锁时可以重入的,底层锁的存储是使用了Hash结构 , key 是锁名 filed 是线程名 , value是锁的重入次数;
Redisson提供的分布式锁不能保证主从一致性问题,而是要使用红锁(就是把二分之一以上的redis节点都加上锁),性能不高, 如果真的要保证强一致性的话,可以使用Zookeper 来上锁。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值