Redis(81)Redis的缓存雪崩是什么?

作者:Victor356日期:2025/10/24

缓存雪崩的概念

缓存雪崩(Cache Avalanche)是指在某一时间段内,缓存中的大量数据同时过期,或者由于缓存服务器宕机导致大量请求直接打到数据库,导致数据库瞬时压力剧增,甚至可能导致数据库崩溃。

解决缓存雪崩的方法

为了解决缓存雪崩问题,可以采取以下几种策略:

  1. 缓存数据的过期时间设置为随机值:避免在同一时间大量缓存数据同时失效。
  2. 加锁或队列:在缓存失效时,通过机制控制对数据库的访问,避免大量请求同时打到数据库。
  3. 双写策略:更新缓存的同时也更新数据库,保证数据的一致性。
  4. 数据预热:在系统启动时,预先将一些热点数据加载到缓存中,防止缓存雪崩。

解决方法及详细代码示例

以下是几种具体的解决方法及示例代码:

1. 缓存数据的过期时间设置为随机值

通过设置随机的过期时间,可以避免大量缓存数据在同一时间失效。

示例代码:

1import redis.clients.jedis.Jedis;
2
3public class CacheAvalancheExample {
4    private Jedis jedis;
5
6    public CacheAvalancheExample(Jedis jedis) {
7        this.jedis = jedis;
8    }
9
10    public void setCachedData(String key, String value, int baseExpTime) {
11        int expTime = baseExpTime + (int)(Math.random() * baseExpTime); // 随机过期时间
12        jedis.setex(key, expTime, value);
13    }
14
15    public String getCachedData(String key) {
16        return jedis.get(key);
17    }
18
19    public static void main(String[] args) {
20        Jedis jedis = new Jedis("localhost", 6379);
21        CacheAvalancheExample cache = new CacheAvalancheExample(jedis);
22
23        String key = "dataKey";
24        String value = "dataValue";
25        int baseExpTime = 3600; // 基础过期时间 1 小时
26
27        cache.setCachedData(key, value, baseExpTime);
28
29        String cachedValue = cache.getCachedData(key);
30        System.out.println("Cached Value: " + cachedValue);
31
32        jedis.close();
33    }
34}
35

2. 加锁或队列

通过加锁或者队列的方式,控制缓存失效时对数据库的访问,避免大量请求同时打到数据库。

示例代码:

1import redis.clients.jedis.Jedis;
2import redis.clients.jedis.params.SetParams;
3
4public class CacheAvalancheWithLockExample {
5    private Jedis jedis;
6
7    public CacheAvalancheWithLockExample(Jedis jedis) {
8        this.jedis = jedis;
9    }
10
11    public String getCachedData(String key, DataProvider provider, int cacheTime) {
12        String value = jedis.get(key);
13        if (value != null) {
14            return value;
15        }
16
17        String lockKey = key + ":lock";
18        String requestId = String.valueOf(Thread.currentThread().getId());
19
20        // 尝试加锁
21        boolean locked = tryGetLock(lockKey, requestId, 30000); // 锁定30秒
22        if (locked) {
23            try {
24                value = provider.getData();
25                if (value != null) {
26                    jedis.setex(key, cacheTime, value);
27                }
28            } finally {
29                releaseLock(lockKey, requestId);
30            }
31        } else {
32            // 等待一段时间后重试
33            try {
34                Thread.sleep(100);
35            } catch (InterruptedException e) {
36                e.printStackTrace();
37            }
38            return getCachedData(key, provider, cacheTime);
39        }
40        return value;
41    }
42
43    private boolean tryGetLock(String lockKey, String requestId, int expireTime) {
44        SetParams params = new SetParams().nx().px(expireTime);
45        String result = jedis.set(lockKey, requestId, params);
46        return "OK".equals(result);
47    }
48
49    private void releaseLock(String lockKey, String requestId) {
50        if (requestId.equals(jedis.get(lockKey))) {
51            jedis.del(lockKey);
52        }
53    }
54
55    public interface DataProvider {
56        String getData();
57    }
58
59    public static void main(String[] args) {
60        Jedis jedis = new Jedis("localhost", 6379);
61        CacheAvalancheWithLockExample cache = new CacheAvalancheWithLockExample(jedis);
62
63        String key = "dataKey";
64        int cacheTime = 3600; // 缓存 1 小时
65
66        String value = cache.getCachedData(key, () -> {
67            // 模拟数据库查询
68            return "dataValue";
69        }, cacheTime);
70
71        System.out.println("Cached Value: " + value);
72
73        jedis.close();
74    }
75}
76

3. 双写策略

更新数据库的同时也更新缓存,可以保证缓存的一致性,减小缓存失效的几率。

示例代码:

1import redis.clients.jedis.Jedis;
2
3public class CacheAvalancheWithDoubleWriteExample {
4    private Jedis jedis;
5
6    public CacheAvalancheWithDoubleWriteExample(Jedis jedis) {
7        this.jedis = jedis;
8    }
9
10    public void updateData(String key, String value, int cacheTime) {
11        // 更新数据库
12        updateDatabase(key, value);
13
14        // 更新缓存
15        jedis.setex(key, cacheTime, value);
16    }
17
18    private void updateDatabase(String key, String value) {
19        // 模拟数据库更新操作
20        System.out.println("Database updated: " + key + " = " + value);
21    }
22
23    public String getCachedData(String key) {
24        return jedis.get(key);
25    }
26
27    public static void main(String[] args) {
28        Jedis jedis = new Jedis("localhost", 6379);
29        CacheAvalancheWithDoubleWriteExample cache = new CacheAvalancheWithDoubleWriteExample(jedis);
30
31        String key = "dataKey";
32        String value = "dataValue";
33        int cacheTime = 3600; // 缓存 1 小时
34
35        cache.updateData(key, value, cacheTime);
36
37        String cachedValue = cache.getCachedData(key);
38        System.out.println("Cached Value: " + cachedValue);
39
40        jedis.close();
41    }
42}
43

4. 数据预热

在系统启动时预先将一些热点数据加载到缓存中,可以有效防止缓存雪崩。

示例代码:

1import redis.clients.jedis.Jedis;
2
3public class CacheWarmUpExample {
4    private Jedis jedis;
5
6    public CacheWarmUpExample(Jedis jedis) {
7        this.jedis = jedis;
8    }
9
10    public void warmUpCache() {
11        // 预先加载热点数据到缓存中
12        String key = "hotKey";
13        String value = "hotValue";
14        int cacheTime = 3600; // 缓存 1 小时
15        jedis.setex(key, cacheTime, value);
16
17        System.out.println("Cache warmed up: " + key + " = " + value);
18    }
19
20    public String getCachedData(String key) {
21        return jedis.get(key);
22    }
23
24    public static void main(String[] args) {
25        Jedis jedis = new Jedis("localhost", 6379);
26        CacheWarmUpExample cache = new CacheWarmUpExample(jedis);
27
28        cache.warmUpCache();
29
30        String key = "hotKey";
31        String cachedValue = cache.getCachedData(key);
32        System.out.println("Cached Value: " + cachedValue);
33
34        jedis.close();
35    }
36}
37

总结

通过以上示例代码,您可以分别采用随机过期时间、加锁或队列、双写策略和数据预热等方法来解决Redis的缓存雪崩问题。合理使用这些方法,可以有效地减少对数据库的瞬时压力,提高系统的稳健性和可用性。


Redis(81)Redis的缓存雪崩是什么?》 是转载文章,点击查看原文


相关推荐


KuiklyUI利用Kotlin Lambda函数实现声明式UI系统的深入分析
风冷2025/10/22

KuiklyUI利用Kotlin Lambda函数实现声明式UI系统的深入分析 KuiklyUI通过巧妙地利用Kotlin的lambda函数特性,构建了一套灵活、高效的声明式UI系统。本文将深入分析其实现机制和核心技术点。 一、Lambda函数在声明式UI中的核心应用 1. 接收器作用域函数的巧妙运用 KuiklyUI的声明式语法核心基于Kotlin的接收器作用域函数。在按钮组件ButtonView中,我们可以看到典型的实现: class ButtonView : ComposeView<But


面试问题—上家公司的离职原因
mapbar_front2025/10/21

面试结尾HR必问的问题,就是上一家公司的离职原因,作为多年的资深架构师,我做过多次终面,听到过千奇百怪的答案,有的真诚,有的官方,有的遮遮掩掩,有的情绪愤怒,这个问题是有正确答案的,今天就来和你分享一下。 1、真实的离职原因 其实离职无非就是两类原因,一类主动,一类被动。 主动,要么钱少,要么心累,但大多数情况都是钱少心又累。 被动,要么被行情拖累,要么末位淘汰,要么违纪被发现,这个问题只要不回答的稀碎,都不会影响你被录用。 2、避开下面两个错误答案 2.1、 破口大骂前公司前领导 有可能真的是


Redis(73)如何处理Redis分布式锁的死锁问题?
Victor3562025/10/20

处理Redis分布式锁的死锁问题,可以采取以下一些方法: 设置锁的自动过期时间: 使用EX和PX参数设置锁的超时时间,确保锁在持有过久后自动释放,避免死锁。 使用看门狗模式: 通过不断刷新锁的过期时间来维持锁的有效性,防止锁的持有者因为长时间操作而导致锁自动过期。 确保锁的唯一性和原子性: 使用具有唯一标识的锁值来确保释放锁时的准确性,避免因误删导致的死锁问题。 故障恢复机制: 在检测到锁持有者失效后,其他节点可以尝试获取锁,确保系统的高可用性。 下面是一个示


区块链技术的五大应用场景
终端域名2025/10/19

区块链技术凭借其去中心化、不可篡改和透明性等核心优势,已渗透至金融、供应链管理、医疗健康、知识产权保护及公共服务五大领域,成为重构信任机制与提升协作效率的关键技术。以下是对五大应用场景的详细阐述: 一、金融:重塑信任基石 跨境支付与清算 区块链通过分布式账本技术实现跨境交易的实时结算,显著降低传统SWIFT网络的中介成本和时间延迟。例如,Ripple、R3等区块链联盟已推动跨境汇款效率提升至分钟级,将跨国交易成本从每笔26美元降低至15美元。 数字货币与支付结算 央行数字货币(如中国


B站多模态精细画质分析模型在 ICCV2025 大赛获得佳绩
哔哩哔哩技术2025/10/17

前言 暑期,B站多媒体实验室带队参与了 ICCV MIPI (Mobile Intelligent Photography and Imaging) Workshop 的细粒度图像质量定位 (Detailed Image Quality Assessment Track) 国际挑战赛,提出创新的多模态训练策略,将综合指标提升了13.5%,最终获得了第二名的好成绩。本次参赛经历阶段性地验证了实验室在视频质量评价 (Video Quality Assessment,后文统称为 VQA) ,MLLM


【软件测试】性能测试工具 JMeter
清风~徐~来2025/10/16

性能测试工具 JMeter 一. JMeter 下载与环境配置二. JMeter 介绍1. JMeter 基本使用2. JMeter 元件作用域和执行顺序3. JMeter 重点组件(1). 线程组(2). HTTP 请求(3). 查看结果树(4). HTTP 请求默认值(5). HTTP 信息头管理器(6). JSON 提取器(7). 用户定义的变量(8). JSON 断言(9). 同步定时器(10). 事务控制器(11). CSV 数据文件设置(12). HTTP Cookie 管理器


Python 的内置函数 bytes
IMPYLH2025/10/14

Python 内建函数列表 > Python 的内置函数 bytes class bytes(x=b''): ''' 创建 bytes :param x: 要转换的变量 :return: x 转换为 bytes 后的值 ''' Python 的内置函数 bytes 用于创建不可变的字节序列对象。它是 Python 中处理二进制数据的基本类型之一,与 str 类型类似但专门用于表示字节数据而非文本。 bytes 函数有三种主要创建方式: 通过指定


电视盒子助手开心电视助手 v8.0 删除电视内置软件 电视远程控制ADB去除电视广告
2501_929382652025/10/13

电视盒子助手开心电视助手 v8.0 删除电视内置软件 电视远程控制ADB去除电视广告                                       “开心电视助手V8.0最新版”是一款功能强大的安卓电视/电视盒子管理软件,通常运行在Windows电脑上。它通过局域网(Wi-Fi)或USB数据线连接到您的电视或盒子,实现一系列高级管理、调试和控制功能。 它尤其受到开发者、电视发烧友和喜欢折腾智能电视/盒子的用户的欢迎。支持安卓设备的电视 盒子 安卓手机 安卓所有设备 下载地


C# 中 Excel 工作表打印前页面边距的设置方法
缺点内向2025/10/12

C# 中 Excel 工作表打印前页面边距的设置方法 在日常的业务报表生成与文档打印场景中,Excel无疑是不可或缺的工具。然而,当我们需要批量打印或自动化生成Excel报表时,一个常见且令人头疼的问题浮现:如何确保所有打印输出的页面边距一致,避免手动逐一调整的繁琐与低效呢? 本文将探讨在C#环境中,如何通过编程方式精确控制Excel工作表的打印页面边距。在这里,我们将借助第三方库——Spire.XLS for .NET,为您提供一个高效、自动化且易于实现的解决方案,让您的Excel打印设置工作


FunASR 前端语音识别代码解析
Cosolar2025/10/10

这是基于Web技术的FunASR( 阿里巴巴达摩院 开源语音识别项目) 前端实现方案,支持麦克风实时录音识别与本地音频文件上传识别两大核心场景。整体功能围绕WebSocket通信、音频数据处理、语音识别结果解析三大关键环节展开,以下从代码结构、核心模块及关键逻辑三方面进行详细剖析。 代码:gitee.com/towao/FunAS… 一、代码整体结构 代码采用原生JavaScript编写,无框架依赖,整体架构清晰,主要划分为初始化配置、UI交互 控制 、音频 数据 处理、WebSocket通信、

首页编辑器站点地图

Copyright © 2025 聚合阅读

License: CC BY-SA 4.0