redis开发中的常见问题-缓存穿透-缓存雪崩-redis脑裂

redis开发中的常见问题-缓存穿透-缓存雪崩-redis脑裂-缓存击穿


前言

在我们日常的开发中,无不都是使用数据库来进行数据的存储,由于一般的系统任务中通常不会存在高并发的情况,所以这样看起来并没有什么问题,可是一旦涉及大数据量的需求,比如一些商品抢购的情景,或者是主页访问量瞬间较大的时候,单一使用数据库来保存数据的系统会因为面向磁盘,磁盘读/写速度比较慢的问题而存在严重的性能弊端,一瞬间成千上万的请求到来,需要系统在极短的时间内完成成千上万次的读/写操作,这个时候往往不是数据库能够承受的,极其容易造成数据库系统瘫痪,最终导致服务宕机的严重生产问题。为了克服上述的问题,项目通常会引入NoSQL技术,这是一种基于内存的数据库,并且提供一定的持久化功能。


redis技术就是NoSQL技术中的一种,但是引入redis又有可能出现缓存穿透,缓存雪崩、缓存击穿等问题。本文就对这几种问题进行较深入剖析

一、Redis的缓存穿透

什么是缓存穿透 ?

简单的说就是获取数据的时候后 先去redis找数据 结果没找到 又去MySQL中找数据 结果还是没有找到 这样的话 那么 每一个线程进来都要去访问数据库、这样的话数据库的压力就很大 数据库就会奔溃 这种现象就叫做 缓存穿透
在这里插入图片描述

二、Redis下的缓存雪崩

在这里插入图片描述

三、Redis的脑裂问题

在这里插入图片描述
客户端向主服务器写入了数据 但是主服务器还没有来得及同步的情况下 主服务器死了 那么这个时候就会选举新的主服务器 原来的主服务器在一段时间之后 又好了 那么这个时候 原来的主服务器 只能作为从服务器了 原来主服务器的数据 没有办法进行同步 这种问题 就是redis的脑裂问题

解决方案

min-slaves-to-write 1 这个表示的意思是:在我们客户端写入数据的时候 至少保证 主服务器上有一个从服务器 处于正常连接才能写入这个数据

min-slaves-max-lag 10 :这个表示的的意思是 主从同步的时间 10s

四、缓存击穿

这里需要注意和缓存穿透的区别。缓存击穿,是指一个 key 非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个 key 在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。

当某个 key 在过期的瞬间,有大量的请求并发访问,这类数据一般是热点数据,由于缓存过期,会同时访问数据库来查询最新的数据,并回写缓存,会导致数据库瞬间压力过大。

解决方案:
1、设置热点数据永不过期
从缓存层来看,没有设置过期时间,所以不会出现热点 key 过期后产生的问题。

2、加互斥锁

分布式锁:使用分布式锁,保证对于每个 key 同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限,因此只需要等待即可。这种方式将高并发的压力转移到了分布式锁,因对分布式锁的考验很大。
在这里插入图片描述

JAVA代码实现

 static Lock reenLock = new ReentrantLock();
    public String findPubConfigByKey1(String key) throws InterruptedException {
    
    
        PubConfig result = new PubConfig();
        // 从缓存读取数据
        result = redisService.getObject(PubConfigKeyConstants.TABLE_NAME + "_"+key, PubConfig.class) ;
        if (result== null ) {
    
    
            if (reenLock.tryLock()) {
    
    
                try {
    
    
                    System.out.println("拿到锁了,从DB获取数据库后写入缓存");
                    // 从数据库查询数据
                    result = pubConfigRepository.queryPubConfigInfoByKey(key);
                    // 将查询到的数据写入缓存
                    Gson g = new Gson();
                    String value = g.toJson(result);
                    redisService.setNx(PubConfigKeyConstants.TABLE_NAME + "_"+key, value);
                } finally {
    
    
                    reenLock.unlock();// 释放锁
                }
 
            } else {
    
    
                // 先查一下缓存
                result = redisService.getObject(PubConfigKeyConstants.TABLE_NAME + "_"+key, PubConfig.class) ;
                if (result== null) {
    
    
                    System.out.println("我没拿到锁,缓存也没数据,先小憩一下");
                    Thread.sleep(100);// 小憩一会儿
                    return findPubConfigByKey1(key);// 重试
                }
            }
        }
        return result.getValue();
    }

总结

针对业务系统,永远都是具体情况具体分析,没有最好,只有最合适。

于缓存其它问题,缓存满了和数据丢失等问题,大伙可自行学习。最后也提一下三个词LRU、RDB、AOF,通常我们采用LRU策略处理溢出,Redis的RDB和AOF持久化策略来保证一定情况下的数据安全。

原文链接:https://blog.csdn.net/fan521dan/article/details/104782315?spm=1001.2014.3001.5501

猜你喜欢

转载自blog.csdn.net/qq_38055805/article/details/122445780