Blage's Coding Blage's Coding
Home
算法
  • 手写Spring
  • SSM
  • SpringBoot
  • JavaWeb
  • JAVA基础
  • 容器
  • Netty

    • IO模型
    • Netty初级
    • Netty原理
  • JVM
  • JUC
  • Redis基础
  • 源码分析
  • 实战应用
  • 单机缓存
  • MySQL

    • 基础部分
    • 实战与处理方案
    • 面试
  • ORM框架

    • Mybatis
    • Mybatis_Plus
  • SpringCloudAlibaba
  • MQ消息队列
  • Nginx
  • Elasticsearch
  • Gateway
  • Xxl-job
  • Feign
  • Eureka
  • 面试
  • 工具
  • 项目
  • 关于
🌏本站
🧸GitHub (opens new window)
Home
算法
  • 手写Spring
  • SSM
  • SpringBoot
  • JavaWeb
  • JAVA基础
  • 容器
  • Netty

    • IO模型
    • Netty初级
    • Netty原理
  • JVM
  • JUC
  • Redis基础
  • 源码分析
  • 实战应用
  • 单机缓存
  • MySQL

    • 基础部分
    • 实战与处理方案
    • 面试
  • ORM框架

    • Mybatis
    • Mybatis_Plus
  • SpringCloudAlibaba
  • MQ消息队列
  • Nginx
  • Elasticsearch
  • Gateway
  • Xxl-job
  • Feign
  • Eureka
  • 面试
  • 工具
  • 项目
  • 关于
🌏本站
🧸GitHub (opens new window)
  • SpringCloudAlibaba

    • Nacos

    • Dubbo

    • Zookeeper

    • Sentinel

    • Seata

      • 分布式事务—Seata
      • 分布式缓存
        • 1.本地缓存-caffeine
        • 2.多级缓存(OpenResty)
        • 3.Canal
          • 原理
  • MQ消息队列

  • Nginx

  • Elasticsearch

  • Gateway

  • Xxl-job

  • Feign

  • Eureka

  • 中间件
  • SpringCloudAlibaba
  • Seata
phan
2023-05-15
目录

分布式缓存

# 分布式缓存

​ NGINX本地缓存——>redis缓存——>Tomcat进程缓存——>数据库

# 1.本地缓存-caffeine

JVM进程缓存

  • 优点:读取本地(Tomcat服务器)内存,没有网络开销,速度快
  • 缺点:本地进程缓存容量上限为JVM设定的堆内存最大值,无法共享。
Cache<String, String> cache = Caffeine.newBuilder().build();
// 存数据
cache.put("name", "张三");
// 取数据,如果不存在返回空
String name = cache.getIfPresent("name");
// 取数据,包含两个参数:参数一:缓存的key,参数二:Lambda表达式,表达式参数就是缓存的key,方法体是查询数据库的逻辑
// 优先根据key查询JVM缓存,如果未命中,则执行参数二的Lambda表达式去数据库数据库查数据,并加入到缓存。
String defaultGF = cache.get("defaultGF", key -> {
    // 根据key去数据库查询数据
    return "李四";
});
1
2
3
4
5
6
7
8
9
10
11

caffeine初始化创建时,可以设置缓存的容量上限和缓存的有效时间

Cache<String, String> cache = Caffeine.newBuilder().maximumSize(1).build();

Cache<String, String> cache = Caffeine.newBuilder().expireAfterWrite(Duration.ofSeconds(10)).build();
1
2
3

# 2.多级缓存(OpenResty)

分布式下每台服务器保存的本地缓存不会共享,因此需要在负载均衡配置中设置 hash+请求uri,保证相同地址的请求访问的是同一台机器的缓存。

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

缓存预热:项目启动时将热点数据提前查询并保存到redis中(实现接口中的afterPropertiesSet方法,会在项目启动创建Bean的成员变量后执行)

ObjectMapper的writeValueAsString方法将对象转化成String

@Component
public class RedisHandler implements InitializingBean{
	@Autowired
	private StringRedisTemplate redisTemplate;
    //spring默认的json处理工具
    private static final ObjectMapper MAPPER = new ObjectMapper();

	@Override
	public void afterPropertiesSet throws Exception{//初始化缓存}
}
1
2
3
4
5
6
7
8
9
10

整个查询逻辑:本地缓存—>redis—>Tomcat服务器内存cache—>DB

function read_data(key, expire, path, params)
    -- 查询本地缓存
    local val = item_cache:get(key)
    if not val then
        ngx.log(ngx.ERR, "本地缓存查询失败,尝试查询Redis, key: ", key)
        -- 查询redis
        val = read_redis("127.0.0.1", 6379, key)
        -- 判断查询结果
        if not val then
            ngx.log(ngx.ERR, "redis查询失败,尝试查询http, key: ", key)
            -- redis查询失败,去查询http
            val = read_http(path, params)
        end
    end
    -- 查询成功,把数据写入本地缓存
    item_cache:set(key, val, expire)
    -- 返回数据
    return val
end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 3.Canal

解决缓存和数据库同步的三种方法:

  • 给缓存设置有效期,到期后自动删除。再次查询时会搜索数据库进行更新
  • 同步双写,更新数据库的同时,直接修改缓存。两者绑定一个事务,但是代码耦合度高
  • 异步通知,修改数据库时发送事件通知,修改缓存。

# 原理

Canal会把自己伪装成MySQL的一个slave节点,监听master的binary log变化,然后再把变化消息通知给Canal客户端。和MQ类似,区别在于Canal不需要推送消息,采用的是监听机制。

  • 添加maven依赖
  • 配置canal监听的数据库名称,canal服务端地址
  • 实现数据更新后JAVA逻辑,@CanalTable注解监听的表
@CanalTable("tb_item")
@Component
public class ItemHandler implements EntryHandler<Item> {
    @Autowired
    private Cache<Long, Item> itemCache;

    @Override
    public void insert(Item item) {
        itemCache.put(item.getId(), item);
    }
    @Override
    public void update(Item before, Item after) {
        itemCache.put(after.getId(), after);
    }
    @Override
    public void delete(Item item) {
        itemCache.invalidate(item.getId());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  • 另外通过注解告诉Canal封装的Item类,@Id标记表中的id,@Transient标记不属于表中的字段。
编辑 (opens new window)
#中间件#SpringCloudAlibaba
上次更新: 2023/12/15, 15:49:57
分布式事务—Seata
RabbitMQ基础

← 分布式事务—Seata RabbitMQ基础→

Theme by Vdoing | Copyright © 2023-2024 blageCoder
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式