Redis缓存问题详解和处理

缓存更新策略


在这里插入图片描述

缓存穿透


缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库.

  • 常见的解决方案:
    • 缓存空对象
      • 优点: 实现简单, 维护方便
      • 缺点: 额外的内存消耗, 可能造成短期的不一致
    • 布隆过滤
      • 优点: 内存占用较少(保存的是数据的二进制位)
      • 缺点: 实现复杂, 存在误判可能

在这里插入图片描述

  • 缓存空对象业务逻辑
    在这里插入图片描述
  • 写入空值
redisTemplate.opsForValue().set("item:1001", "", 30L, TimeUnit.SECONDS);

缓存雪崩


缓存雪崩是指在同一时段大量的缓存key同时失效或者Redis服务宕机, 导致大量请求到达数据库, 带来巨大压力.

解决方案:

  • 给不同的key的TTL添加随机值
  • 利用Redis集群提高服务的可用性
  • 给缓存业务添加降级限流策略
  • 给业务添加多级缓存

缓存击穿


缓存击穿问题也叫热点Key问题, 就是一个高并发访问并且缓存重建业务较复杂的key突然失效了, 无数的请求访问会瞬间给数据库带来巨大的冲击.

常见的解决方案:

  • 互斥锁
  • 逻辑过期

在这里插入图片描述

互斥锁

在这里插入图片描述

  • 定义获取锁和释放锁的方法
	private boolean tryLock(String key){Boolean flag = redisTemplate.opsForValue().setIfAbsent(key, "1", 10L, TimeUnit.SECONDS);return BooleanUtils.isTrue(flag); }private void unlock(String key){redisTemplate.delete(key);}

在这里插入图片描述
在这里插入图片描述

逻辑过期

在这里插入图片描述

  • 逻辑过期业务逻辑

在这里插入图片描述

  • 缓存预热

在这里插入图片描述

  • RedisData.java
@Data
public class RedisData {private LocalDateTime expireTime;private Object data;}
  • 判断是否逻辑过期

在这里插入图片描述

  • 开启独立线程重建缓存

在这里插入图片描述

封装Redis工具类


缓存工具类


import cn.hutool.json.JSONUtil;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;@Component
public class CacheClient {private final StringRedisTemplate stringRedisTemplate;private static final long NULL_TTL = 1L;public CacheClient(StringRedisTemplate stringRedisTemplate) {this.stringRedisTemplate = stringRedisTemplate;}public void set(String key, Object value, Long time, TimeUnit unit) {stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(value), time, unit);}public String get(String key) {return stringRedisTemplate.opsForValue().get(key);}public void delete(String key) {stringRedisTemplate.delete(key);}public void setWithLogicalExpire(String key, Object value, Long time, TimeUnit unit) {// 设置逻辑过期RedisData redisData = new RedisData();redisData.setData(value);redisData.setExpireTime(LocalDateTime.now().plusSeconds(unit.toSeconds(time)));// 写入redisstringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(redisData));}/*** 查询--缓存穿透处理*/public <R, ID> R queryWithPassThrough(String keyPrefix, ID id, Class<R> type, Long time, TimeUnit unit, Function<ID, R> dbFallBack) {String key = keyPrefix + id;String json = stringRedisTemplate.opsForValue().get(key);if (StringUtils.isNotBlank(json)) {// 存在,直接返回return JSONUtil.toBean(json, type);}// 判断命中的是否为空值,缓存穿透处理会存""if (json != null) {// 返回一个错误信息return null;}R r = dbFallBack.apply(id);if (r == null) {// 将空值写入redis, 缓存穿透处理stringRedisTemplate.opsForValue().set(key, "", NULL_TTL, TimeUnit.SECONDS);return null;}// 存在, 写入redisthis.set(key, JSONUtil.toJsonStr(r), time, unit);return r;}}@Data
class RedisData {// 逻辑过期时间private LocalDateTime expireTime;private Object data;
}

分布式锁类

  • ILock.java
public interface ILock {/*** 尝试获取锁* @param timeoutSec* @return*/boolean tryLock(long timeoutSec);/*** 释放锁*/void unlock();
}
  • SimpleRedisLock.java
import cn.hutool.core.lang.UUID;
import org.springframework.data.redis.core.StringRedisTemplate;import java.util.concurrent.TimeUnit;public class SimpleRedisLock implements ILock {private StringRedisTemplate stringRedisTemplate;private String name;private static final String KEY_PREFIX = "lock:";private static final String ID_PREFIX = UUID.randomUUID().toString(true) + "-";public SimpleRedisLock(StringRedisTemplate stringRedisTemplate, String name) {this.stringRedisTemplate = stringRedisTemplate;this.name = name;}@Overridepublic boolean tryLock(long timeoutSec) {String threadId = ID_PREFIX + Thread.currentThread().getId();Boolean success = stringRedisTemplate.opsForValue().setIfAbsent(KEY_PREFIX + name, threadId, timeoutSec, TimeUnit.SECONDS);return Boolean.TRUE.equals(success);}@Overridepublic void unlock() {String threadId = ID_PREFIX + Thread.currentThread().getId();String id = stringRedisTemplate.opsForValue().get(KEY_PREFIX + name);if (threadId.equals(id)) {// 释放锁stringRedisTemplate.delete(KEY_PREFIX + name);}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/535871.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PDF Word Converter V2-一站式文档转换解决方案

PDF Word Converter V2 一站式文档转换解决方案 功能亮点&#xff1a; PDF 转 Word&#xff1a;轻松将 PDF 文档转换为可编辑的 Word 文件&#xff0c;保持原有格式和布局。 Word 转 PDF&#xff1a;将 Word 文档转换为 PDF 格式&#xff0c;确保跨平台的文档一致性和专业呈…

像SpringBoot一样使用Flask - 3.蓝图路由Blueprint

接上一篇文章《像SpringBoot一样使用Flask - 2.静态资源访问及模版》&#xff0c;我们看到测试的"controller"都写在了一起&#x1f914; 如何像Springboot一样划分出一个完整的controller&#xff0c;里面实现不同业务的包呢&#xff1f; 本篇引入Blueprint&#xf…

uniapp图片涂鸦插件(支持多种涂鸦方式,图片放大缩小)

工程地址https://gitee.com/geshijia/ct-graffiti ct-graffiti涂鸦组件使用说明 参考说明 参考链接&#xff1a;https://github.com/ylyuanlu/yl-graffiti 感谢作者的付出&#xff0c;给我提供了一些思路&#xff0c;并做了如下优化&#xff1a; 增加图片放大缩小移动功能添…

数据库基础理论知识

1.基本概念 数据(Data)&#xff1a;数据库存储的基本对象。数字、字符串、图形、图像、音频、视频等数据库(DB)&#xff1a;在计算机内&#xff0c;永久存储、有组织、可共享的数据集合数据库管理系统(DBMS)&#xff1a;管理数据库的系统软件数据库系统(DBS)&#xff1a;DBDBM…

数据结构:红黑树的模拟实现

目录 1、什么是红黑树&#xff1f; 2、红黑树的相关操作与实现 1、节点定义 2、查找操作 3、插入操作 1、cur为红&#xff0c;p为红&#xff0c;g为黑&#xff0c;cur存在且为红 2、cur为红&#xff0c;p为红&#xff0c;g为黑&#xff0c;u不存在/u存在且为黑 4、判断…

Prompt进阶3:LangGPT(构建高性能质量Prompt策略和技巧2)--稳定高质量文案生成器

Prompt进阶3:LangGPT(构建高性能质量Prompt策略和技巧2)–稳定高质量文案生成器 1.LangGPT介绍 现有 Prompt 创建方法有如下缺点&#xff1a; 缺乏系统性&#xff1a;大多是细碎的规则&#xff0c;技巧&#xff0c;严重依赖个人经验缺乏灵活性&#xff1a;对他人分享的优质 …

mysql基于mycat实现读写分离

试验环境 基于mysql主从复制已经实现 mycat主机192.168.199.149&#xff0c;安装好java和jdk 数据库主机192.168.199.150 数据库从机192.168.199.151 149配置 下载mycat并解压 vim /root/mycat/conf/server.xml vim /root/mycat/conf/schema.xml 150是主数据库&#xff0…

jenkins部署go应用 基于docker-compose

丢弃旧的的构建 github 拉取代码 指定go的编译版本 安装插件 拉取代码是排除指定的配置文件 比如 conf/config.yaml 文件 填写配置文件内容 比如测试环境一些主机信息 等 可以配置里面 构建的时候选择此文件替换开发提交的配置文件。。。。 编写docker-compose 文件 docker…

CountDownLatch介绍和使用

1. CountDownLatch是什么 CountDownLatch 是 Java.util.concurrent 包中的一个同步工具类&#xff0c;用于控制线程的执行顺序。它的主要作用是让一个或多个线程等待其他线程完成操作后再继续执行。 2. CountDownLatch 类常用方法 CountDownLatch(int count) 是 CountDownLa…

【C++ Boost库】原始计时器

文章目录 前言一、原始计时器1.1 timer定时器timer类的介绍异常安全代码概况 1.2 progress_timer类如何使用异常安全代码概况 1.3 progress_display类如何使用代码概况 总结 前言 在现代软件开发中&#xff0c;时间是一种不可逆转的资源。特别是在需要按时执行任务、调度事件或…

鸿蒙开发月薪过万,背后的秘密~

自从智联招聘公布出春节后首周的岗位需求数据后&#xff0c;鸿蒙开发岗位就被推上了热潮&#xff01;鸿蒙相关职位数同比增长163%&#xff0c;投递人数同比增长349%&#xff0c;即分别增至去年同期的2.6倍、4.5倍&#xff0c;涨势突出。 于是我的朋友圈中就有人去市场中简单探…