Java开发 - Redis常见问题场景及解决办法一览

本文介绍了Redis使用中常见的缓存穿透、击穿和雪崩问题,提供了解决方案,包括保存空值、布隆过滤器和设置永不过期、分布式锁等。同时提到了Redis主从和集群对于这些问题的应对策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

前面几篇博客对Redis的讲解不可谓不详细,从单节点到主从,到sentinel哨兵,到Redis Cluster都一一搭配使用给大家做了讲解,但在使用Redis的过程中我们还是要注意一些比较常见的问题,比如穿透、击穿等等,所以本篇博客主要就是给大家做这方面的扫盲,希望对一些初学者可以有些帮助。

导读

在开始讲解之前,Redis相关的博客地址我先给大家做一个推荐:

Java开发 - Redis初体验

Java开发 - 让你少走弯路的Redis的主从复制

Java开发 - 让你少走弯路的Redis主从实现单节点哨兵模式

Java开发 - 让你少走弯路的Redis集群搭建

Java开发 - 深入理解Redis哨兵机制原理

Java开发 - 深入理解Redis Cluster的工作原理

以上几篇,希望能给需要的朋友一些帮助,下面,我们来讲解Redis使用中常见的一些问题。

缓存穿透

出现的场景

当我们查询一个数据的时候,数据在Redis缓存中不存在,就会查询到数据库中,如果数据库中也没有这条数据,那就相当于没有查到任何东西。这看似很正常,可是当数以万计的查询同时进行时,缓存都没有数据,这些查询将直接访问数据库,这就带给数据库极大的压力,缓存也就失去了存在的意义。这种情况,我们称之为缓存穿透,即穿透了缓存,直达数据库,这个前提条件是大量的穿透。

解决办法

对于缓存穿透,解决的办法博主说两种:

第一种:这是业内比较常见的处理办法:保存空值。即数据库也查不到数据时,在Redis保存一个空值,并返回给请求方,下次再查询的时候就能查到空值直接返回。同时设置一个过期时间,万一这个值后面又存进去了。不过,一般在存进去的时候会把值同步到Redis,所以也不用担心数据库实际有数据,Redis仍为空的情况。

第二种:利用布隆过滤器,布隆过滤器都听过吧?没听过不要紧,最下面会说。首先将数据同步到布隆过滤器,接着再查询时判断数据不在布隆过滤器(布隆过滤器只能判断不存在),如果不存在就直接返回空数据,否则就去缓存中查找数据。看下图:

缓存击穿

出现的场景

当一个访问频繁的热点数据在Redis中突然失效时,大量的请求就会绕过Redis,直接访问数据库,相当于凿穿了Redis,这个情况其实和缓存穿透很类似,只是击穿是在缓存突然失效的时候无法找到缓存,直接访问了数据库。这种现象我们叫做缓存击穿。

解决办法

缓存击穿的解决办法也不少,主要分为以下几种:

第一种:设置热点数据为永不过期,这样就不会出现击穿的现象;

第二种:利用分布式锁,在热点数据失效后,保证只有一个线程去访问数据库,访问数据库后就把查询到的数据缓存到Redis,这样,后面的数据就不会出现击穿的情况。如下图:

缓存雪崩

出现的场景

缓存雪崩指在某一段时间内,缓存大量过期,或者Redis服务直接宕机,导致大量的缓存无法命中,越积越多,就像雪花一样,最后引起大范围的崩塌,就好像雪崩了一样。其本质也是直接访问了数据库,只是出现的情况和上面的击穿和穿透不一样。但严重的不是缓存的集中过期,而是Redis服务的宕机,我想,大家应该都能想明白这其中的道理。

解决办法

解决的办法嘛其实也很简单:

第一种:针对集中过期的数据,设置基数+随机数的过期时间,这样就不会出现缓存集中过期的场景,或者设置锁,限制绕过缓存访问数据库的线程数量;

第二种:针对Redis服务宕机的情况,使用Redis主从、集群都是很好的解决方案,但也要根据实际情况和成本出发去考虑问题。

布隆过滤器

关于布隆过滤器的使用,博主在先前的博客中有详细介绍过,传送门:Java开发 - 布隆过滤器初体验

所以,此处不再赘述,你只需要知道的是:布隆过滤器只能判断不存在某个数据,而不能判断存在。

结语

伴随着轻快的下课铃声,额...不是,伴随着博主留下一个个链接之后,本篇博客就要跟大家说再见了,学习使我快乐,不知道这篇博客能不能带给你快乐呢?咱们今天就讲到这里,下一篇讲什么,博主要好好想想,有可能是Kafka,也有可能是RabbitMQ,我再纠结纠结。

### Spring Boot 中整合 Redis 并操作各种数据类型 #### 配置 Redis 连接 在 `application.yml` 文件中配置 Redis 的连接参数,如下所示: ```yaml spring: redis: host: localhost port: 6379 password: database: 10 ``` 此部分配置定义了 Redis 实例的位置、端口以及其他必要的属性[^3]。 --- #### String 类型的操作 对于字符串类型的存储和获取,可以使用 `opsForValue()` 方法。以下是具体实现方式: - **设置值** 将一个键值对存入 Redis: ```java @Autowired private StringRedisTemplate redisTemplate; public void setString(String key, String value) { redisTemplate.opsForValue().set(key, value); } ``` - **获取值** 根据给定的键从 Redis 中读取对应的值: ```java public String getString(String key) { return (String) redisTemplate.opsForValue().get(key); } ``` 上述代码展示了如何利用 `redisTemplate.opsForValue().set()` 和 `.get()` 来完成基本的字符串写入与查询功能[^1]。 --- #### Hash 类型的操作 哈希结构允许将多个字段及其关联的值作为一个整体进行管理。下面是如何执行哈希表的增删改查操作的例子: - **批量插入多组键值对** 借助 `putAll()` 函数一次性向某个命名空间下的散列表填充若干条记录: ```java Map<String, Object> map = new HashMap<>(); map.put("field1", "value1"); map.put("field2", "value2"); redisTemplate.opsForHash().putAll("myhash", map); ``` - **单个字段更新/新增** 如果仅需修改某一项,则可单独调用 `put()` 方法来处理特定项的数据变更需求: ```java redisTemplate.opsForHash().put("myhash", "newField", "newValue"); ``` 这些函数提供了灵活的方式来管理和维护复杂的嵌套关系中的子节点信息[^2]。 --- #### List 类型的操作 列表是一种有序集合形式,在实际应用中有广泛用途。这里列举几个常用命令说明其工作原理: - **左推入元素至队列头部** 向已存在的链表左侧追加新成员实例演示: ```java redisTemplate.opsForList().leftPush("mylist", "item1"); ``` - **右弹出最后一个项目** 当需要移除并返回最末端的一项时可用以下语句达成目的: ```java String lastItem = (String) redisTemplate.opsForList().rightPop("mylist"); ``` 以上两步分别代表了双向动态调整数组长度的能力体现之一方面[^4]。 --- #### Set 类型的操作 无序不重复集合作为另一种基础抽象模型同样重要。下面是关于它的简单介绍: - **添加唯一元素进入群组之中** 确保每次加入的新实体不会与其他已有者发生冲突: ```java redisTemplate.opsForSet().add("myset", "memberA", "memberB"); ``` - **随机抽取其中的一个样本出来查看** 可以轻松实现概率分布均匀采样的效果: ```java Object randomMember = redisTemplate.opsForSet().randomMember("myset"); ``` 这种特性非常适合用来构建抽奖类业务逻辑场景下所需的功能模块[^5]。 --- #### ZSet(Sorted Set)类型的操作 带权重排序后的集合具备更多高级特性的支持能力。比如按分数高低排列展示排行榜等功能都可以依赖于此种机制得以高效解决: - **增加带有评分等级的信息单元进去体系内部保存起来备用** 结合分值一起录入待检索的目标对象详情资料: ```java redisTemplate.opsForZSet().add("myleaderboard", "playerX", 85.5d); ``` - **依据范围筛选符合条件的结果呈现出来供进一步分析判断所用** 提取出前几名表现优异者的名单清单作为最终输出结果的一部分组成部分: ```java Set<ZSetOperations.TypedTuple<Object>> topPlayers = redisTemplate.opsForZSet() .reverseRangeWithScores("myleaderboard", 0, 2); ``` 这样就可以方便快捷地统计出各个维度上的优胜选手情况一览表[^6]。 --- ### 总结 通过上述描述可以看出,在 Spring Boot 应用程序里集成 Redis 不但能够简化开发流程而且还能极大地提升性能效率水平。无论是简单的 Key-Value 存储还是复杂的关系建模都能找到合适的解决方案予以应对满足不同层次的需求标准。 ---
评论 46
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CodingFire

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值