oa考勤管理系统解决方案,考勤系统操作流程
1091
2022-05-29
大家好,我是李哥。
上次我们讨论了在分布式系统下的缓存架构体系,从浏览器缓存到客户端缓存,再到CDN缓存,再到反向代理缓存,再到本地缓存,再到分布式缓存。整个链路中有非常多的缓存。
如果面试官问你说:给你一个机会,你有什么办法能够绕过这么多层缓存,将我们的慢设备击垮呢?(这里的慢设备一般指基于磁盘进行存储的关系型数据库,如MySQL)
难道这就是传说中的:「即使敌众我寡,末将也能从百万丛军中取敌将首级!」
这便是我们今天的主题:缓存穿透
什么是缓存穿透?
我们知道,缓存的工作原理是先从缓存中获取数据,如果有数据则直接返回给用户,如果没有数据则从慢速设备上读取实际数据并且将数据放入缓存。同步缓存就像这样:
或者使用异步的方式去同步缓存就像这样:
但是,如果缓存中和慢设备中一直都没有数据的话,是什么流程呢?
没错,如果缓存和数据库都没有的数据,请求仍然会先经过缓存再经过数据库,下次请求依然是同样的路径,这便是缓存穿透。
小结:缓存穿透,是指请求每次都要经过缓存,去访问慢设备,而慢设备又没有数据,在并发访问的情况有可能将慢设备击垮。
缓存穿透可能带来哪些问题?
我们知道了缓存穿透的场景后,其次我们要了解它的痛点是什么?
在高并发的情况下有可能将慢设备击垮;
每次请求都要经过无效的缓存层,请求相对较慢;
缓存穿透的解决思路有哪些?
问题1的解决思路:
高并发会将慢设备击垮,那么我们在这里的解决思路可以是让高并发变成低并发,让慢设备变得足够强大可以抗住足够的压力不被击垮。
高并发转换为低并发
如何让高并发变成低并发呢?
此刻你的思路没错,加锁。这种情况下可以是本地锁和分布式锁。本地锁指的是一个服务只允许N个线程同时访问慢设备(N代表N个实例),分布式锁指的是在永远只允许一个线程同时访问慢设备。当然了,也可以使用一些限流算法来玩。比如计数器法、令牌桶算法、漏桶算法等,我们今天的主题并不是它,暂且跳过,后续会有专门的文章来讲解。
回到正题。
服务实例数量不多的话可以使用本地锁,毕竟本地锁比分布式锁快。
服务实例数量较多的话则需要使用分布式锁来解决,进行流量防护。
但是如果数据一直不存在的话,仍然是有这种无效的请求,所以,在这一个线程访问慢设备的时候,如果数据为空,我们就约定一个数据放入缓存,如果数据为约定数据,则下次请求直接返回没有数据即可。示例图如下:
(这张图建议好好理解)
提高慢设备高可用
慢设备我们一般指的是DB,我们在这个场景中如何提升DB的高可用而不被击垮呢?
我们有以下两种思路:
我们在DB侧使配置最大线程数,用固定线程数对其进行限流处理;
或者是我们将DB做成主从数据库,读数据均匀的散布在从库上,并且从库让我们可以无限水平扩容。
问题2的解决思路:
问题2:每次请求都要经过无效的缓存层,请求相对较慢。
没错,细心的你一定发现了,我们在讨论《高并发转换为低并发》其实就已经解决了这个问题。
另外一种思考方式:
为什么会存在这个情况?(缓存无数据,慢设备无数据,但是又存在这样的请求)
我的猜想有:
攻击者!
数据被修改或删除,数据变更后,原来的查询路径无法获取数据;
慢设备故障导致数据丢失+缓存失效
那么如果是攻击者的话,我们的应对办法可以是请求达到阈值后封禁IP和对查询内容进行过滤,比如id≤0一定不存在则可以过滤。
如果是数据更新导致原路径无法查询,再加上高并发导致慢设备宕机,所以这种情况的应对办法应该是尽可能的减少热点数据更新频率+热点数据异步刷新保证热点数据在缓存中不过期。
如果是慢设备故障的话,那就没办法了,超出程序员应该有的思考范围了,这种情况下应该是做同城双活、异地多活等架构来保证高可用性。像阿里的两地三中心,三地五中心等架构,别着急,后面会详细介绍的,点个关注吧。
可以关注我的公中号:李哥技术
大家好,我是李哥。
上次我们讨论了在分布式系统下的缓存架构体系,从浏览器缓存到客户端缓存,再到CDN缓存,再到反向代理缓存,再到本地缓存,再到分布式缓存。整个链路中有非常多的缓存。
如果面试官问你说:给你一个机会,你有什么办法能够绕过这么多层缓存,将我们的慢设备击垮呢?(这里的慢设备一般指基于磁盘进行存储的关系型数据库,如MySQL)
难道这就是传说中的:「即使敌众我寡,末将也能从百万丛军中取敌将首级!」
这便是我们今天的主题:缓存穿透
什么是缓存穿透?
我们知道,缓存的工作原理是先从缓存中获取数据,如果有数据则直接返回给用户,如果没有数据则从慢速设备上读取实际数据并且将数据放入缓存。同步缓存就像这样:
或者使用异步的方式去同步缓存就像这样:
但是,如果缓存中和慢设备中一直都没有数据的话,是什么流程呢?
没错,如果缓存和数据库都没有的数据,请求仍然会先经过缓存再经过数据库,下次请求依然是同样的路径,这便是缓存穿透。
小结:缓存穿透,是指请求每次都要经过缓存,去访问慢设备,而慢设备又没有数据,在并发访问的情况有可能将慢设备击垮。
缓存穿透可能带来哪些问题?
我们知道了缓存穿透的场景后,其次我们要了解它的痛点是什么?
在高并发的情况下有可能将慢设备击垮;
每次请求都要经过无效的缓存层,请求相对较慢;
缓存穿透的解决思路有哪些?
问题1的解决思路:
高并发会将慢设备击垮,那么我们在这里的解决思路可以是让高并发变成低并发,让慢设备变得足够强大可以抗住足够的压力不被击垮。
如何让高并发变成低并发呢?
此刻你的思路没错,加锁。这种情况下可以是本地锁和分布式锁。本地锁指的是一个服务只允许N个线程同时访问慢设备(N代表N个实例),分布式锁指的是在永远只允许一个线程同时访问慢设备。当然了,也可以使用一些限流算法来玩。比如计数器法、令牌桶算法、漏桶算法等,我们今天的主题并不是它,暂且跳过,后续会有专门的文章来讲解。
回到正题。
服务实例数量不多的话可以使用本地锁,毕竟本地锁比分布式锁快。
服务实例数量较多的话则需要使用分布式锁来解决,进行流量防护。
但是如果数据一直不存在的话,仍然是有这种无效的请求,所以,在这一个线程访问慢设备的时候,如果数据为空,我们就约定一个数据放入缓存,如果数据为约定数据,则下次请求直接返回没有数据即可。示例图如下:
(这张图建议好好理解)
慢设备我们一般指的是DB,我们在这个场景中如何提升DB的高可用而不被击垮呢?
我们有以下两种思路:
我们在DB侧使配置最大线程数,用固定线程数对其进行限流处理;
或者是我们将DB做成主从数据库,读数据均匀的散布在从库上,并且从库让我们可以无限水平扩容。
问题2的解决思路:
问题2:每次请求都要经过无效的缓存层,请求相对较慢。
没错,细心的你一定发现了,我们在讨论《高并发转换为低并发》其实就已经解决了这个问题。
另外一种思考方式:
为什么会存在这个情况?(缓存无数据,慢设备无数据,但是又存在这样的请求)
我的猜想有:
攻击者!
数据被修改或删除,数据变更后,原来的查询路径无法获取数据;
慢设备故障导致数据丢失+缓存失效
那么如果是攻击者的话,我们的应对办法可以是请求达到阈值后封禁IP和对查询内容进行过滤,比如id≤0一定不存在则可以过滤。
如果是数据更新导致原路径无法查询,再加上高并发导致慢设备宕机,所以这种情况的应对办法应该是尽可能的减少热点数据更新频率+热点数据异步刷新保证热点数据在缓存中不过期。
如果是慢设备故障的话,那就没办法了,超出程序员应该有的思考范围了,这种情况下应该是做同城双活、异地多活等架构来保证高可用性。像阿里的两地三中心,三地五中心等架构,别着急,后面会详细介绍的,点个关注吧。
可以关注我的公中号:李哥技术
总结
缓存穿透是指:缓存和慢设备都没有数据,加上高并发的请求,慢设备扛不住导致宕机。
缓存穿透的解决方案:
如果是攻击者,封禁IP
提前做数据过滤,减少慢设备访问次数
当缓存无数据时,访问慢设备之前获取一把锁,减少慢设备并发访问
做好高可用架构设计
好了,本期就讨论到这里,感谢阅读。
既然都看到这里了,你的+在看就是对我最大的支持。
Java 分布式 分布式缓存服务 Redis 架构设计 缓存
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。