4.1 JVM进程缓存
一、传统缓存的问题
传统的缓存策略一般是请求到达Tomcat后,先查Redis,如果未命中,则查询数据库,存在如下问题:
请求要经过Tomcat处理,Tomcat的性能称为整个系统的瓶颈
Redis缓存失效时,会对数据库产生冲击
多级缓存:就是充分利用请求处理的每一个环节,分别添加缓存,减轻Tomcat压力,提升服务性能

备注:可以将nginx与Redis调用的服务做成集群,前面再加一个nginx做反向代理

反向代理配置:
http { include mime.types; default_type application/octet-stream; sendfile on; #tcp_nopush on; keepalive_timeout 65; # nginx的业务集群,nginx本地缓存 upstream nginx-cluster{ server 192.168.150.101:8081; } # 监听地址+端口 server { listen 80; server_name localhost; # 反向代理 location /api { proxy_pass http://nginx-cluster; } location / { root html; index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } }
二、初始Caffeine
缓存在日出厂开发中起到至关重要的作用,由于是存储在内存中,数据的读取速度是非常快的,能大量减少对数据库的访问,减少数据库的压力。我们吧缓存分为两类:
分布式缓存:例如Redis:
优点:存储容量更大、可靠性更好、可以在集群间共享
缺点:访问缓存有网络开销
场景:缓存数据量较大、可靠性要求较高、需要在集群间共享
进程本地缓存,例如HashMap、GuavaCache:
优点:读取本地内存,没有网络开销,速度更快
缺点:存储容量有限、可靠性较低、无法共享
场景:性能要求较高,缓存数据量较小
Caffeine是一个基于Java8开发的,提供了近乎最佳命中的高性能本地缓存库。目前Spring内部的缓存使用的就是Caffeine,GitHubub地址:https://github.com/ben-manes/caffeine
简单示例:
引入坐标
<dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId>caffeine</artifactId> </dependency>代码示例
public void testBasicOps() { // 创建缓存对象 Cache<String, String> cache = Caffeine.newBuilder.build(); // 存数据 cache.put("ls", "LonelySnow"); // 取数据,不存在返回null String ls = cache.getIfPresent("ls"); System.out.print("ls = " + ls); // 取数据,不存在则去数据库查询 String defaultLS = cache.get("defaultLS", key -> { // 这里可以去数据库中查询,根据key去查询,key的值就是defaultLS // 查询数据库的方法(参数-key) return "SnowLonely"; }); System.out.print("defaultLS = " + defaultLS); }备注:cache.get过程中,如果不存在,直接调用数据库,,得到数据库的结果后,直接存入缓存,并返回
Caffeine提供了三种缓存驱逐策略
基于容量:设置缓存的数量上限
// 创建缓存对象 Cache<String, String> cache = Caffeine.newBuilder() .maximumSize(1) // 设置缓存大小上限为1 .build();基于时间:设置缓存的有效时间
// 创建缓存对象 Cache<String, String> cache = Caffeine.newBuilder() .expireAfterWrite(Duration.ofSeconds(10)) // 设置缓存有效期为10秒,从最后一次写入时开始计时 .build();基于引用:设置缓存为软引用或弱引用,利用那个GC来回收缓存数据。性能较差,不建议使用。
默认情况下,当一个缓存元素过期的时候,Caffeine不会自动立即将其清理和驱逐。而是在一次读或写操作后,或在空闲时间完成对失效数据的驱逐
三、实现进程缓存
声明Bean配置
@Configuration public class CaffeineConfig() { @Bean public Cache<Long, Item> itemCache() { // Cache<>声明的key与value,跟实际情况定义 return Caffeine.newBuilder() .initialCapacity(100) // 初始化大小为100 .maximumSize(10_000) // 设置缓存上线为10000 .build(); } // 上面的Bean可以创建多个 }代码中写入
// 在方法中注入对应的Bean @Autowired private Cache<Long, Item> itemCache; // 代码中就可以正常操作 // 取数据,不存在则去数据库查询 String defaultLS = cache.get("defaultLS", key -> { // 这里可以去数据库中查询,根据key去查询,key的值就是defaultLS // Service.查询数据方法(key); return "SnowLonely"; });
最后更新于
这有帮助吗?