【博学谷学习记录】超强总结,用心分享 |多级缓存


前言

缓存在日常开发中启动至关重要的作用,由于是存储在内存中,数据的读取速度是非常快的,能大量减少对数据库的访问,减少数据库的压力。


一、什么是多级缓存?

多级缓存就是充分利用请求处理的每个环节,分别添加缓存,减轻Tomcat压力,提升服务性能
在这里插入图片描述

1.JVM进程缓存

缓存在日常开发中启动至关重要的作用,由于是存储在内存中,数据的读取速度是非常快的,能大量减少对数据库的访问,减少数据库的压力。我们把缓存分为两类:

  • 分布式缓存,例如Redis:
    • 优点:存储容量更大、可靠性更好、可以在集群间共享
    • 缺点:访问缓存有网络开销
    • 场景:缓存数据量较大、可靠性要求较高、需要在集群间共享
  • 进程本地缓存,例如HashMap、GuavaCache:
    • 优点:读取本地内存,没有网络开销,速度更快
    • 缺点:存储容量有限、可靠性较低、无法共享
    • 场景:性能要求较高,缓存数据量较小
  • 进程本地缓存
    • Caffeine是一个基于Java8开发的,提供了近乎最佳命中率的高性能的本地缓存库。目前Spring内部的缓存使用的就是Caffeine。

    • 示例

      @Test
      void testBasicOps() {
      	// 创建缓存对象
      	Cache<String, String> cache = Caffeine.newBuilder().build();
          // 存数据
          cache.put("gf", "迪丽热巴");
          // 取数据,不存在则返回null
          String gf = cache.getIfPresent("gf");
          System.out.println("gf = " + gf);
          // 取数据,不存在则去数据库查询
          String defaultGF = cache.get("defaultGF", key -> {
          	// 这里可以去数据库根据 key查询value
          	return "柳岩";
          });
          System.out.println("defaultGF = " + defaultGF);
      }
      
    • Caffeine提供了三种缓存驱逐策略:

      • 基于容量:设置缓存的数量上限

        // 创建缓存对象
        Cache<String, String> cache = Caffeine.newBuilder()
        									  .maximumSize(1) // 设置缓存大小上限为 1
        									  .build();
        
      • 基于时间:设置缓存的有效时间

        // 创建缓存对象
        Cache<String, String> cache = Caffeine.newBuilder()
                .expireAfterWrite(Duration.ofSeconds(10)) // 设置缓存有效期为 10 秒,从最后一次写入开始计时 
                .build();
        
      • 基于引用:设置缓存为软引用或弱引用,利用GC来回收缓存数据。性能较差,不建议使用。

2.Redis缓存预热

Redis缓存会面临冷启动问题:

冷启动:服务刚刚启动时,Redis中并没有缓存,如果所有商品数据都在第一次查询时添加缓存,可能会给数据库带来较大压力。

缓存预热:在实际开发中,我们可以利用大数据统计用户访问的热点数据,在项目启动时将这些热点数据提前查询并保存到Redis中。

3.NGINX本地缓存

多级缓存的实现离不开Nginx编程,OpenResty为Nginx提供了shard dict的功能,可以在nginx的多个worker之间共享数据,实现缓存功能。

4.缓存同步

大多数情况下,浏览器查询到的都是缓存数据,如果缓存数据与数据库数据存在较大差异,可能会产生比较严重的后果。所以我们必须保证数据库数据、缓存数据的一致性,这就是缓存与数据库的同步。
数据同步策略
缓存数据同步的常见方式有三种:

  1. 设置有效期:给缓存设置有效期,到期后自动删除。再次查询时更新
    • 优势:简单、方便
    • 缺点:时效性差,缓存过期之前可能不一致
    • 场景:更新频率较低,时效性要求低的业务
  2. 同步双写:在修改数据库的同时,直接修改缓存
    • 优势:时效性强,缓存与数据库强一致
    • 缺点:有代码侵入,耦合度高;
    • 场景:对一致性、时效性要求较高的缓存数据
  3. 异步通知:修改数据库时发送事件通知,相关服务监听到通知后修改缓存数据
    • 优势:低耦合,可以同时通知多个缓存服务
    • 缺点:时效性一般,可能存在中间不一致状态
    • 场景:时效性要求一般,有多个服务需要同步
      而异步实现又可以基于MQ或者Canal来实现:
      1)基于MQ的异步通知:
      在这里插入图片描述
      2)基于Canal的通知
      引入依赖
<dependency>
    <groupId>top.javatool</groupId>
    <artifactId>canal-spring-boot-starter</artifactId>
    <version>1.2.1-RELEASE</version>
</dependency>

编写配置:

canal:
  destination: test# canal的集群名字,要与安装canal时设置的名称一致
  server: 192.168.150.101:11111 # canal服务地址

修改实体类:通过@Id、@Column、等注解完成Item与数据库表字段的映射:
编写监听器:通过实现EntryHandler接口编写监听器,监听Canal消息

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值