Redis缓存实现及其常见问题解决方案

随着互联网技术的发展,数据处理的速度和效率成为了衡量一个系统性能的重要指标。在众多的数据处理技术中,缓存技术以其出色的性能优化效果,成为了不可或缺的一环。而在众多的缓存技术中,Redis 以其出色的性能和丰富的功能,赢得了广大开发者的喜爱。

Redis 是一个开源的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。Redis 支持多种类型的数据结构,如字符串、哈希、列表、集合、有序集合等。此外,Redis 还提供了一系列的特性,如数据持久化、事务和发布订阅等。

然而,如何利用 Redis 实现高效的缓存机制呢?这就是我们今天要探讨的主题。在这篇文章中,我们将详细介绍 Redis 的缓存实现,包括其读写策略、过期策略和淘汰策略等。我们希望通过这篇文章,帮助读者更好地理解和使用 Redis,从而提高自己的系统性能。


文章目录

        • 1、Redis缓存实现与缓存策略
          • 1.1、Redis缓存应用
          • 1.2、Redis缓存策略分类
          • 1.3、Redis常见读策略
          • 1.4、Redis常见写策略
          • 1.5、Redis常见过期策略
          • 1.6、Redis淘汰策略
        • 2、Redis缓存常见问题及解决方案
          • 2.1、Redis热键问题
          • 2.2、Redis缓存穿透
          • 2.3、Redis缓存击穿
          • 2.4、Redis缓存雪崩
        • 3、Java下Redis缓存实现
          • 3.1、Jedis实现
          • 3.2、SpringBoot实现


1、Redis缓存实现与缓存策略

1.1、Redis缓存应用

Redis 缓存是 Redis 的一种主要应用场景。通过将热点数据存储在内存中,可以大大提高应用的读取速度,从而提高应用的性能。

image-20230913200928903

在使用 Redis 作为缓存时,通常会设置一个过期时间,当数据过期后,Redis 会自动删除这些数据,以释放内存空间。同时,为了防止缓存雪崩,通常会对过期时间进行随机化处理。

此外,Redis 还提供了丰富的数据结构,如字符串、列表、集合、哈希表等,可以满足各种复杂的缓存需求。例如,可以使用哈希表存储对象,使用列表实现最近最少使用(LRU)算法等。

1.2、Redis缓存策略分类

缓存策略是指在使用缓存时,如何选择和管理缓存中的数据的一系列规则和方法。缓存策略的目标是尽可能地提高数据访问的速度,减少对原始数据源(如数据库)的访问,从而提高系统的性能。

缓存策略主要包括以下几个方面:读策略、写策略、加载策略、过期策略、淘汰策略。

1.3、Redis常见读策略

Redis常见读策略:

  1. Read Through(读策略-按需加载):在读取数据时,如果发现缓存中没有,那么会从数据库中读取,读取后将数据放入缓存。这种策略可以保证缓存中的数据都是热点数据,但可能会导致第一次读取数据时延迟增加;
  2. Lazy Loading(读策略-按需加载):只有当数据被请求时,才将其加载到缓存中。如果数据在缓存中未命中,则从数据库中读取并添加到缓存中;
  3. Pre Loading(读策略-预加载):系统在启动或者在某个特定的时间点,会预先将可能需要的数据加载到缓存中。这样,当数据被请求时,可以直接从缓存中获取,无需再去数据库中查询,从而提高了数据访问的速度。预加载策略特别适用于那些数据访问模式比较固定,且数据更新频率不高的场景。例如,一些配置信息、静态内容等,就非常适合使用预加载策略。

在实际使用中,可以根据具体的应用场景和需求,选择合适的读策略。例如,如果数据更新频率较低,且读取操作的性能要求较高,可以选择使用 Read Through 策略;如果数据更新频率较高,或者希望节省缓存空间,可以选择使用 Lazy Loading 策略。

1.4、Redis常见写策略

Redis常见写策略:

  1. Write Through(写策略-同步更新):每次数据更新时,都会同时更新数据库和缓存。这种策略的优点是能够保持数据的一致性,但缺点是会影响性能,因为每次更新都需要同时操作数据库和缓存。
  2. Write Back(写策略-异步更新):每次数据更新时,先更新缓存,然后再异步更新数据库。这种策略的优点是不会影响缓存的高性能,能够快速响应客户端,但缺点是在数据异步写回到数据库之前,存在缓存和数据库数据短暂不一致的情况。
  3. Write Around(写策略-直接更新):在更新数据时,直接更新数据库,不更新缓存。当下次读取数据时,如果缓存中没有,再从数据库中读取。这种策略适用于那些被写入后很少被读取的数据。
1.5、Redis常见过期策略

Redis 的过期策略主要是通过设置 TTL(Time To Live)来实现的。对于每个设置了过期时间的键,Redis 会在键到达其过期时间时自动删除它。Redis 使用了惰性删除和定期删除两种策略来处理过期的键:

  1. 惰性删除:即只有当某个键被访问时,Redis 才会检查该键是否过期,如果过期则删除。这种策略的优点是可以减少对 CPU 的占用,避免在键过期的瞬间产生大量的删除操作,影响 Redis 的性能;

image-20230913200158436

  1. 定期删除:即 Redis 会每隔一段时间随机检查一些键,如果发现有键已经过期,就会将其删除。这种策略可以有效地清理过期的键,释放内存空间。

    但是,由于 Redis 不能对所有键进行轮询,所以可能会有一些已经过期的键没有被立即删除。这就是为什么 Redis 还需要使用惰性删除策略,即只有当某个键被访问时,Redis 才会检查该键是否过期,如果过期则删除。

这两种策略的结合使用,可以在保证 Redis 性能的同时,有效地管理过期的键,避免过期的键长时间占用内存。

1.6、Redis淘汰策略

那么定期+惰性都没有删除过期的 Key 怎么办?这时就需要 Redis 的内存淘汰策略登场了

当 Redis 的内存使用达到设定的上限时,如果还需要存储新的数据,就需要采用一种淘汰策略来删除一些旧的数据,以释放内存空间。这就是所谓的内存淘汰机制。

Redis 提供了多种淘汰策略,可以通过 maxmemory-policy 配置项来设置,包括:

  1. noeviction:当内存不足以容纳新写入数据时,新写入操作会报错;
  2. allkeys-lru:从数据集中挑选最近最少使用的数据淘汰;
  3. volatile-lru:从设置了过期时间的数据集中挑选最近最少使用的数据淘汰;

image-20230913194418121

  1. allkeys-random:随机移除某个键;
  2. volatile-random:从设置了过期时间的数据集中任意选择数据淘汰;
  3. volatile-ttl:从设置了过期时间的数据集中挑选将要过期的数据淘汰。

以上策略可以根据实际应用的需求和场景进行选择。


2、Redis缓存常见问题及解决方案

2.1、Redis热键问题

所谓热键问题就是,某个或某些键被大量并发的请求访问,可能会导致流量过于集中,达到物理网卡上限,从而导致这台 Redis 的服务器宕机引发雪崩。

针对热键问题的解决方案:

  1. 提前把热键打散到不同的服务器:这种方法也被称为分片,可以将热键的数据分散到多个 Redis 服务器中,降低单个服务器的访问压力;
  2. 二级缓存:在应用服务器内部维护一个本地缓存,当 Redis 宕机时,可以从本地缓存中获取数据。这种方法可以提高系统的可用性,但需要注意的是,本地缓存和 Redis 之间可能会存在数据一致性的问题

另外,还可以考虑使用一些流量控制的手段,比如限流、熔断等,来防止大量的请求同时访问热键,从而避免服务器宕机的问题。

2.2、Redis缓存穿透

缓存穿透是指查询一个在缓存和数据库中都不存在的数据,每次请求都会打到数据库,造成数据库压力过大。

有效的解决方案是:

  1. 接口校验:对请求的参数进行校验,非法的请求直接返回错误,不让其打到数据库。
  2. 缓存空值:即使数据库中没有查询到数据,也将空值写入缓存,这样下次查询同样的数据时,直接从缓存中获取空值,不需要再访问数据库。
  3. 布隆过滤器:布隆过滤器是一种概率型数据结构,可以用来判断一个元素是否在一个集合中。我们可以将所有可能存在的数据的 Key 存入布隆过滤器,当查询数据时,先判断 Key 是否在布隆过滤器中,如果不在,直接返回不存在,如果在,再去缓存和数据库中查询。

布隆过滤器(Bloom Filter)的主要特点如下:

  1. 判断不存在:如果布隆过滤器判断一个元素不存在,则这个元素一定不存在。
  2. 判断存在:如果布隆过滤器判断一个元素存在,这个元素可能存在也可能不存在,存在一定的误判率。这个误判率是可以通过调整布隆过滤器的参数来控制的。

布隆过滤器由一个位数组(BitSet)和一组哈希函数组成,是一种空间效率极高的概率型算法和数据结构,主要用来判断一个元素是否在集合中存在。

相比于HashMap,布隆过滤器在处理大数据量时有明显的优势。当数据量较小,HashMap可以很好地处理问题,而且不存在误判率。但是,当数据量变大,尤其是要存储的键(Key)占用空间越大,布隆过滤器的空间优势就会开始体

这些方法可以有效地防止缓存穿透问题,保护数据库不被大量无效请求打垮。

2.3、Redis缓存击穿

缓存击穿是指一个热点数据在缓存中过期的瞬间,大量的请求直接打到数据库,可能会导致数据库压力骤增,甚至崩溃。

有效的解决方案是:

  1. 加互斥锁:在第一个请求查询数据库并更新缓存的过程中,其他的请求等待。这样可以保证只有一个请求会访问数据库,避免数据库压力过大。
  2. 热点数据不过期:将热点数据设置为永不过期,然后通过定时任务异步更新这些数据。这种方法可以避免热点数据突然过期导致的缓存击穿问题,但需要注意的是,这可能会导致数据在一段时间内不一致,需要根据业务需求来决定是否可以接受。

这些方法可以有效地防止缓存击穿问题,保护数据库不被大量请求打垮。

2.4、Redis缓存雪崩

缓存雪崩是指大量的热点数据在同一时间点过期,导致大量的请求直接打到数据库,可能会导致数据库压力骤增,甚至崩溃。

有效的解决方案是:

  1. 过期时间打散:给每个键的过期时间添加一个随机值,使得各个键的过期时间分散开来,避免在同一时间点大量键过期。
  2. 加互斥锁:对于同一个键,只允许一个请求查询数据库并更新缓存,其他的请求等待。这样可以保证只有一个请求会访问数据库,避免数据库压力过大。
  3. 热点数据不过期:将热点数据设置为永不过期,然后通过定时任务异步更新这些数据。这种方法可以避免热点数据突然过期导致的缓存雪崩问题,但需要注意的是,这可能会导致数据在一段时间内不一致,需要根据业务需求来决定是否可以接受。

这些方法可以有效地防止缓存雪崩问题,保护数据库不被大量请求打垮。


3、Java下Redis缓存实现

3.1、Jedis实现

以下是使用 Java 实现 Read Through 和 Write Through 策略的简单例子:

import redis.clients.jedis.Jedis;public class Cache {private Jedis jedis;private Database db;public Cache() {this.jedis = new Jedis("localhost", 6379);this.db = new Database();}// Read Through策略public String readThrough(String key) {// 先从缓存中读取数据String value = jedis.get(key);if (value == null) {// 如果缓存中没有,那么从数据库中读取value = db.getFromDatabase(key);// 将从数据库中读取的数据放入缓存jedis.set(key, value);}return value;}// Write Through策略public void writeThrough(String key, String value) {// 先将数据写入数据库db.writeToDatabase(key, value);// 然后将数据写入缓存jedis.set(key, value);}
}class Database {// 这里假设我们有一个数据库,具体实现省略public String getFromDatabase(String key) {// 从数据库中获取数据的代码return "data";}public void writeToDatabase(String key, String value) {// 将数据写入数据库的代码}
}

在这个例子中,我们首先创建了一个Cache类,该类在构造函数中连接到 Redis 服务器,并初始化一个数据库对象。

然后,我们定义了两个方法:readThroughwriteThrough,分别实现了 Read Through 和 Write Through 策略。

  • readThrough方法首先尝试从缓存中读取数据,如果缓存中没有,那么从数据库中读取,并将从数据库中读取的数据放入缓存。
  • writeThrough方法首先将数据写入数据库,然后将数据写入缓存。

Database类是一个假设的数据库类,具体实现省略。

3.2、SpringBoot实现

在 Spring Boot 中,我们也可以使用springframework.data.redis 来实现 Read Through 和 Write Through 策略。以下是一个简单的例子:

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;@Service
public class DataService {private final StringRedisTemplate redisTemplate;public DataService(StringRedisTemplate redisTemplate) {this.redisTemplate = redisTemplate;}public String readThrough(String key) {// 先从缓存中读取数据String value = redisTemplate.opsForValue().get(key);if (value == null) {// 如果缓存中没有,那么从数据库中读取value = getFromDatabase(key);// 将从数据库中读取的数据放入缓存redisTemplate.opsForValue().set(key, value);}return value;}public void writeThrough(String key, String value) {// 先将数据写入数据库writeToDatabase(key, value);// 然后将数据写入缓存redisTemplate.opsForValue().set(key, value);}private String getFromDatabase(String key) {// 从数据库中获取数据的代码return "data";}private void writeToDatabase(String key, String value) {// 将数据写入数据库的代码}
}

在这个例子中,我们首先创建了一个 DataService 类,该类被 Spring 管理。

然后,我们定义了两个方法:readThrough writeThrough,分别实现了 Read Through 和 Write Through 策略。

  • readThrough 方法首先尝试从缓存中读取数据,如果缓存中没有,那么从数据库中读取,并将从数据库中读取的数据放入缓存。
  • writeThrough 方法首先将数据写入数据库,然后将数据写入缓存。

getFromDatabasewriteToDatabase方法是从数据库中获取数据和将数据写入数据库的代码,具体实现省略。

注意:在实际使用中,你需要在 Spring Boot 的配置文件中配置 Redis 连接信息。

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

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

相关文章

JDK jps命令复习

之前写过jdk命令工具的博文,下面复习jps命令; jps 是 Java Process Status Tool 的简称,它的作用是为了列出所有正在运行中的 Java 虚拟机进程和相关信息; jps 命令参数 -q 只输出进程 ID,省略主类的名称 -m 输出虚拟机进程启动时传递…

AG35学习笔记(一):debug串口抓取模组log、debug串口测试AT指令、echo命令通过串口发送16进制数据

目录 一、概述二、抓取模组log2.1 硬件接口2.2 用户登录2.3 相关指令 三、测试AT指令3.1 查看端口3.2 进入模式 四、串口发16进制echo使用 一、概述 二、抓取模组log 在之前记录了通过USB,使用移远工具Qwinlog来抓取log(3.3 抓取模组log)。…

【Java】第一个Servlet程序

第一个Servlet程序 创建项目引入依赖手动创建必要的目录/文件编写代码打包程序部署验证程序是否正常工作 创建项目 选中maven 创建好项目后,观察左侧项目结构 引入依赖 当权代码需要使用servlet开发,而Java标准库中并没有servlet,此时就需要让maven能够把servlet的依赖获取…

子网的划分

强化计算机网络发现王道没有这一块的内容,导致做题稀里糊涂。于是个人调研补充。 子网划分是将一个大型IP网络划分成更小的子网,以实现更有效的网络管理和资源分配。 原因: 提高网络性能:子网划分可以减少广播域的大小&#xff…

成集云 | 用友NC集成旺店通ERP(旺店通主管库存)| 解决方案

源系统成集云目标系统 方案介绍 用友NC是用友NC产品的全新系列,是面向集团企业的世界级高端管理软件。它以“全球化集团管控、行业化解决方案、全程化电子商务、平台化应用集成”的管理业务理念而设计,采用J2EE架构和先进开放的集团级开发平台…

bootstrap柵格

.col-xs- 超小屏幕 手机 (<768px) .col-sm- 小屏幕 平板 (≥768px) .col-md- 中等屏幕 桌面显示器 (≥992px) .col-lg- 大屏幕 大桌面显示器 (≥1200px) 分为12个格子 -后面的1代表占12分子1也就是一份 1.中等屏幕 <div class"container-fluid a">&l…

Autojs 小游戏实践-潮玩宇宙开扭蛋

概述 最近在玩潮流宇宙&#xff0c;里面有扭蛋兔的一个玩法&#xff0c;开始有很多蛋&#xff0c;需要我们一个个点开&#xff0c;然后根据装备品质替换分解&#xff0c;潮流提供了自动开扭蛋功能&#xff0c;但是开到品质比自己装备好的时候回暂停&#xff0c;由于个人懒得看…

在Kubernetes上安装和配置Istio:逐步指南,展示如何在Kubernetes集群中安装和配置Istio服务网格

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

掌握这三大要素,轻松写出爆款软文

随着网络的快速发展&#xff0c;软文营销的趋势也在不断变化&#xff0c;做软文看似简单&#xff0c;但是想要做出成绩&#xff0c;真正吸引用户其实是有一定难度的&#xff0c;也有不少企业向媒介盒子咨询软文写作的相关话题&#xff0c;今天就让媒介盒子告诉大家&#xff0c;…

Linux查找文件内容的命令

在Linux中&#xff0c;您可以使用以下命令来查找文件内容&#xff1a; grep命令&#xff1a; grep命令用于在文件中搜索指定的文本模式&#xff0c;并将包含匹配的行打印出来。语法如下&#xff1a; grep "要查找的文本" 文件名例如&#xff0c;要在名为example.txt的…

【深度学习 | LSTM】解开LSTM的秘密:门控机制如何控制信息流

&#x1f935;‍♂️ 个人主页: AI_magician &#x1f4e1;主页地址&#xff1a; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 &#x1f468;‍&#x1f4bb;景愿&#xff1a;旨在于能和更多的热爱计算机的伙伴一起成长&#xff01;&#xff01;&…

(超详解)堆排序+(图解)

目录&#xff1a; 1:如何建堆(两种方法) 2:两种方法建堆的时间复杂度分析与计算 3:不同类型的排序方式我们应该如何建堆 文章正式开始&#xff1a; 1&#xff1a;如何建堆 在实现堆排序之前我们必须得建堆&#xff0c;才能够实现堆排序 首先在讲解如何建堆之前让我们先来回顾一…

JDK8新特性

Lembda表达式 lembda表达式是一个简洁、可传递的匿名函数,实现了把代码块赋值给一个变量的功能 是我认为jdk1.8中最让人眼前一亮的特性&#xff08;我没用过其他函数式的语言&#xff09; 在了解表达式之前&#xff0c;我们先看两个概念 函数式接口 含有且仅含有一个抽象方法&…

CSS核心使用

CSS核心使用 box-sizingbox-shdowtext-shadowpositionwriting-mode box-sizing 定义计算一个元素的总高度和总宽度. 属性值 content-box 默认值,width 内容宽度,height内容的高度border-box 宽度和高度包含内容,内边距和边框 widthborderpadding内容宽度, heightborderpaddi…

测试进阶知识之零日攻击的发现和防御

零日攻击是指针对软件或系统中未公开&#xff08;或未被开发者知晓&#xff09;的漏洞进行的攻击。这些漏洞被称为零日漏洞&#xff0c;因为在被公开之前&#xff0c;它们对开发者或安全研究人员来说是未知的&#xff0c;所以没有足够的时间进行防御或修复。 发现零日漏洞 发…

启动YOLO进行图片物体识别

查看官方文档YOLO: Real-Time Object Detection 这些是一些模型的对比&#xff0c;显示了YOLO的优势&#xff0c;继续往下面看 CoCoData set 是一个数据库&#xff0c;用来训练模型&#xff0c;这里面有丰富的物体检测&#xff0c;分割数据集&#xff0c;图像经过了精确的segm…

Pikachu Burte Force(暴力破解)

一、Burte Force&#xff08;暴力破解&#xff09;概述 ​ “暴力破解”是一攻击具手段&#xff0c;在web攻击中&#xff0c;一般会使用这种手段对应用系统的认证信息进行获取。 其过程就是使用大量的认证信息在认证接口进行尝试登录&#xff0c;直到得到正确的结果。 为了提高…

Jenkins List Git Branches插件 构建选择指定git分支

List Git Branches Parameter | Jenkins pluginAdds ability to choose from git repository revisions or tagshttps://plugins.jenkins.io/list-git-branches-parameter/ 1、安装组件 List Git Branches 2、验证功能 1&#xff09;新建任务 2&#xff09;新增构建参数 3&…

JavaSE List

目录 1 预备知识-泛型(Generic)1.1 泛型的引入1.2 泛型类的定义的简单演示 1.3 泛型背后作用时期和背后的简单原理1.4 泛型类的使用1.5 泛型总结 2 预备知识-包装类&#xff08;Wrapper Class&#xff09;2.1 基本数据类型和包装类直接的对应关系2.2 包装类的使用&#xff0c;装…

【教程】微信小程序导入外部字体详细流程

前言 在微信小程序中&#xff0c;我们在wxss文件中通过font-family这一CSS属性来设置文本的字体&#xff0c;并且微信小程序有自身支持的内置字体&#xff0c;可以通过代码提示查看微信小程序支持字体&#xff1a; 这些字体具体是什么样式可以参考&#xff1a; 微信小程序--字…