一、背景知识
Redis之父Antirez。
redis的诞生,跟关系数据库MySQL还挺有渊源的。
在redis之前,MySQL的压力很大,因为随着互联网发展的越来越快,它容纳的数据也越来越多,用户请求也随之暴涨,而每一个用户请求都变成了对它的一个又一个读写操作,MySQL是苦不堪言。尤其是到“双11”、“618“这种全民购物狂欢的日子,都是MySQL受苦受难的日子。
事实上,其实有一大半的用户请求都是读操作,而且经常都是重复查询一个东西,浪费它很多时间去进行磁盘I/O。
后来有人就思考,是不是可以学习CPU,给数据库也加一个缓存呢?于是redis就诞生了!
之后,redis就和MySQL经常携手出现在后端服务器中。
应用程序们从MySQL查询到的数据,在redis这里登记一下,后面再需要用到数据的时候,就先找redis要,没有时再找MySQL要。
为了方便使用,redis支持好几种数据结构的存储:
String
Hash
List
Set
SortedSet
Bitmap
······
因为redis把登记的数据都记录在内存中,不用去执行慢如蜗牛的I/O操作,所以找redis比找MySQL能省去不少时间。
可别小瞧这简单的一个改变,redis为MySQL减轻了不小的负担!随着程序的运行,redis缓存的数据越来越多,有相当部分时间redis都给MySQL挡住了用户请求,MySQL的压力就减少了。
有了redis的加入,网络服务的性能提升了不少。
二、缓存过期 && 缓存淘汰
但是随着时间的流逝,redis缓存的数据都是在内存中,可是就算是在服务器上,内存的空间资源还是很有限的,不能无节制的这么存下去,否则,早晚会出现问题。
于是,就有了一个方法:给缓存内容设置一个超时时间,具体设置多长交给应用程序们去设置,redis要做的就是把过期了的内容从内存里面删除掉,及时腾出空间就行了。
那么何时去清理呢?
最简单的就是定期删除。如果100ms清理一次,一秒钟就是10次!
由于清理的时候也不能一次把所有过期的都给删除掉,里面存了大量的数据,要全面扫一遍的话会花很长的时间,会严重影响redis处理新的客户请求!只能随机选择一部分来清理,能缓解内存压力就可以了。
但是这种方式也会有一些"漏网之鱼 ",躲过了随机算法的选中。
于是在原来定期删除的基础上,又加了一条:之前逃脱随机选择算法的键值,一旦遇到查询请求,当被发现已经超期了,就立即删除。
这种方式因为是被动式触发的,不查询就不会发生,所以也叫惰性删除!
但是,还会有一些键值因为运气没有被删掉,这就会导致可以使用的内存空间越来越少,就会产生一系列的问题。
所以针对此类情况,就有了 内存淘汰策略
redis提供了8种策略供应用程序选择,用于内存不足时该如何决策:
noeviction:返回错误,不会删除任何键值
allkeys-lru:使用LRU算法删除最近最少使用的键值
volatile-lru:使用LRU算法从设置了过期时间的键集合中删除最近最少使用的键值
allkeys-random:从所有key随机删除
volatile-random:从设置了过期时间的键的集合中随机删除
volatile-ttl:从设置了过期时间的键中删除剩余时间最短的键
volatile-lfu:从配置了过期时间的键中删除使用频率最少的键
allkeys-lfu:从所有键中删除使用频率最少的键
三、缓存穿透 && 布隆过滤器
MySQL有时候遇到些烦人的请求,查询的数据不存在,MySQL就要白忙活一场!不仅如此,因为不存在,redis没办法缓存,导致同样的请求来了每次都要去让MySQL白忙活一场。redis作为缓存的价值就没得到体现啦!这就是人们常说的缓存穿透。
此时就需要用到布隆过滤器 了。关于布隆过滤器详情,可以点击这里
四、缓存击穿 && 缓存雪崩
缓存击穿:由于热点数据到了过期时间,被redis删掉了,不巧的是随后就有对这个数据的大量查询请求来了,redis已经删了,所以请求都发到了MySQL上。
缓存雪崩:由于一大批数据几乎同时过了有效期,然后又发生了很多对这些数据的请求。
想要环节这两个问题的方法:
※ 对缓存击穿,可以设置热点数据永不过期。
※ 对缓存雪崩,可以将缓存过期时间设置的均匀些。