谷粒商城实战笔记-153-缓存-缓存使用-改造三级分类业务

文章目录

一,153-缓存-缓存使用-改造三级分类业务

这一节的主要内容是改造查询三级分类的接口,将Redis缓存加入进来。

在查询三级分类时,先查redis,如果redis中有数据,则使用redis的数据,如果没有再查数据库,并将结果保存在redis中供后续请求使用。

c 复制代码
    private List<CategoryEntity> getCategoryCache() {
        long l = System.currentTimeMillis();

        String catelogJson = stringRedisTemplate.opsForValue().get(BasicTypeConstants.CATELOG_JSON);
        log.info("查询redis结束{}", System.currentTimeMillis() - l);
        List<CategoryEntity> cateList;
        if (StrUtil.isEmpty(catelogJson)) {
            //将数据库的多次查询变为一次
            cateList = this.baseMapper.selectList(null);
            stringRedisTemplate.opsForValue().set(BasicTypeConstants.CATELOG_JSON, JSON.toJSONString(cateList));
        } else {
            cateList = JSON.parseObject(catelogJson,  new TypeReference<List<CategoryEntity>>() {});
        }

        log.info("查询结束{}", System.currentTimeMillis() - l);
        return cateList;
    }

二,154-缓存-缓存使用-压力测试出的内存泄露及解决

在压测的过程中,可能会出现如下错误。

这是由于Spring Boot 2.0以后默认使用的Lettuce客户端所引发的一种内存溢出问题。

Lettuce客户端的引入

自Spring Boot 2.0版本起,Lettuce成为了操作Redis的默认客户端。Lettuce是基于Netty的网络通信框架实现的,它提供了异步的Redis操作能力,可以显著提高应用程序的性能。

堆外内存溢出问题

在使用Lettuce客户端时,可能会遇到OutOfDirectMemoryError错误。这是因为Lettuce使用Netty进行网络通信,而Netty默认的堆外内存设置可能不足以满足应用程序的需求。

问题分析

问题原因

  1. Lettuce的Bug:Lettuce客户端存在一个Bug,导致Netty在使用默认的堆外内存设置时,可能会发生内存溢出。

  2. 默认堆外内存设置 :Netty如果没有指定堆外内存,默认使用-Xmx300m,这可能不足以应对高并发场景。

解决方案

方案一:调整堆外内存

可以通过设置系统属性-Dio.netty.maxDirectMemory来增加Netty的堆外内存。但这种方法并不是最佳实践,因为它只是简单地增加内存,而没有解决根本问题。

方案二:切换到Jedis客户端

  1. 升级Lettuce客户端:如果问题是由Lettuce的Bug引起的,可以尝试升级到最新版本的Lettuce客户端。

  2. 切换到Jedis:如果升级Lettuce客户端后问题仍然存在,可以考虑切换回Jedis客户端。Jedis是Spring Boot之前默认使用的Redis客户端,它没有使用Netty,因此不会遇到堆外内存溢出的问题。在redis的starter中排除对lettuce的依赖,然后引入jedis的依赖。

c 复制代码
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>io.lettuce</groupId>
                    <artifactId>lettuce-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>

三,155-缓存-缓存使用-缓存击穿、穿透、雪崩

Redis在实际使用过程中,可能会遇到缓存击穿、缓存穿透和缓存雪崩等问题,这些问题严重影响了缓存的效率和系统的稳定性。

缓存击穿(Cache Breakthrough)

问题描述

缓存击穿是指一个非常热点的数据在某个时间点过期时,大量请求直接打在数据库上,导致数据库瞬时压力过大。

解决方案

  1. 设置过期时间:为缓存数据设置合理的过期时间,避免同时过期。
  2. 互斥锁:在缓存失效时,通过互斥锁保证同一时间只有一个请求能够访问数据库,其他请求等待或重试。
  3. 预热机制:在缓存数据即将过期前,提前更新缓存数据。

缓存穿透(Cache Penetration)

问题描述

缓存穿透是指查询一个不存在的数据,由于缓存和数据库中都没有,导致请求直接穿透缓存查询数据库。

解决方案

  1. 布隆过滤器:使用布隆过滤器拦截不存在的数据请求,避免对数据库的查询。
  2. 缓存空值:对于查询结果为空的操作也进行缓存,但可以设置较短的过期时间。
  3. 限制访问频率:对用户访问频率进行限制,避免恶意攻击。

缓存雪崩(Cache Avalanche)

问题描述

缓存雪崩是指在某一时刻,大量的缓存数据同时过期,导致大量请求直接访问数据库,造成数据库压力过大。

解决方案

  1. 分散缓存过期时间:使用随机时间或分片策略来分散缓存的过期时间,避免同时过期。
  2. 限流降级:在系统访问量剧增时,通过限流和降级策略保护系统。
  3. 高可用架构:使用Redis集群,提高缓存系统的可用性和容错性。

实例分析

缓存击穿示例

假设一个电商平台的商品详情页非常热门,缓存设置为10分钟过期。当缓存过期时,如果大量用户同时访问该页面,会导致数据库压力剧增。解决方案是在缓存数据中设置互斥锁,确保同一时间只有一个请求访问数据库。

缓存穿透示例

在电商平台搜索一个不存在的商品,如果没有布隆过滤器,每次搜索都会查询数据库,这会给数据库带来不必要的压力。解决方案是使用布隆过滤器拦截这些请求,避免对数据库的查询。

缓存雪崩示例

电商平台的促销活动导致大量商品缓存在某一时刻同时过期,如果此时用户访问量激增,数据库将承受巨大压力。解决方案是使用Redis集群分散缓存过期时间,并通过限流降级策略保护系统。

相关推荐
Oak Zhang27 分钟前
sharding-jdbc自定义分片算法,表对应关系存储在mysql中,缓存到redis或者本地
redis·mysql·缓存
门牙咬脆骨1 小时前
【Redis】redis缓存击穿,缓存雪崩,缓存穿透
数据库·redis·缓存
门牙咬脆骨1 小时前
【Redis】GEO数据结构
数据库·redis·缓存
wusong9992 小时前
mongoDB回顾笔记(一)
数据库·笔记·mongodb
猫爪笔记2 小时前
前端:HTML (学习笔记)【1】
前端·笔记·学习·html
Resurgence032 小时前
【计组笔记】习题
笔记
pq113_62 小时前
ftdi_sio应用学习笔记 3 - GPIO
笔记·学习·ftdi_sio
爱米的前端小笔记3 小时前
前端八股自学笔记分享—页面布局(二)
前端·笔记·学习·面试·求职招聘
寒笙LED5 小时前
C++详细笔记(六)string库
开发语言·c++·笔记
Dlwyz6 小时前
问题: redis-高并发场景下如何保证缓存数据与数据库的最终一致性
数据库·redis·缓存