怎么解决“击穿”问题?
怎么解决“击穿”问题?
提示
**题眼:**高并发问题。单飞
**缓存击穿:**是指某个极度“热点”数据在某个时间点过期时,恰好在这个时间点对这个 KEY 有大量的并发请求过来,这些请求发现缓存过期一般都会从 DB 加载数据并回设到缓存,但是这个时候大并发的请求可能会瞬间 DB 压垮。对于一些设置了过期时间的 KEY ,如果这些 KEY 可能会在某些时间点被超高并发地访问,是一种非常“热点”的数据。这个时候,需要考虑这个问题。
区别: 和缓存“雪崩“”的区别在于,前者针对某一 KEY 缓存,后者则是很多KEY 。和缓存“穿透“”的区别在于,这个 KEY 是真实存在对应的值的。
解决方案:
- 使用互斥锁。请求发现缓存不存在后,去查询 DB 前,使用分布式锁,保证有且只有一个线程去查询 DB ,并更新到缓存。
- 手动过期。缓存上不设置过期时间。
重要
参考答案:
缓存击穿,其实就是某个数据过期了,然后恰巧这个时间点,有较大的流量要读取这个数据,结果就全部压在了数据库上,导致数据库崩溃,进而拖累整个服务。它的问题点其实就两个,一个是缓存过期,一个是流量压到了数据库上。对应得解决办法也比较明确吧,首先就是不能用“读时更新,写时删除”这个策略了,可以改为缓存永不过期,然后用定时器异步更新,也可以监听binlog日志,更新缓存。这样得好处是,流量不会过期,也就不会出现缓存为空的情况,但是不太适合时效性较高的场景,它多少还是会有一些延迟的。而且,它实现起来挺复杂的,依赖的组件比较多,有时候容易出现Bug,导致数据一直不更新。
然后如果说,数据时效性要求比较高,或者有流量突发的话,这个时候可以通过加锁的方式,让流量不要一次性压到DB身上,这样可以保护数据库。Go有一个单飞包,它可以实现一批流量过来只放行一个,然后其他等这一个的访问结果。它的话也可以对DB起到保护作用。
相关信息
引申:什么是单飞?
