Redis为什么需要作为缓存使用?
在高并发的业务场景下,数据库往往是用户并发访问最薄弱的环节,所以,这个时候就需要做一个缓存操作,如果是单机服务,当然也可以使用ConcurrentHashMap
作为简单缓存使用,但遇到分布式服务时,就需要使用一个公共的缓存进行缓存操作,此时就可以使用Redis作为缓存,这样就可以大大的环节数据库的压力。那么如果使用Redis作为缓存就需要考虑一些失效问题。
高并发使用Redis作为缓存出现的失效问题
- 缓存雪崩、缓存穿透、缓存击穿、缓存污染
- 缓存雪崩:大量缓存数据同一时刻过期或Redis故障宕机
- 缓存穿透:数据压根不存在于Redis和数据库
- 缓存击穿:热点缓存数据过期
- 缓存污染:大量缓存数据只被访问一次或几次却占用缓存空间
- 缓存与数据库的一致性问题(如何保持一致性?)
- 双写模式下存在的问题
- 失效模式下存在的问题
1. 缓存雪崩
缓存雪崩概述
当大量缓存数据在同一时刻过期(即缓存数据失效)或者Redis故障宕机时,此时如果有大量的请求访问Redis缓存数据则会导致大量请求会直接访问数据库(即直接压入数据库),导致数据库压力剧增,严重的情况会导致数据库直接宕机,致使整个系统崩溃,这就是缓存雪崩。
出现缓存雪崩主要是因为:① Redis中大量缓存数据同一时间过期; ② Redis故障宕机
解决方案
- 过期时间设置随机值 (最常用)
给缓存数据设置随机值过期时间,使得数据的过期时间可以均匀开来,避免大量数据在同一时间全部过期(实用)
- 加互斥锁(不适用高并发情况) (注意分布式系统下,要加分布式锁,后面说明)
当请求访问Redis时,发现Redis缓存数据不存在,则加互斥锁,保证相同请求过来时因为加了互斥锁只能等当前请求访问完数据库并将数据缓存到Redis后释放互斥锁才允许其他相同的请求访问,这样就不会导致大量相同请求直接访问数据库,当然其他请求可以根据业务需求是继续等待还是返回空值。
- 双key策略
可以给缓存数据同时准备两个key,主key
设置过期时间,副key
不设置过期时间,两个key保存的值value是相同的,相当于副key
是缓存数据的副本,当主key
过期时可以直接返回副key
的value(即缓存数据),而在主key
更新时同时要更新主key
和副key
的缓存数据value
-
针对Redis故障宕机的处理方式
- 使用服务熔断机制(阿里的sentinel),暂停业务应用对Redis的访问,直接返回错误,不再继续将请求压入数据库,保证数据库系统能正常运行,这样整个系统就不会崩溃,等Redis恢复后再允许业务应用访问Redis。
- 可以构建高可用集群Redis服务器,实现Redis高可用,当Redis主节点宕机后,可以切换节点继续提供缓存服务,从根源上解决宕机问题。
2. 缓存穿透
缓存穿透概述
用户访问的数据压根不存在Redis缓存中,也不存在数据库中,导致用户发送请求访问缓存时,缓存失效,便直接访问数据库也没有拿到数据,这样的话当有大量这样的请求打入时,数据库的压力会剧增,同样可能会导致数据库崩溃从而导致系统崩溃,这就是缓存穿透。
一般导致缓存穿透的情况有两种:① 业务误操作(数据意外丢失) ② 黑客恶意攻击(故意访问一些不存在的数据)
解决方案
- 设置缓存空值或者默认值(常用)
当业务应用查询不到缓存和数据库的数据时,可以最后在缓存中设置一个对应的空值或者默认值,这样后续的请求就可以从缓存中读取到空值或者默认值,返回给业务应用,这样就可以避免大量请求压入数据库导致缓存穿透。
- 非法请求的限制
在请求打入缓存前即在接口拿到数据前就对请求参数进行判断,查看是否合理,是否是非法值,请求字段是否存在,对非法数据直接拦截,这样就可以避免后续的缓存穿透问题了。
- 设置可访问的名单(白名单)
使用Redis中的bitmaps
类型定义一个可以访问的名单,名单id作为bitmaps的偏移量(数组的下标),每次访问和bitmap里面的id进行比较,如果访问id不在bitmaps里面,进行拦截,不允许访问。
- 使用布隆过滤器
在数据库写入数据之后,使用布隆过滤器对数据进行标记(上述3的方式类似)