1.Redis脑裂问题

1.什么是集群脑裂 

 Redis的集群脑裂是指因为网络问题,导致Redis Master节点跟Redis slave节点和Sentinel集群处于不同的网络分区,此时因为sentinel集群无法感知到master的存在,所以将slave节点提升为master节点。

注意:

此时存在两个不同的master节点,就像一个大脑分裂成了两个。集群脑裂问题中,如果客户端还在基于原来的master节点 继续写入数据,那么新的Master节点将无法同步这些数据,当网络问题解决之后,sentinel集群将原先的Master节点降为slave节点,此时再从新的master中同步数据,将会造成大量的数据丢失。

2.解决方案

 redis.conf配置参数:

min-replicas-to-write 1

min-replicas-max-lag 5

参数:

第一个参数表示最少的slave节点为1个 第二个参数表示数据复制和同步的延迟不能超过5秒

 2.Redis缓存预热问题

1.缓存冷启动 

 缓存中没有数据,由于缓存冷启动一点数据都没有,如果直接就对外提供服务了,那么并发量上来Mysql就裸奔挂掉了。

 

 2.解决思路

提前给redis中灌入部分数据,再提供服务 如果数据量非常大,就不可能将所有数据都写入redis,因为数据量太大了,第一是因为耗费的时间太长了,第二根本redis容纳不下所有的数据 需要根据当天的具体访问情况,实时统计出访问频率较高的热数据 然后将访问频率较高的热数据写入redis中,肯定是热数据也比较多,我们也得多个服务并行读取数据去写,并行的分布式的缓存预热

 3.Redis缓存穿透问题

 缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。

1.解决方案 

对空值缓存:如果一个查询返回的数据为空(不管数据是否存在),我们仍然把这个空结果缓存,设置空结果的过期时间会很短,最长不超过5分钟。 布隆过滤器:如果想判断一个元素是不是在一个集合里,一般想到的是将集合中所有元素保存起来,然后通过比较确定。

2.布隆过滤器 

 布隆过滤器是一种数据结构,比较巧妙的概率型数据结构(probabilistic data structure),特点是高效地插入和查询,可以用来告诉你 “某样东西一定不存在或者可能存在”。

注意:

布隆说不存在一定不存在,布隆说存在你要小心了,它有可能不存在

使用布隆过滤器必须引入依赖

  cn.hutool

  hutool-all

  5.7.17

 4.Redis缓存击穿问题

 某一个热点 key,在缓存过期的一瞬间,同时有大量的请求打进来,由于此时缓存过期了,所以请求最终都会走到数据库,造成瞬时数据库请求量大、压力骤增,甚至可能打垮数据库。

 1.解决方案

互斥锁:在并发的多个请求中,只有第一个请求线程能拿到锁并执行数据库查询操作,其他的线程拿不到锁就阻塞等着,等到第一个线程将数据写入缓存后,其他线程直接查询缓存。 热点数据不过期:直接将缓存设置为不过期,然后由定时任务去异步加载数据,更新缓存(不咋靠谱)

2.代码实现 

 理念是对的,但是满足不了的企业的实际需求

public String get(String key) throws InterruptedException {

      String value = jedis.get(key);

      // 缓存过期

      if (value == null){

          // 设置3分钟超时,防止删除操作失败的时候 下一次缓存不能load db

          Long setnx = jedis.setnx(key +"mutex", "1");          

jedis.pexpire(key + "mutex", 3 *60);

          // 代表设置成功

          if (setnx == 1){

              // 数据库查询

              //value = db.get(key);

              //保存缓存

              jedis.setex(key,3*60,"");

              jedis.del(key + "mutex");

              return value;

          }else {

              // 这个时候代表同时操作的其他线程已经load db并设置缓存了。 需要重新重新获取缓存

              Thread.sleep(50);

              // 重试

              return get(key);

          }

      }else {

          return value;

      }

}

5.Redis缓存雪崩问题 

缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB(数据库),DB瞬时压力过重雪崩。

1.解决方案 

过期时间打散:既然是大量缓存集中失效,那最容易想到就是让他们不集中生效。可以给缓存的过期时间时加上一个随机值时间,使得每个 key 的过期时间分布开来,不会集中在同一时刻失效。 热点数据不过期:该方式和缓存击穿一样,也是要着重考虑刷新的时间间隔和数据异常如何处理的情况。 加互斥锁: 该方式和缓存击穿一样,按 key 维度加锁,对于同一个 key,只允许一个线程去计算,其他线程原地阻塞等待第一个线程的计算结果,然后直接走缓存即可 开启二级缓存:让nginx作为一级缓存·,另外使用其它缓存工具作为二级缓存,让他们存相同的数据,存储时间不同,这样就解决了。

6.Redis数据一致性问题 

 缓存已经在项目中被广泛使用,在读取缓存方面,大家没啥疑问, 都是按照下图的流程来进行业务操作。

 

缓存说明:

从理论上来说,给缓存设置过期时间,是保证最终一致性的解决方案。

三种更新策略

先更新数据库,再更新缓存 先删除缓存,再更新数据库 先更新数据库,再删除缓存

 先更新数据库,再更新缓存

线程安全角度 ,同时有请求A和请求B进行更新操作,那么会出现

(1)线程A更新了数据库

(2)线程B更新了数据库

(3)线程B更新了缓存

(4)线程A更新了缓存

这就出现请求A更新缓存应该比请求B更新缓存早才对,但是因为网络等原因,B却比A更早更新了缓存。这就导致了脏数据,因此不考虑。

先删缓存,再更新数据库

该方案会导致不一致的原因是。同时有一个请求A进行更新操作,另一个请求B进行查询操作。那么会出现如下情形:

(1)请求A进行写操作,删除缓存

(2)请求B查询发现缓存不存在

(3)请求B去数据库查询得到旧值

(4)请求B将旧值写入缓存

(5)请求A将新值写入数据库

 注意: 该数据永远都是脏数据。

 先更新数据库,再延时删缓存

 

(1)请求A进行删除缓存,然后去更新数据库

(2) 请求B查询发现缓存不存在了

(3)请求B去数据库查询得到新值

(4)请求B或请求A将新值写入缓存

好文推荐

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。