基于Java实现Redis多级缓存方案

网友投稿 545 2022-08-18


基于Java实现Redis多级缓存方案

目录一、多级缓存1. 传统缓存方案2. 多级缓存方案二、JVM本地缓存1. 实用案例三、缓存一致性1. 常见方案1.1 设置有效期1.2 同步双写1.3 异步通知2. 基于Canal的异步通知2.1 mysql主从复制2.2 canal 工作原理

一、多级缓存

1. 传统缓存方案

请求到达tomcat后,先去redis中获取缓存,不命中则去mysql中获取

2. 多级缓存方案

tomcat的请求并发数,是远小于redis的,因此tomcat会成为瓶颈利用请求处理每个环节,分别添加缓存,减轻tomcat压力,提升服务性能

二、JVM本地缓存

缓存是存储在内存中,数据读取速度较快,能大量减少对数据库的访问,减少数据库压力

分布式缓存,如redis - 优点: 存储容量大,可靠性好,可以在集群中共享 - 缺点: 访问缓存有网络开销 - 场景: 缓存数据量大,可靠性高,需要在集群中共享的数据

进程本地缓存, 如HashMap, GuavaCache- 优点:读取本地内存,没有网络开销,速度更快- 缺点:存储容量有限,可靠性低(如重启后丢失),无法在集群中共享- 场景:性能要求高,缓存数据量少

1. 实用案例

Caffeine是一个基于java8开发的,提供了近乎最佳命中率的高性能的本地缓存库目前spring内部的缓存用的就是这个

com.github.ben-manes.caffeine

caffeine

3.0.5

package com.erick.cache;

import com.github.benmanes.caffeine.cache.Cache;

import com.github.benmanes.caffeine.cache.Caffeine;

import java.time.Duration;

public final class CacheUtil {

private static int expireSeconds = 2;

public static Cache cacheWithExpireSeconds;

private static int maxPairs = 1;

public static Cache cacheWithMaxPairs;

static {

/*过期策略,写完60s后过期*/

cacheWithExpireSeconds = Caffeine.newBuilder()

.expireAfterWrite(Duration.ofSeconds(expireSeconds))

.build();

/*过期策略,达到最大值后删除

* 1. 并不会立即删除,等一会儿才会删除

* 2. 会将之前存储的数据删除掉*/

cacheWithMaxPairs = Caffeine.newBuilder()

.maximumSize(maxPairs)

.build();

}

/*从缓存中获取数据

* 1. 如果缓存中有,则直接从缓存中返回

* 2. 如果缓存中没有,则去数据查询并返回结果*/

public static String getKHPyrTxAReyWithExHPyrTxARpire(String key) {

return cacheWithExpireSeconds.get(key, value -> {

return getResultFromDB();

});

http://}

public static String getKeyWithMaxPair(String key) {

return cacheWithMaxPairs.get(key, value -> {

return getResultFromDB();

});

}

private static String getResultFromDB() {

System.out.println("数据库查询");

return "db result";

}

}

package com.erick.cache;

import java.util.concurrent.TimeUnit;

public claHPyrTxARss Test {

@org.junit.Test

public void test01() throws InterruptedException {

CacheUtil.cacheWithExpireSeconds.put("name", "erick");

System.out.println(CacheUtil.getKeyWithExpire("name"));

TimeUnit.SECONDS.sleep(3);

System.out.println(CacheUtil.getKeyWithExpire("name"));

}

@org.junit.Test

public void test02() throws InterruptedException {

CacheUtil.cacheWithMaxPairs.put("name", "erick");

CacheUtil.cacheWithMaxPairs.put("age", "12");

System.out.println(CacheUtil.getKeyWithMaxPair("name"));

System.out.println(CacheUtil.getKeyWithMaxPair("age"));

TimeUnit.SECONDS.sleep(2);

System.out.println(CacheUtil.getKeyWithMaxPair("name")); // 查询不到了

System.out.println(CacheUtil.getKeyWithMaxPair("age"));

}

}

三、缓存一致性

1. 常见方案

1.1 设置有效期

给缓存设置有效期,到期后自动删除。再次查询时可以更新优势:简单,方便缺点:时效性差,缓存过期之前可能不一致场景:更新频率低,时效性要求比较低的业务

1.2 同步双写

在修改数据库的同时,直接修改缓存优势:有代码侵入,缓存与数据库强一致性缺点:代码进入,耦合性高场景:对一致性,失效性要求较高的缓存数据

1.3 异步通知

修改数据库时发送事件通知,相关服务监听到后修改缓存数据优势:低耦合,可以同时通知多个缓存服务缺点:时效性一把,可能存在缓存不一致问题场景:时效性一般,有多个服务需要同步

2. 基于Canal的异步通知

是阿里旗下的一款开源项目,基于java开发基于数据库增量日志解析,提供增量数据订阅和消费基于mysql的主从备份的思想

2.1 mysql主从复制

2.2 canal 工作原理

canal 模拟 MySQL slave 的交互协议,伪装自己为 MySQL slave ,向 MySQL master 发送dump 协议MySQL master 收到 dump 请求, 开始推送 binary log 给 slave (即 canal )canal 解析 binary log 对象(原始为 byte 流)


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:mybatis foreach 循环 list(map)实例
下一篇:mybatis使用foreach查询不出结果也不报错的问题
相关文章

 发表评论

暂时没有评论,来抢沙发吧~