Redis-06 Redis面试高频问题、Redis日常开发规避问题

众所周知,使用Redis可极大提升查询效率,也可提供分布式锁解决方案,本章节将根据日常开发中可能出现的实际场景重点讲解使用Redis的架构设计相关问题,以及如何设计高效的分布式锁。

1,缓存穿透

查询缓存和数据库中都没有的数据,导致请求都下沉至数据库,造成数据库压力过大。

常用场景:

1,程序判断机制有误,并发场景下大量查询下沉至数据库;

2,黑客攻击,通过缓存穿透方式打垮数据库,造成系统崩溃。

解决方案:

1,前端程序做限频率

1,后端程序做基本判断。ID<0直接返回;

2,缓存空对象并设置过期时间。可使相同数据第二次请求时快速返回;

3,使用布隆过滤器。通过bitmap将所有对象ID缓存至布隆过滤器,请求先通过布隆过滤器判断对象是否存在,不存在则直接返回,存在再去Redis或数据库拿取数据。

2,缓存击穿

查询缓存中有但数据库没有的数据,导致请求都下沉至数据库,造成数据库压力过大。

常用场景:

1,大批量缓存数据在同一时间或临近时间失效,导致查询下沉;

2,少量缓存数据失效,大并发请求该数据,同样导致查询下沉。

解决方案:

1,查询时为缓存续命,每次查询添加或重置过期时间,引导冷热数据分离;

2,设置缓存的过期时间时,在时间基数上添加随机时间,造成缓存过期时间不同。

3,缓存雪崩

解释一:Redis服务宕机,所有查询直接流向数据库,导致数据压力变大,查询变慢甚至宕机;

解释二:大批量数据在同一时间或临近时间段内失效,后续大量查询流向数据库,导致数据压力变大,查询变慢甚至宕机。

解决方案:同缓存击穿

4,热点key重建优化

常用场景:

某个热点消息或热点商品的缓存过期后,大并发请求查询,可能造成多个线程重建缓存,导致程序和Redis服务压力过大

解决方案:

重建缓存时加分布式锁,并使用双重验证法。

加分布式锁可使得只能有一个线程重建缓存;双重验证可使得其余线程执行时直接从缓存获取。伪代码如下:

java 复制代码
String get(String key) {
    // 从Redis中获取数据
    String value = redis.get(key);
    if (value != null){
        return value;
    }

    // 如果value为空, 则开始重构缓存
    // 只允许一个线程重建缓存, 使用nx, 并设置过期时间ex
    String lockKey = "lock:key:" + key;
    if (redis.set(lockKey , "1", "ex 180", "nx")) {
        
        // 双重验证。从Redis中获取
        value = redis.get(key);

        if (value ==null){
            // 从数据源获取数据
            value = db.get(key);
            // 回写Redis, 并设置过期时间
            redis.setex(key, timeout, value);
        } else {
            // 重置过期时间
            redis.expire(key, timeout);
        }      
        
        // 删除锁
        redis.delete(mutexKey);
    }
    // 其他线程休息50毫秒后重试
    else {
        Thread.sleep(50);
        get(key);
    }

    return value;
}

5,缓存与数据库双写不一致

如下图:线程1在写完数据库后,写Redis前因程序或网络导致延迟,线程2在延迟期间通过数据库查询到该值,更新后写至数据库和Redis。线程1再写Redis时,写入的就是错误的旧值。

解决方案:

使用redisson的读写锁,读写锁对Redis的读读不互斥,读写/写写互斥,保证在同一时刻,只能有一个线程写Redis。

同上例,若使用了读写锁,线程1在写Redis时卡顿,线程2对Redis的写操作将会阻塞,等待线程1写完Redis并释放锁后,线程2才能获取锁再写Redis,保证了Redis数据为最新值。

注意:

1,双写不一致现象为小概率事件。并发量不高的系统,几乎不用考虑;

2,Redis数据一般都会设置过期时间,如果可以容忍短期数据不一致,也不用考虑。

相关推荐
461K.17 分钟前
写spark程序数据计算( 数据库的计算,求和,汇总之类的)连接mysql数据库,写入计算结果
大数据·分布式·spark
每次的天空34 分钟前
Android第三次面试总结之网络篇补充
android·网络·面试
张哈大1 小时前
【 Redis | 实战篇 秒杀优化 】
java·数据库·redis·笔记·缓存
Hello World......3 小时前
互联网大厂Java面试:从Spring到微服务的全面探讨
java·spring boot·spring cloud·微服务·面试·技术栈·互联网大厂
却道天凉_好个秋9 小时前
系统架构设计(九):分布式架构与微服务
分布式·架构·系统架构
predisw12 小时前
kafka connect 大概了解
分布式·kafka
计算机毕设定制辅导-无忧学长14 小时前
RabbitMQ 快速上手:安装配置与 HelloWorld 实践(二)
分布式·rabbitmq·ruby
supingemail14 小时前
面试之 Java 新特性 一览表
java·面试·职场和发展
LDM>W<14 小时前
黑马点评-用户登录
java·redis
啾啾Fun15 小时前
【Java微服务组件】分布式协调P1-数据共享中心简单设计与实现
java·分布式·微服务