一,多级缓存解决方案
1,当项目发展到一定阶段,积累到一定用户时,就会出现一个数据量过大,查询频率过高的问题,针对以上特点,我们进行逐一分析,首选是数据量大,这个挑战是在存储方面,如果我们做技术选型的话,无非就是两种选择,一种是关系型数据库,另一种是非关系型数据库,显然,在存储大数据方面非关系型数据库更合适一些,以我们目前掌握的技术而言,选择MongoDB存储要比MySQL更合适一些。
目前我们已经实现了物流信息的保存、更新操作,基本功能已经了ok了,但是有个问题我们还没解决,就是前面提到的并发大的问题,一般而言,解决查询并发大的问题,常见的手段是为查询接口增加缓存,从而可以减轻持久层的压力。
按照我们以往的经验,在查询接口中增加Redis缓存即可,将查询的结果数据存储到Redis中,执行查询时首先从Redis中命中,如果命中直接返回即可,没有命中查询MongoDB,将解决写入到Redis中。
这样就解决问题了吗?其实并不是,试想一下,如果Redis宕机了或者是Redis中的数据大范围的失效,这样大量的并发压力就会进入持久层,会对持久层有较大的影响,甚至可能直接崩溃。
如何解决该问题呢,可以通过多级缓存的解决方案来进行解决。
二,什么是多级缓存
在用户的一次请求中,可以设置多个缓存以提升查询的性能,能够快速响应。
- 如果Redis依然没有命中的话,请求就会进入到Tomcat,也就是执行我们写的程序,在程序中可以设置进程级的缓存,如果命中直接返回即可。
- 如果进程级的缓存依然没有命中的话,请求才会进入到持久层查询数据。
以上就是多级缓存的基本的设计思路,其核心思想就是让每一个请求节点尽可能的进行缓存操作。
查询时候可能会存在高并发问题,查询接口增加缓存,减轻持久层的压力
通过多级缓存解决并发:
(nginx加lua脚本去redis中查询 未完成)
第一次查询未命中查询mongdb,第二次查询命中查询一级缓存
①一级缓存:tomcat jvm进程缓存作为一级缓存 使用caffeine(进程级的缓存框架)
-
导入依赖、配置参数:初始容量 最大容量
-
定义config配置文件、配置数据、注入bean
caffeine内存驱逐策略:lfu删除不常用 有效时间 设置为软引用(不太好)
②二级缓存:redis作为二级缓存
-
使用SpringCache进行缓存数据的存储和读取
-
SpringCache默认使用jdk的序列化方式缓存数据到redis中,阅读不方便,对redisCacheManager进行配置,使用json格式序列化
在添加缓存数据方法上添加@Cacheable注解
缓存不一致问题
-
方法一:使用 @CachePut(value = "transport-info", key = "#p0") 更新缓存数据,只要mongdb中更新,reids就会更新,删除一级缓存的数据,用户查询时查询到二级缓存 更新到caffeine中(只适合单体架构)
-
方法二:在多集群的环境下,让每个节点接收到消息就可以了,如果用mq就需要在每一个caffeine中设置消息队列,来监听消息,占用不少资源,太浪费了。其实本质就是redis更新了,没有通知另外一个节点的caffeine,使用的是redis中的发布订阅功能,相当于简化版的mq。删除caffeine——redis更新后发起通知——caffeine订阅redis的消息,这个时候caffeine中的数据也会更新