缓存雪崩导致的危害和解决办法

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 缓存雪崩导致的危害和解决办法

1. Redis 数据失效导致的雪崩


因为缓存失效,从而导致大量请求导向数据库。

大量请求,导致数据库处理不过来,整个系统依赖数据库的功能全部崩溃
单系统挂掉,其他依赖于该系统的应用也会出现不稳定甚至崩溃


2. Redis数据失效的场景


最大内存控制

maxmemory 最大内存阈值
maxmemory-policy 到达阈值的执行策略


3. 缓存雪崩解决方案

3.1 Semaphore信号量限流


J.U.C包重要的并发编程工具类

又称“信号量”,控制多个线程争抢许可。
核心方法
acquire:获取一个许可,如果没有就等待,
release:释放一个许可。

典型场景∶

1、代码并发处理限流;

例子

package cn.lazyfennec.cache.redis.service;
import cn.lazyfennec.cache.redis.annotations.NeteaseCache;
import cn.lazyfennec.cache.redis.dao.UserDao;
import cn.lazyfennec.cache.redis.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
@Service // 默认 单实例
public class UserService2 {
    @Autowired
    UserDao userDao;
    @Autowired
    RedisTemplate redisTemplate; // spring提供的一个redis客户端,底层封装了jedis等客户端
    // userId ---> lock 记录每一个userId当前的查询情况
    static Map<String, ReentrantLock> mapLock = new ConcurrentHashMap<>();
    static Semaphore semaphore = new Semaphore(50); // 信号量 50 -- 类似车票
    /**
     * 根据ID查询用户信息 (redis缓存,用户信息以json字符串格式存在(序列化))
     */
    public User findUserById(String userId) throws Exception {
        // 1\. 先读取缓存
        Object cacheValue = redisTemplate.opsForValue().get(userId); // redisTemplate是spring提供的redis客户端
        if (cacheValue != null) {
            System.out.println("###缓存命中:" + ((User) cacheValue).getUname());
            return (User) cacheValue;
        }
        // ---------------缓存miss之后流程--------------
        ReentrantLock reentrantLock = new ReentrantLock();
        try {
            if (mapLock.putIfAbsent(userId, reentrantLock) != null) { // 有返回值代表存在锁
                reentrantLock = mapLock.get(userId);
            }
            Thread.sleep(3000);// TODO 停顿3秒,等下一个线程过来,模拟多个用户同时并发请求的场景
            reentrantLock.lock(); // 争抢锁,抢不到的排队---1个请求查询数据库 --- 599个等待
            Thread.sleep(3000);// TODO 停顿3秒,模拟lock获取之后业务处理时间
            // 再次查询缓存 -- 避免大量重复数据库查询
            cacheValue = redisTemplate.opsForValue().get(userId); // redisTemplate是spring提供的redis客户端
            if (cacheValue != null) {
                System.out.println("###缓存命中:" + ((User) cacheValue).getUname());
                return (User) cacheValue;
            }
            semaphore.acquire(); // 获取信号量 ,没有获取到
            // 2\. 如果缓存miss,则查询数据库
            User user = userDao.findUserById(userId);
            System.out.println("***缓存miss:" + user.getUname());
            // 3\. 设置缓存(重建缓存) // 主播信息查询缓存
            redisTemplate.opsForValue().set(userId, user);// set key value
            redisTemplate.expire(userId, 100, TimeUnit.SECONDS); // 需要手动设
            semaphore.release(); // 释放信号量
            return user;
        } finally {
            if (!reentrantLock.hasQueuedThreads()) { // 当锁最后一个释放的时候,删除掉
                mapLock.remove(userId);
            }
            reentrantLock.unlock();
        }
    }
    @CacheEvict(value = "user", key = "#user.uid") // 方法执行结束,清除缓存
    public void updateUser(User user) {
        String sql = "update tb_user_base set uname = ? where uid=?";
        jdbcTemplate.update(sql, new String[]{user.getUname(), user.getUid()});
    }
    /**
     * 根据ID查询用户名称
     */
    // 我自己实现一个类似的注解
    @NeteaseCache(value = "uname", key = "#userId") // 缓存
    public String findUserNameById(String userId) {
        // 查询数据库
        String sql = "select uname from tb_user_base where uid=?";
        String uname = jdbcTemplate.queryForObject(sql, new String[]{userId}, String.class);
        return uname;
    }
    @Autowired
    JdbcTemplate jdbcTemplate; // spring提供jdbc一个工具(mybastis类似)
}

3.2 容错降级

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
Web App开发 缓存 网络协议
chrome谷歌浏览器&firefox火狐清除dns缓存的办法
chrome谷歌浏览器&firefox火狐清除dns缓存的办法
511 0
chrome谷歌浏览器&firefox火狐清除dns缓存的办法
|
缓存 开发框架 .NET
实体列表缓存(最土的办法实现百万级性能)
在实际项目开发中,经常遇到有一些表数据很少(1000行以内),不会频繁修改(平均每行几个小时才会修改一次),例如配置表、分类表等。 这样的表,往往可以接受三五秒甚至更长的延迟,正是最适合使用缓存的地方。 实体缓存:一次性加载全表数据进入内存,供上层多维度查询!
359 0
|
缓存 JavaScript 索引
webpack分离第三方库(CommonsChunkPlugin并不是分离第三方库的好办法DllPlugin科学利用浏览器缓存)
webpack算是个磨人的小妖精了。之前一直站在glup阵营,使用browserify打包,发现webpack已经火到爆炸,深怕被社区遗落,赶紧拿起来把玩一下。本来只想玩一下的。尝试打包了以后,就想启个webpack服务器,之后就想添加热替换,什么css文件单独拆分,各种 loader 处理优化打包结果,各种 source-map 有什么不同,一个都不能少。
1373 0
|
存储 缓存 Android开发
【技术贴】解决相册thumbnails文件过大 小米缩略图缓存根除办法
命令:cd.> I:\DCIM\.thumbnails   I为你的小米插到电脑上的usb的盘符,进到你的usb里面的此文件夹中,删除.thumbnails文件夹,然后把上面的命令右键复制,然后再cmd里面右键粘贴,然后打个回车即可。
1785 0
|
23天前
|
canal 缓存 NoSQL
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
根据对一致性的要求程度,提出多种解决方案:同步删除、同步删除+可靠消息、延时双删、异步监听+可靠消息、多重保障方案
Redis缓存与数据库如何保证一致性?同步删除+延时双删+异步监听+多重保障方案
|
2月前
|
缓存 NoSQL Java
Redis深度解析:解锁高性能缓存的终极武器,让你的应用飞起来
【8月更文挑战第29天】本文从基本概念入手,通过实战示例、原理解析和高级使用技巧,全面讲解Redis这一高性能键值对数据库。Redis基于内存存储,支持多种数据结构,如字符串、列表和哈希表等,常用于数据库、缓存及消息队列。文中详细介绍了如何在Spring Boot项目中集成Redis,并展示了其工作原理、缓存实现方法及高级特性,如事务、发布/订阅、Lua脚本和集群等,帮助读者从入门到精通Redis,大幅提升应用性能与可扩展性。
60 0
|
24天前
|
存储 NoSQL Redis
SpringCloud基础7——Redis分布式缓存,RDB,AOF持久化+主从+哨兵+分片集群
Redis持久化、RDB和AOF方案、Redis主从集群、哨兵、分片集群、散列插槽、自动手动故障转移
SpringCloud基础7——Redis分布式缓存,RDB,AOF持久化+主从+哨兵+分片集群
|
2天前
|
缓存 NoSQL Java
Springboot自定义注解+aop实现redis自动清除缓存功能
通过上述步骤,我们不仅实现了一个高度灵活的缓存管理机制,还保证了代码的整洁与可维护性。自定义注解与AOP的结合,让缓存清除逻辑与业务逻辑分离,便于未来的扩展和修改。这种设计模式非常适合需要频繁更新缓存的应用场景,大大提高了开发效率和系统的响应速度。
10 2
|
7天前
|
存储 缓存 NoSQL
解决Redis缓存击穿问题的技术方法
解决Redis缓存击穿问题的技术方法
21 2