Redis的雪崩,击穿,穿透,一致性,预热,key指令

1.缓存雪崩

缓存雪崩是指缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。

解决方案:

  缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
 一般并发量不是特别多的时候,使用最多的解决方案是加锁排队。
 给每一个缓存数据增加相应的缓存标记,记录缓存的是否失效,如果缓存标记失效,则更新数据缓存。

2.缓存穿透

缓存穿透是指缓存和数据库中都没有的数据,导致所有的请求都落到数据库上,造成数据库短时间内承受大量请求而崩掉

解决方案:

  接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
  从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击
  采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对底层存储系统的查询压力

3.缓存击穿

缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。和缓存雪崩不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。

解决方案:

  设置热点数据永远不过期。
  加互斥锁,互斥锁

4.缓存预热

缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!

解决方案:

  直接写个缓存刷新页面,上线时手工操作一下;
  数据量不大,可以在项目启动的时候自动进行加载;
  定时刷新缓存;

5.如何保证缓存与数据库双写时的数据一致性

你只要用缓存,就可能会涉及到缓存与数据库双存储双写,你只要是双写,就一定会有数据一致性的问题,那么你如何解决一致性问题?


微信图片_20200813171647.png

解决方案:

  1.一般来说,就是如果你的系统不是严格要求缓存+数据库必须一致性的话,缓存可以稍微的跟数据库偶尔有不一致的情况,最好不要做这个方案,读请求和写请求串行化,串到一个内存队列里去,这样就可以保证一定不会出现不一致的情况
  2.串行化之后,就会导致系统的吞吐量会大幅度的降低,用比正常情况下多几倍的机器去支撑线上的一个请求。
  3.还有一种方式就是可能会暂时产生不一致的情况,但是发生的几率特别小,就是先更新数据库,然后再删除缓存。

6.Redis key指令

Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如果将它们全部找出来?

 使用keys指令可以扫出指定模式的key列表。

如果这个redis正在给线上的业务提供服务,那使用keys指令会有什么问题?

redis关键的一个特性:redis的单线程的。keys指令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。这个时候可以使用scan指令,scan指令可以无阻塞的提取出指定模式的key列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用keys指令长。

7.Redis异步队列

使用list类型保存数据信息,rpush生产消息,lpop消费消息,当lpop没有消息时,可以sleep一段时间,然后再检查有没有信息,如果不想sleep的话,可以使用blpop, 在没有信息的时候,会一直阻塞,直到信息的到来。
redis可以通过pub/sub主题订阅模式实现一个生产者,多个消费者,当然也存在一定的缺点,当消费者下线时,生产的消息会丢失。

8.Redis如何实现延时队列

 使用sortedset,使用时间戳做score, 消息内容作为key,调用zadd来生产消息,
 消费者使用zrangbyscore获取n秒之前的数据做轮询处理。
9.Redis回收进程
 一个客户端运行了新的命令,添加了新的数据。
 Redis检查内存使用情况,如果大于maxmemory的限制, 则根据设定好的策略进行回收。
 一个新的命令被执行,等等。
 所以我们不断地穿越内存限制的边界,通过不断达到边界然后不断地回收回到边界以下。
 如果一个命令的结果导致大量内存被使用(例如很大的集合的交集保存到一个新的键),不用多久内存限制就会被这个内存使用量超越。
10.redis是单线程的,为什么6.0版本还要引入多线程呢?

为什么redis是设计为单线程

其一是因为redis的设计是io多路复用,即使连接网络处理多io多路复用也可以在内存处理中被忽略
其二多线程模型虽然快但他不可保证执行顺序,并带来了并发读写的问题,
三是redis是基于内存的,多线程的是为了充分利用cpu资源.但对redis来说除了进行备份基本不会涉及到io操作数据读写,读写只发生在内存中,处理速度很快,所以使用多线程技术会很鸡肋

为什么要引入多线程

read/write系统调用在执行期间占用了大量的cpu时间,将其网络读写总成多线程的方式会有很大性能提升,在其最新的几个版本中也加入了被其他线程异步处理的删除操作,因为redis的del命令删除元素特别大在短时间内不可完成,所以引入多线程来进行异步操作

11.redis集群是如何访问的
 客户端是先往集群中的一个节点发,如果命中直接返回,如果不命中,会返回moved指令,然后告知key所在的是哪个节点。
12.redis 的hash扩容过程
 字典有两个表,平时用一个,当扩容的时候在每次添加删除的时候顺带移一个槽去新的表, 
 直到扩容完毕。在查找的时候先去老的找,找不到去新的找。

你可能感兴趣的:(Redis的雪崩,击穿,穿透,一致性,预热,key指令)