上篇文章介绍了redisCluster。
redis集群-Redis(六)https://blog.csdn.net/ke1ying/article/details/131217674
缓存穿透
正常情况下,用户访问某条数据,第一次从数据库获取,后面会set进缓存,从缓存获取。缓存穿透指的是数据库没有这个值,当大量请求时,会经过缓存在数据库不断查询,数据库负担不断增加。这种情况下可能是业务代码异常,也可能是黑客利用不存在的key不断攻击数据库(所以redis不光可以提高性能,还可以利用减轻数据库压力防止黑客攻击)。那这种情况如何解决呢?
可以增加业务代码逻辑,当这个值不存在,则set空值到缓存,给这个空值一个过期时间。
还有一种方式使用bigMap布隆过滤器,在业务代码上先对数据进行一次过滤器过滤,对于不存在的数据,布隆过滤器可以先过滤掉。
缓存击穿
当系统中redis的key大量一起过期,导致同一时间高并发一起请求这些key,全部打到数据库服务器上,这时候导致数据库宕机怎么解决呢?
设置redis过期随机过期时间,并且提供一个过期时间基数。
缓存雪崩
整个redis服务器直接宕机导致不可用,这时候 必须通过我们前面说的集群保证redis高可用,以及预估高峰流量,做限流预案,用队列削峰,服务降级。比如用hystrix服务降级组件,kafka队列等。
当key是一个热点,比如双11某部手机大降价,高并发同时都访问这个key,于是全部一起访问到数据库,这时候怎么解决呢,用redission分布式锁来保证只有一个请求访问到数据库,其他的从缓存冲获取。(顺便一提redission分布式锁源码里通过lua脚本访问redis,保证事务和原子性)
线程1:set数据库10,删除缓存
线程2:set数据库6,删除缓存
线程3:get数据库10,set缓存10
当线程3和线程2并行执行:
第一步:线程3获取10,线程2set数据库6,删除缓存
第二步:线程3set缓存10
这时候实际数据库存入的是6,但是缓存存入的是10。
导致了数据库和缓存不一致。这时候如何解决呢?
(延迟双删也是一种解决策略,在删除缓存的时候,sleep 50ms再删一次。但这种情况不推荐,这种小概率事件而让所有请求都停顿)
针对读多写少的情况,加入缓存提高性能,针对写多读少并且不能容忍不一致性的情况,就没必要使用缓存,可以直接操作数据库,没必要为了提高性能,而增加很多复杂的设计。
1)以业务名(或者数据库名)为前缀,防止key冲突,冒号分割。
(微服务的情况下,加上服务名称)
Bigkey针对value的,绝对不能放大key,前面强调过很多次。在redis一个字符串最大512mb,哈希,set,zest,list可以存储大约40亿元素。实际情况下我们一般认为:
1)redis阻塞。
2)网络阻塞:Bigkey意味着产生网络流量较大,假设一个bigkey是1mb,客户端每秒访问1000,那么每秒产生1000mb流量,对于普通千兆网络服务器(按字节每秒128mb/s)直接宕机。
(千兆网卡为什么是128mb/s,因为需要除以8,按字节计算)
3)过期删除:在redis4.0版本设置lazyfree-lazy-expir yes,改为异步删除,如果没有配置,则bigkey过期会造成阻塞。
正常都是程序设计不当,
如何优化呢?
可以拆分,通过哈希取模拆分更小模块,进行二次存储。
如果实在不可以避免,必须要bigkey,那么只可以在操作的时候不要hgetall,用hmget,删除的时候也要渐进式删除。
Set user:1:name ky
Set user:1:age 20
可以改为哈希
Hmset user:1 name ky age 20