(一).概念
缓存,就是把一些常用的数据放到访问速度更快的地方,方便随时读取。
注意:这个"访问速度更快"是一个相对的概念。对于硬件的访问速度,通常情况下,CPU寄存器>内存>硬盘>网络
缓存是更快,但是空间上往往是不足的,所以,大部分的时候,缓存只能存放一些热点数据。
(二).使用Redis作为缓存
Redis的用途主要有三个:①.作为内存数据库,存储数据。②.缓存。③.消息队列
通常情况下,我们会使用redis作为mysql的缓存 。因为mysql关系型数据库的性能并不高。如果访问数据库的并发量比较高,那么对于数据库的压力是很大的,很容易就会使数据库服务器宕机。为了避免这种情况,就需要让数据库能够承担更大的并发量。主要思路有两个:①.开源,即增加更多的机器②.节流,即引入缓存

当客户端访问业务服务器的时候,先发起查询请求。
业务服务器先查询redis,看数据是否在redis上存在。如果在redis中已经存在,则直接返回,不必访问mysql;如果在redis中不存在,再查询mysql。
(三).缓存的更新策略
前面说的"热点数据",那么如何在能知道哪些数据是"热点数据"?这就需要了解缓存的更新策略了。
1.定期生成
定期生成,会把访问的数据,以日志的形式记录下来。例如,搜索引擎,通过在搜索框里输入的词来访问具体的数据。
那么"定期生成"就会通过日志 ,把都使用到了哪些词记录下来,然后针对这些日志进行统计,统计一月/一周/一天,每个词出现的概率,然后根据概率进行排序,再取出"20%"的词,此时,就可以把这些词认为是"热点数据"了。然后,就可以把这些热点词以及涉及到的搜索结果提前放入到redis中。
优点:实现起来比较容易,过程可控,方便排查问题。
缺点:实时性不够。当面对一些突发性事件的时候,有些不是热点数据的内容, 突然变成了热点数据,那么新的热点数据可能就会给服务器造成压力。例如"春晚"。
2.实时生成
实时生成,指的是,先给缓存设置容量上限,可以通过配置文件中的maxmemory参数来进行设置。
如果查询的数据在redis中查到了,那么就会直接返回;如果redis中不存在,那么就会查数据库,把查到的结果同时放入到redis中。
当缓存满了,此时就会触发缓存淘汰策略。把一些"相对不热点"的数据淘汰掉,按照上述过程,持续一段时间之后,redis内部的数据自然就是"热点数据"了。缓存淘汰策略有以下几种:①.FIFO②.LRU③.LFU④.Random随机淘汰
①.FIFO
FIFO,先进先出。把缓存中存在时间最久的,即先来的数据,淘汰掉。
②.LRU
LRU,淘汰最久未使用的。记录每个key的最近访问时间,把最近访问时间最老的key淘汰掉。
③.LFU
LFU,淘汰访问次数最少的。记录每个key最近一段时间的访问次数,把访问次数最少的淘汰掉。
④.Random随机淘汰
Radom随机淘汰,从所有的key中随便选择一个进行淘汰。
上述的淘汰策略,我们可以自己实现。其次,Redis也提供了内置的淘汰策略,提供我们进行使用。
①.volatile-lru:当内存不能容纳新写入数据时,从设置了过期时间的key中使用LRU算法进行淘汰
②.allkeys-lru:当内存不能容纳新写入数据时,从所有key中使用LRU算法进行淘汰
③.volatile-lfu:当内存不能容纳新写入数据时,在过期的key中,使用LFU算法进行淘汰
④.allkeys-lfu:当内存不能容纳新写入数据时,从所有key中使用LFU算法进行淘汰
⑤.volatile-random:当内存不能容纳新写入数据时,从设置了过期时间的key中,随机淘汰数据
⑥.allkeys-random:当内存不能容纳新写入数据时,从所有的key中随机淘汰数据
⑦.volatile-ttl:在设置了过期时间的key中,根据过期时间进行淘汰,越早过期的优先被淘汰
⑧.noeviction:默认策略,当内存不能容纳新写入数据时,新写入操作则报错
(四).缓存预热
缓存预热,指的是,当redis刚刚启动的时候或者redis大批量key失效之后,此时由于redis是空的,那么所有的请求都会打给mysql数据库,此时就会给mysql数据库造成比较大的压力。"缓存预热"就是来解决该问题的,"缓存预热"会把定期生成和实时生成结合,先通过离线的方式,通过一些统计的途径,先把热点数据找到一批,导入到redis种,此时导入的热点数据,就能帮mysql承担很大的压力,随着时间的推移,逐渐就是用新的热点数据淘汰掉旧的数据
(五).缓存穿透
缓存穿透,指的是,查询某个key,在redis中没有,并且在mysql中也没有,那么这个key肯定不会被更新到redis中。如果这样的数据存在很多,并且反复查询,就会给mysql造成很大的压力,这种情况被称为"缓存穿透"。
"缓存穿透"产生的原因:
①.业务设计的不合理,例如,缺少必要的参数校验环节,导致非法的key也被进行查询了
②.开发/运维人员的误操作,不小心把部分数据从数据库上删除了
③.黑客的恶意攻击
"缓存穿透"的解决方案:
①.针对要查询的参数进行严格的合法性校验
②.如果发现这个key在redis和mysql上都不存在,我们可以写入到redis中,但是将value设置成一个非法值,例如""
③.引入布隆过滤器,每次查询redis/mysql之前,都先判断一下key是否在布隆过滤器中存在
(六).缓存雪崩
缓存雪崩,指的是,在短时间内,redis上大规模的key失效,导致缓存命中率突然下降,并且mysql的压力迅速上升,甚至直接宕机,这种情况称为"缓存雪崩"。
"缓存雪崩"产生的原因:
①.redis挂了
②.redis上的大量key同时过期
解决方法:
①.部署高可用的redis集群,并且完善监控报警体系
②.不给key设置过期时间,或者设置过期时间的时候添加随机时间因子,避免同时过期
(七).缓存击穿
缓存击穿,指的是,某个热点key,突然过期了,导致大量的请求直接打到了数据库上,甚至引起了数据库宕机,这个情况称为"缓存击穿"。
解决方式:
①.基于统计的方式发现热点key,并设置永不过期
②.进行必要的服务降级,例如,访问数据库的时候使用分布式锁,限制同时请求数据库的并发数