分布式锁
分布式锁本质就是在Redis中设置一把锁,当别的进程也要上锁时,入股发现已经被上锁了,就需要放弃或者重试。
上锁一般使用set(set if not exits)
指令,只允许一个客户端上锁,用完之后使用del
指令释放。
但是如果成功上锁后,程序出现问题,无法执行del
,那么锁将永远不能释放。对此,可以将锁设置一个过期时间,set [key] [value] ex [timeout] nx
,这个指令是将setnx
和expire
组合在一起的原子指令,这就是分布式锁的核心。
Redlock算法
加锁时,会向过半的节点发送
set(key, value, nx = True, ex = xxx)
指令,只要过半节点set
成功,就认为加锁成功释放锁时,需要向所有节点发送
del
指令。因为Redlock需要向多个节点进行读写,会比单实例的Redis性能下降一些。
缓存穿透
缓存穿透是指查询一个一定不存在的数据,因为缓存中也无该数据的信息,则会直接去数据库层进行查询,从系统层面来看像是穿透了缓存层直接达到DB,从而称为缓存穿透。
解决:
- bloom filter:类似于哈希表的一种算法,用所有可能的查询条件生成一个bitmap,在进行数据库查询之前会使用这个bitmap进行过滤,如果不在其中则直接过滤,从而减轻数据库层面的压力。
- 空值缓存:一种比较简单的解决办法,在第一次查询完不存在的数据后,将该key与对应的空值也放入缓存中,只不过设定为较短的失效时间,例如几分钟,这样则可以应对短时间的大量的该key攻击,设置为较短的失效时间是因为该值可能业务无关,存在意义不大,且该次的查询也未必是攻击者发起,无过久存储的必要,故可以早点失效。
缓存雪崩
缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到DB,DB瞬时压力过重雪崩。
解决:
- 交错失效时间:这种方法时间比较简单粗暴,既然在同一时间失效会造成请求过多雪崩,那我们错开不同的失效时间即可从一定长度上避免这种问题,在缓存进行失效时间设置的时候,从某个适当的值域中随机一个时间作为失效时间即可。
- Hystrix + 本地缓存:这是当发生雪崩时的应对方法
缓存击穿
缓存击穿实际上是缓存雪崩的一个特例,在热点的缓存到达失效时间时,此依然有大量的请求到达系统,没有了缓存层的保护,这些请求同样的会到达DB从而可能引起故障。击穿与雪崩的区别即在于击穿是对于特定的热点数据来说,而雪崩是全部数据。
解决:
- 使用互斥锁
- 永远不过期
- 热点散列