首页 > 数据库 >【Redis】什么是缓存击穿 ? 怎么解决

【Redis】什么是缓存击穿 ? 怎么解决

时间:2024-06-03 12:31:21浏览次数:26  
标签:缓存 String Redis 击穿 value jedis key Jedis

缓存击穿(Cache Breakdown)是指缓存中某个热点数据在某一时刻失效,大量并发请求同时查询这个数据,由于缓存失效,这些请求会直接打到数据库,可能导致数据库瞬间负载过高,甚至崩溃。与缓存穿透不同,缓存击穿是针对一个特定的热点数据在高并发场景下的失效问题。

解决缓存击穿的方法

  1. 互斥锁(Mutex)

    • 当缓存失效后,通过加锁机制确保只有一个请求可以访问数据库并重建缓存,其他请求等待缓存重建完成后再从缓存读取数据。
    import redis.clients.jedis.Jedis;
    
    public class CacheBreakdownExample {
        private static final String LOCK_KEY = "lock:key";
    
        public static void main(String[] args) {
            Jedis jedis = new Jedis("localhost");
    
            String key = "hotspot_key";
            String value = jedis.get(key);
    
            if (value == null) {
                // 获取分布式锁
                while (jedis.setnx(LOCK_KEY, "1") == 0) {
                    try {
                        // 锁等待时间
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
    
                // 再次检查缓存,防止重复重建缓存
                value = jedis.get(key);
                if (value == null) {
                    // 从数据库查询数据
                    value = getFromDatabase(key);
                    // 更新缓存并设置过期时间
                    jedis.setex(key, 300, value);
                }
    
                // 释放锁
                jedis.del(LOCK_KEY);
            }
    
            System.out.println("Value: " + value);
            jedis.close();
        }
    
        private static String getFromDatabase(String key) {
            // 模拟数据库查询
            return "database_value";
        }
    }
    
  2. 预热缓存

    • 在缓存即将过期或失效前,提前主动刷新缓存,确保热点数据始终在缓存中,避免大量并发请求直接打到数据库。
    import redis.clients.jedis.Jedis;
    import java.util.concurrent.Executors;
    import java.util.concurrent.ScheduledExecutorService;
    import java.util.concurrent.TimeUnit;
    
    public class CachePrewarmExample {
        private static final String KEY = "hotspot_key";
        private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
    
        public static void main(String[] args) {
            Jedis jedis = new Jedis("localhost");
    
            // 初始化缓存
            String value = getFromDatabase(KEY);
            jedis.setex(KEY, 300, value);
    
            // 定时任务预热缓存
            scheduler.scheduleAtFixedRate(() -> {
                Jedis jedisInner = new Jedis("localhost");
                String newValue = getFromDatabase(KEY);
                jedisInner.setex(KEY, 300, newValue);
                jedisInner.close();
            }, 250, 250, TimeUnit.SECONDS);
    
            // 模拟访问
            String cachedValue = jedis.get(KEY);
            System.out.println("Cached Value: " + cachedValue);
    
            jedis.close();
        }
    
        private static String getFromDatabase(String key) {
            // 模拟数据库查询
            return "database_value";
        }
    }
    
  3. 设置合理的过期时间和使用随机过期时间

    • 为不同的缓存数据设置不同的过期时间,避免大量缓存同时失效。
    • 使用随机过期时间可以防止缓存雪崩(大量缓存同时失效导致的缓存击穿)。
    import redis.clients.jedis.Jedis;
    
    public class RandomExpireExample {
        public static void main(String[] args) {
            Jedis jedis = new Jedis("localhost");
    
            String key = "hotspot_key";
            String value = getFromDatabase(key);
    
            // 设置带有随机性的过期时间
            int expireTime = 300 + (int) (Math.random() * 100);
            jedis.setex(key, expireTime, value);
    
            System.out.println("Value: " + value);
            jedis.close();
        }
    
        private static String getFromDatabase(String key) {
            // 模拟数据库查询
            return "database_value";
        }
    }
    

总结

通过使用互斥锁、预热缓存、设置合理的过期时间以及使用随机过期时间等方法,可以有效防止缓存击穿。结合具体的业务场景,选择适合的方法来预防和解决缓存击穿问题,确保系统在高并发情况下的稳定性和性能。

标签:缓存,String,Redis,击穿,value,jedis,key,Jedis
From: https://blog.csdn.net/hui_zai_/article/details/139317133

相关文章

  • Redis - 实现在线人数统计功能
    一、前言在线人数统计这个功能实现的方式很多,这里说一下常使用的方式:使用Redis的有序集合(zset)实现。核心方法是这四个:zadd、zrangeByScore、zremrangeByScore、zrem。二、实现步骤1.如何认定用户是否在线?认定用户在线的条件一般跟网站有关,如果网站需要登录才能进入,那么这......
  • Redis-目录
    背景:今天是2024.6.2。我在网上搂了500页redis相关的面试题,通过ai整理的提纲。为了方便复习,特此记录,逐章节更新。标题下方有链接的,就是更新好了。Redis基础Redis-Redis为什么快、底层数据结构Redis简介数据类型:String、List、Hash、Set、SortedSet常用命令过期时间设置......
  • Redis5学习笔记之四:高级特性(持久化、订阅、主从复制、缓存穿透和雪崩)
    4.redis高级特性4.1持久化Redis的数据全部在内存里,如果突然宕机,数据就会全部丢失,因此必须有一种机制来保证Redis的数据不会因为故障而丢失,这种机制就是Redis的持久化机制。Redis有两种持久化的方式:快照(RDB文件)和追加式文件(AOF文件)4.1.1RDB在指定的时间间隔内将内......
  • Redis
    Redis(RemoteDictionaryServer),即远程字典服务,是一个开源的使用ANSIC语言编写的、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。Redis的数据结构丰富,支持存储的value类型包括string(字符串)、list(链表)、set(集合)、zset(sortedset--有序集合)和h......
  • Redis设计与实现(一)SDS与C字符串的对比
    sds的定义:每个sds.h/sdshdr结构表示一个SDS值:struct__attribute__((__packed__))sdshdr8{uint8_tlen;/*used*/uint8_talloc;/*excludingtheheaderandnullterminator*/unsignedcharflags;/*3lsboftype,5unusedbits*/char......
  • Redis单线程
    Redis是基于Reactor模式开发的网络事件处理器,这个处理器是单线程的,所以redis是单线程的。为什么它是单线程还那么快呢?主要有以下几个原因:一、纯内存操作由于Redis是纯内存操作,相比于磁盘来说,内存就快得多,这个是Redis快的主要原因。二、多路复用I/O机制(NIO)Re......
  • Linux系统上配置redis开机自启
    Redis开机自启:第一步添加环境变量:命令:vim/etc/profile在结尾添加:exportPATH=$PATH:/usr/local/redis/bin作用是为了后续脚本的启动命令不需写的过长重载环境变量文件:source/etc/profile第二步:编写redis.service节点1:152服务器vim/etc/systemd/system/redis.service添......
  • Redis的分布式缓存问题
    击穿  Redis曾存在的key,由于过期时间而被删除,导致请求跳过redis而访问DB处理方法:不设置过期时间,永远存在使用锁,synchronized、分布式锁布隆过滤器穿透  数据库与redis都不存在的key,由于莫名原因存在大量请求,导致请求跳过redis而访问DB处理方法:数据库不存在,redis也......
  • Redis 高级应用与性能优化
    目录1.Redis集群与高可用性Redis集群介绍高可用性方案与实践2.Redis性能优化与监控性能指标与监控工具Redis的性能优化策略实时监控与故障排查3.Redis实践场景与最佳实践缓存与缓存雪崩、击穿、穿透计数器和限流器的实现分布式锁的应用实际项目中的Redis......
  • Redis集群搭建实战(主从复制、哨兵、集群)
    目录1、安装Redis3.02、主从复制(读写分离)2.1主从架构2.1.1 启动实例2.1.2设置主从2.1.3测试2.2主从从架构2.2.1启动实例2.2.2测试2.3从库只读​编辑2.4复制的过程原理2.5无磁盘复制2.6复制架构中出现宕机情况,怎么办?3、哨兵(sentinel)3.1什么是哨兵3......