高并发的情况会给系统带来很高的访问流量,这就给存储这些热点信息的Redis数据造成了一些压力。
用户消费的数据远大于生产的数据 (热卖商品、热点新闻、热点评论、明星直播)等。
在日常工作生活中一些突发的的事件,例如某明星突然宣布恋情,导致某新闻点击量瞬间变大,请求远超过对数据的写入。就会造成热数据问题。
我们 一般采用缓存 + 过期时间的策略来帮助我们加速接口的访问速度,减少了后端负载,同时保证功能的更新,一般情况下这种模式已经基本满足要求了。
但是有两个问题如果同时出现,可能就会对系统造成致命的危害:
以上两个问题如果同时出现,就可能会造成缓存失效问题,有大量线程来构建缓存,造成后端负载过大,严重还会导致系统崩溃。
上图简单描述了访问热点key及构建缓存的一个过程。
解决热点key问题,可以有以下几种方案,
1、互斥锁
在上图查询数据库的过程,只让一个线程独占,这个线程构建缓存的过程,其他线程都要等待,直到第一个线程构建完成可以从中读取数据。
2、提前使用互斥锁
提前使用互斥锁,和互斥锁差不多,都是让一个线程独占构建缓存,不一样的是,在构建缓存的时候。
在value内部设置一个超时值timeout1,这个过期时间比实际的缓存过期时间短。
当从缓存中读到timeout1已经过期的时候,就认为数据也快过期了,直接执行查询数据库,进行构建缓存的过程。
这样在所有快过期的数据前,就重新构建了缓存。
3、永远不过期
永远不过期有两点
a、从redis上看,确实没有设置过期时间,这就保证了,不会出现热点key过期问题,也就是“物理”不过期。
b、从功能上看,如果不过期,那不就成静态的了吗?所以我们把过期时间存在key对应的value里,如果发现要过期了,通过一个后台的异步线程进行缓存的构建,也就是“逻辑”过期
可能会出现的问题,就是会出现老数据,怎么说?
有1、2、3、4个线程,在第2个线程时,发现value中数据已经过期,通过异步更新重新构建缓存,前面有说过,线程构建缓存会需要一定时间,如果在第4个线程执行时才完成构建,那么第2、3个线程输出的就是老数据。不过对于一般的业务需求是可以接受的。
什么是缓存穿透?
在客户端和数据库中间增加一个缓存层,如果这个缓存层中保存的都是数据库命中数据,如果服务层并没有返回数据保存到缓存中,而客户端一直在访问这个数据,则每次都要直接访问数据库,在流量小时没有问题,如果流量非常大或有恶意攻击,就会利用这个漏洞,使服务端的压力增大,严重会导致系统崩溃。
解决方案
1、把查询结果为空的结果也放到缓存中,设置很短的缓存过期时间,不超过5分钟;
也会引入新的问题,比如内存会管理更多的键,尤其是被恶意攻击,后果更严重。
2、增加一个bloomfilter,任务某个key不存在,则不访问数据库;
什么是缓存雪崩?
雪崩是设置缓存失效的时间相同,造成大量的数据在短时间内同时失效,这样访问数据库的压力也会陡增。压力这么大,就像是发生了雪崩一样。
解决方案
1、采用加锁或消息队列,采用单线程的方式,防止失效时大量线程请求数据库。
2、在同样的缓存失效时间上,增加一个随机值,这样每个缓存的过期时间的重复率就会降低很多。
3、保证缓存的高可用。例如Redis Sentinel 和 Redis Cluster
4、提前演练,在项目上线前,就演练缓存宕机的情况,根据实际情况查看应用层及服务层的负载情况,在此基础上做准备。
5、依赖隔离组件为后端限流并降级。如Hystrix。
保存在内存中的缓存数据如果过期或失效,为了更合理利用内存空间,提高内存使用效率。
什么是淘汰机制
在内存中保存的Key被清除掉,
(1)定时去清理过期的缓存,使用Expire;
(2) LRU、LFU、FIFO算法剔除;
(3)主动更新:当有用户请求过来时,再判断这个请求所用到的缓存是否过期,过期的话就去底层系统得到新数据并更新缓存。
可以通过redis.conf设置# maxmemory
redis数据淘汰策略
volatile-lru 从已设置过期时间的数据集中挑选最近最少使用的数据淘汰
volatile-ttl 从已设置过期时间的数据集中挑选将要过期的数据淘汰
volatile-random 从已设置过期时间的数据集中任意选择数据淘汰
allkeys-lru 从所有数据集中挑选最近最少使用的数据淘汰
allkeys-random 从所有数据集中任意选择数据进行淘汰
noeviction 禁止驱逐数据
缓存是为了有效加速应用的读写速度,同时为后端降低负载,对日常访问量大的系统至关重要。如果缓存出现问题,不只不能降低压力,还会给后端服务造成更大的问题。所以在开发过程中,要避免预防这些问题出现。
Reference
https://timyang.net/tag/mutex/
https://help.aliyun.com/document_detail/67252.html
https://www.cnblogs.com/moonandstar08/p/5365507.html