传统缓存的问题
传统的缓存策略一般是请求到达Tomcat后,先查询Redis,如果未命中则查询数据库,存在下面的问题:
●请求要经过Tomcat处理,Tomcat的性能成为整个系统的瓶颈
●Redis缓存失效时,会对数据库产生冲击
多级缓存方案
多级缓存就是充分利用请求处理的每个环节,分别添加缓存,减轻Tomcat压力,提升服务性能:
JVM进程缓存
本地进程缓存
缓存在日常开发中启动至关重要的作用,由于是存储在内存中,数据的读取速度是非常快的,能大量减少对数据库的访问,减少数据库的压力。我们把缓存分为两类:
●分布式缓存,例如Redis:
优点:存储容量更大、可靠性更好、可以在集群间共享
缺点:访问缓服务器托管网存有网络开销
场景:缓存数据量较大、可靠性要求较高、需要在集群间共享
●进程本地缓存,例如HashMap、GuavaCache:
优点:读取本地内存,没有网络开销,速度更快
缺点:存储容量有限、可靠性较低、无法共享
场景:性能要求较高,缓存数据量较小
Caffeine
Caffeine是一个基于Java8开发的,提供了近乎最佳命中率的高性能的本地缓存库。目前Spring内部的缓存使用的就是Caffeine。GitHub地址: https://github.com/ben-manes/caffeine/wiki/Home-zh-CN
Caffeine简单测试
public class CaffeineTest {
/*
基本用法测试
*/
@Test
void testBasicOps() {
// 创建缓存对象
Cache 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("d服务器托管网efaultGF = " + defaultGF);
}
/*
基于大小设置驱逐策略:
*/
@Test
void testEvictByNum() throws InterruptedException {
// 创建缓存对象
Cache cache = Caffeine.newBuilder()
// 设置缓存大小上限为 1
.maximumSize(1)
.build();
// 存数据
cache.put("gf1", "柳岩");
cache.put("gf2", "范冰冰");
cache.put("gf3", "迪丽热巴");
// 延迟10ms,给清理线程一点时间
Thread.sleep(10L);
// 获取数据
System.out.println("gf1: " + cache.getIfPresent("gf1"));
System.out.println("gf2: " + cache.getIfPresent("gf2"));
System.out.println("gf3: " + cache.getIfPresent("gf3"));
}
/*
基于时间设置驱逐策略:
*/
@Test
void testEvictByTime() throws InterruptedException {
// 创建缓存对象
Cache cache = Caffeine.newBuilder()
.expireAfterWrite(Duration.ofSeconds(1)) // 设置缓存有效期为 10 秒
.build();
// 存数据
cache.put("gf", "柳岩");
// 获取数据
System.out.println("gf: " + cache.getIfPresent("gf"));
// 休眠一会儿
Thread.sleep(1200L);
System.out.println("gf: " + cache.getIfPresent("gf"));
}
}
Caffeine提供了三种缓存驱逐策略:
●基于容量:设置缓存的数量.上限
//创建缓存对象
Cache cache = Caffeine .newBuilder()
. maximumSize(1) //设置缓存大小上限为1
. build() ;
●基于时间:设置缓存的有效时间
//创建缓存对象
Cache cache = Caffeine .newBuilder()
. expireAfterWrite (Durati on. ofSeconds(10)) //设置缓存有效期为10秒,从最后一次写入开始计时
.build() ;
●基于引用:设置缓存为软引用或弱引用,利用GC来回收缓存数据。性能较差,不建议使用。
在默认情况下,当一个缓存元素过期的时候,Caffeine不会 自动立即将其清理和驱逐。而是在一-次读或写操作后, 或者在空闲时间完成对失效数据的驱逐。
案例
添加缓存配置类
Configuration
public class CacheConfig {
/**
* 创建一个缓存对象,用于存储商品信息
* 缓存初始容量为100,最大容量为10000
*
* @return 返回Cache类型的缓存对象
*/
@Bean
public Cache itemCache() {
return Caffeine.newBuilder()
.initialCapacity(100)
.maximumSize(10_000)
.build();
}
/**
* 创建一个缓存对象,用于存储商品库存信息
* 缓存初始容量为100,最大容量为10000
*
* @return 返回Cache类型的缓存对象
*/
@Bean
public Cache stockCache() {
return Caffeine.newBuilder()
.initialCapacity(100)
.maximumSize(10_000)
.build();
}
}
测试代码
@Autowired
private Cache itemCache;
@Autowired
private Cache stockCache;
@GetMapping("/{id}")
public Item findById(@PathVariable("id") Long id) {
return itemCache.get(id, key -> itemService.query()
.ne("status", 3).eq("id", key)
.one());
}
@GetMapping("/stock/{id}")
public ItemStock findStockById(@PathVariable("id") Long id) {
return stockCache.get(id, key -> stockService.getById(key));
}
第一次查询访问了数据库
第二次查询没有访问数据库
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net
相关推荐: 【密码学】为什么不推荐在对称加密中使用CBC工作模式
引言 这篇文章是我在公司内部分享中一部分内容的详细版本,如标题所言,我会通过文字、代码示例、带你完整的搞懂为什么我们不建议你使用cbc加密模式,用了会导致什么安全问题,即使一定要用需要注意哪些方面的内容。 注:本文仅从安全角度出发,未考虑性能与兼容性等因素 工…