【大型电商项目开发】缓存的使用-本地缓存与分布式缓存-整合redis-41

导读:本篇文章讲解 【大型电商项目开发】缓存的使用-本地缓存与分布式缓存-整合redis-41,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

一:缓存

1.缓存使用

1)频繁访问数据库,势必会对数据库造成很大的压力,降低系统性能。所以我们可以把不会经常变化的,或者变化对用户影响不大的数据保存到缓存中。
2)为了系统性能的提升,我们一般都会将部分数据放入缓存中,加速访问。而 db 承担数据落盘以及持久化的工作。
3)哪些数据适合放入缓存?

  • 即时性、数据一致性要求不高的
  • 访问量大且更新频率不高的数据(读多,写少)

4)举例:电商类应用,商品分类,商品列表等适合缓存并加一个失效时间(根据数据更新频率 来定),后台如果发布一个商品,买家需要 5 分钟才能看到新的商品一般还是可以接受的。

2.读模式缓存使用流程

1)流程图
在这里插入图片描述
2)代码实现

data = cache.load(id);//从缓存加载数据 
If(data == null){ 
    data = db.load(id);//从数据库加载数据 
    cache.put(id,data);//保存到 cache 中 
}
return data;

3)在开发中,凡是放入缓存中的数据我们都应该指定过期时间,使其可以在系统即使没 有主动更新数据也能自动触发数据加载进缓存的流程。避免业务崩溃导致的数据永久不一致 问题。

3.本地缓存——map集合

本地缓存:同一个进程,同一个jvm,在本地保存一个副本。我们可以使用map作为本地缓存,数据以内存的方式进行保存
1)示例代码

private Map<String,Object> cache = new HashMap<>();
//先从缓存中获取数据,如果缓存有,就是用缓存的
Object data = cache.get("msg");
if(data == null){
//首先从数据库获取
Objetc data = db.get("msg");
//其次保存到map中
cache.put("msg",data );
}
return data;
  • 如果缓存有,就是用缓存的
  • 如果没有,就先从数据库获取,然后保存到缓存中

2)优点&缺点
优点:如果项目是单体架构,只部署在一台服务器,不会有任何问题,使用本地缓存效果很好,很快。
在这里插入图片描述
缺点:在分布式系统下,一个模块可能部署在若干服务器上,每个服务器都带一个本地缓存,如果不能负载均衡到一个服务器就会导致,访问到不同服务器时,会重新查询数据库。并且修改数据后,不能保证每一个服务器内的缓存一致,会发生数据不一致的情况。

  • 本地缓存
    本地缓存
  • 分布式缓存
    分布式缓存
    结论:所以在分布式的系统下,不要使用本地缓存,推荐将缓存提取出来,作为一个中间件。都集中的给一个地方存放数据,就会保证数据的一致性问题。

二:SpringBoot整合redis

1.redis的好处

1)使用redis作为集群,分片存储,提升存储容量
2)打破了本地缓存的容量限制
3)易于维护,容易做到高可用,高性能

2.整合redis

1)服务器安装redis
服务器安装redis传送门
2)在product的pom文件中引入redis依赖

<!--引入redis-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

3)在application.yml文件配置redis

spring:
  ## 指定redis的地址
  redis:
  ## 虚拟机或者服务器的的ip
    host: 127.0.0.1
    port: 6389

4)使用SpringBoot自动配置好的StringRedisTemplate来操作redis

  • redis主要是K,V结构
  • StringRedisTemplate的k和v都是字符串
  • redis可以当作map来使用,存放数据用key,数据值用value

5)在test类测试redis

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Test
    public void testStringRedisTemplate(){
        //key-hello  value-word
        ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
        //保存
        ops.set("hello","word_"+ UUID.randomUUID().toString());
        //查询
        String hello = ops.get("hello");

三:改造三级分类业务-将三级分类信息存入缓存

1.代码逻辑改造

    @Override
    public Map<String, List<Catalog2Vo>> getCatalogJson() {
        //1.加入缓存逻辑,缓存中存入的数据是json字符串
        String catalogJson = redisTemplate.opsForValue().get("catalogJson");
        if(StringUtils.isEmpty(catalogJson)){
            //2.缓存没有就查询数据库
            Map<String, List<Catalog2Vo>> catalogJsonFromDb = getCatalogJsonFromDb();
            //3.将查到的数据放进缓存,将对象转化为json放进缓存
            String s = JSON.toJSONString(catalogJsonFromDb);
            redisTemplate.opsForValue().set("catalogJson",s);
            return catalogJsonFromDb;
        }
        //转为指定的对象
        TypeReference<Map<String, List<Catalog2Vo>>> typeReference = new TypeReference<Map<String, List<Catalog2Vo>>>() {};
        Map<String, List<Catalog2Vo>> result = JSON.parseObject(catalogJson,typeReference);
        return result;
    }
  • JSON跨语言,跨平台的兼容
  • 加入缓存逻辑,缓存中的数据就是json字符串
  • 给缓存中放入json字符串。拿出的json字符串,还要逆转为能用的对象类型(序列化与反序列化)

2.访问商城首页测试

在这里插入图片描述
成功存入redis

三:压力测试出的内存泄漏与解决

1.压力测试

用JMeter模拟高并发下访问三级分类,就会报错!
在这里插入图片描述

2.原因分析——堆外内存溢出

1)springboot2.0版本以后,默认使用lettuce作为操作redis的客户端,他使用netty进行网络通信。
2)lettuce的bug导致netty对外内存溢出。netty如果没有指定堆外内存,默认使用-Xmx300m
3)netty底层会统计内存的使用量,使用了多少就会减去多少,直到发生堆外内存溢出

3.解决方案

注:不能通过使用-Dio.netty.maxDirectMemory只去调大堆外内存
1)升级lettuce客户端,使用netty进行网络底层框架,吞吐量极大
2)切换使用jedis客户端,老版客户端,好久没更新

4.引入jedis

<!--引入redis-->
        <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>
  • 切换jedis客户端以后,吞吐量提高了四倍,响应时间提高了四倍
  • 上线之后会切换到lettuce,然后定位问题

5.springRedisTemplate与lettuce,jedis之间的关系

  • lettuce,jedis都是操作redis的底层客户端
  • spring对lettuce,jedis会再次封装为springRedisTemplate
  • springRedisTemplate可以直接操作lettuce和jedis

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/84107.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!