前言
在最近的问题咨询中,有不少的读者朋友谈到缓存就比较懵圈,说是项目都在用,但是却不是很懂,希望可以讲一讲。所以,这次就来个《图解缓存实战五部曲》,从原理到实战,给你安排得明明白白。屁话不多说,我们开整!
我们会以《最新 Spring Cloud Alibaba 实战开发》中完成的微服务实战项目smartcar-project, 为它加入缓存来提升性能作为案例代码。
一、缓存
1.1.为什么要用缓存?
在项目开发完成后,往往会发现部署后的系统,运行速度不如人意,此时,就需要做性能调优,方法很多,比如给表加索引、动静资源分离、减少不必要的日志打印等等。还有一个很强大的优化方式,那就是 加缓存!
当然,在高并发、高可用、高性能的要求下(虽然大多数项目都是吹牛皮的),我们通过将热点数据放入缓存中,让数据库只需要承担存储的工作,以此来提高系统的访问速度,减轻数据压力。
1.2.哪些数据适合放入缓存中呢?
通常来说,我们把 热点数据,放入缓存。
归纳为一下几种:
- 访问量大但更新频率不高的。例如网站首页的友情链接,访问量,不会经常变化。
- 及时性的。例如查询最新的订单物流信息,外卖状态,地理位置信息等等。
- 数据一致性要求不高的。例如门店信息,CSDN的个人资料,都是修改后,数据库中已经改了,x 分钟后缓存中才是最新的,但这不影响功能使用。
其他的,大多数也接触不到,就不一一列举了!
1.3.使用缓存的流程
目前,大多数项目中,比如当我们查询某数据时,使用缓存的流程如下:
注意这个缓存组件,你可能会听到:Redis、Memcache、Ehcache、甚至还有用Map、Hibernate 等做缓存的。
我们就先不说这些,因为要使用缓存,最简单的是使用本地缓存。
二、本地缓存
我说最简单的缓存使用方式是用本地缓存。
what?估计很多一开始就使用Redis的小伙伴,都不没听过这个东西。
2.1.什么是本地缓存?
本地缓存,说白了就是在内存中缓存数据,可以用Map、数组等数据结构来缓存数据。(严格来说本地缓存不能用HashMap,因为不是线程安全的,会出问题)。
比如现在有一个需求,前端需要查询计费规则,而计费规则放在网站的首页,假设访问量是非常高的,但又不是经常变化的数据,所以我们将 “计费规则数据” 放到缓存中。
2.2. 不使用缓存时
我们先来看下不使用缓存的情况:
- 前端的请求先经过网关,然后请求到对应的微服务,然后查询数据库,返回查询结果。
如图:
对应的核心代码,先自定义一个 API 用来查询计费规则的列表数据,从数据库查询出来后直接返回给前端。
@GetMapping("/list")
public ResponseResult typeList(){
// 从数据库中查询数据
List<RecordChargeRule> list = ruleService.list();
return ResponseResult.ok(list);
}
2.3.使用缓存时
再看下使用缓存的情况:
- 前端先经过网关,然后到资源微服务,先判断缓存中有没有数据,如果没有,则查询数据库再更新缓存,最后返回查询到的结果。
如图:
那我们现在创建一个 HashMap 来缓存资源的类型列表:
private Map<String, Object> cache = new HashMap<>();
先获取缓存中的类型列表:
/从本地缓存中取数据
List<RecordChargeRule> ruleCache = (List<RecordChargeRule>) cache.get("ruleList");
如果缓存中没有,则先从数据库中获取。当然,假设第一次查询缓存时,肯定是没有这个数据的。
最终的方法如下:
private Map<String, Object> cache = new HashMap