redis作为缓存
互联网高并发请求数据的情况,可能出现频繁访问MySQL的情况,但是MySQL由于自身的特性,可能无法抗住这么大的压力,因此我们想利用redis存储一些MySQL中的数据,redis作为缓存时,一般有以下几个场景:
数据的一致性不是强制的
比如查询UV的次数,允许和数据库有一些不一致,更新redis是异步的。而像支付等,是强一致性的,则不能使用缓存(只是举个例子),redis更新是异步执行的。数据经常被访问
如果数据访问频率不高,则数据库就能解决了,使用redis就是浪费了。
这样,利用redis作为缓存,利用redis的高QPS特点,使得客户端先访问redis,命中的数据直接返回给客户端,未找到的再去数据库中查询,返回给用户最终的结果。
缓存雪崩
问题现象:短时间内存在大量的key过期,而新的key还没有写入内存,访问这些key的请求会直接访问SQL,造成服务崩溃。
问题的本质原因:同时过期的key数量太多,请求越过了redis,直接访问了SQL
解决方案:
服务器访问SQL的地方,限流操作设置过期时间时,添加随机策略,不要统一过期建立缓存备份,在一个出现大量过期且新key没有写入时,访问备份缓存,确保至少一个可用。
缓存穿透
问题现象:客户端高并发获取redis的数据如果获取不到,则会高并发查询数据库,如果数据库中的数据也不存在,而且访问持续进行,则会打垮数据库。一般是恶意攻击的情况
问题的本质原因:数据不存在的请求没有被redis过滤掉,而且不存在的值也不会再加入redis中,等效成直接访问SQL
解决方案:限制不存在值访问SQL的频率即可,不同的业务场景有不同的方案,给几个常用的方式:
客户端对不存在的访问进行限流处理,比如时间戳限流、漏斗限流和令牌桶等。这种模式的优势在于,对接客户端的时候,就能直接限制次数,而且可以通知不存在的数据布隆过滤器,把常见的数据加入到布隆过滤器中,如果布隆显示存在则查找redis,并返回数据;因为布隆过滤器可能会误判,误判的情况去找MySQL,这种概率比较小。服务器端,需要对访问SQL的请求限流
缓存击穿
问题现象:某个key
是一个热点的key,即有大量并发的请求会访问这个key
。如果此时key
过期了,那么这些服务会直接请求到SQL上,导致SQL压力过大而崩掉。注意,这不是雪崩,雪崩是大量的key过期,而这个是特别热点的一个或者几个key过期问题的本质原因:这种属于正常的业务访问,整个访问流程也是没有问题的,只是瞬间过期的key
把承受的压力转移到了SQL端解决方案SQL端首先要有自己的保护机制,保证最坏的情况下,不会被打垮对于热点key,可以设置永不过期的策略,只有主动更新的时候去更改缓存预热
概念:服务启动时,把相关的数据一次性加入redis中
解决问题:避免了用户初始化频繁访问不存在的数据,导致直接请求SQL和频繁加载。
一些限制:
需要手动操作数据量不能太大,否则无法全量加载
缓存更新
缓存中的数据不是一成不变的,需要定期更新,比如置换掉不经常查询的数据,选择出常用的数据重新加入redis中。可以使用LRU等方式来解决这种场景的问题。
注意,更新的时候,如果用到了防止击穿的布隆过滤器,需要一并更新布隆过滤器的数据
缓存降级
redis缓存如果挂掉,则需要执行降级策略:
重试机制:不断重试访问,同时日志报错,提示服务监控应该报警限流访问机制:此时仍然要给客服服务,应该限流访问MySQL,牺牲部分的性能来换取可用性