缓存在系统中的位置
因为大型系统,其数据库资源比较紧俏,并且数据库的访问速度并发量远不如目前的各种内存缓存系统。所以缓存的主要意义是减少数据库压力,增加访问速度。其位置是建立在数据库层和业务逻辑层之间。
缓存容易出现的问题
人为攻击类型
缓存穿透
描述:
缓存穿透是指访问数据库中都没有的数据(数据库中没有,缓存中自然也没有),如发起为id为“-1”的数据或id为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。
解决方案:
- 接口层增加校验,排除明显的非法数据,例如id<=0的直接拦截。
- 对重要的接口进行用户校验,必须登录鉴权后使用,增加攻击难度。
- 从缓存取不到的数据,在数据库中也没有取到,这时如果访问量很大,基本可以证实为攻击性行为,对于此种行为,网上一般都会说可以设置虚假缓存进行欺骗,例如可以将对应查询缓存value设置成null或特殊值,这样缓存命中,不会给数据带来很大压力。但是实际上真的攻击者,不会使用一个固定值来攻击网站,都会选择一个超限的不同的值进行攻击,如果攻击者量很大,容易造成缓存系统崩溃,这种最主要的还是要配合其他手段进行防护,比如流量限制,ip封禁,另外逻辑层参考第一步,对非正常数据进行限制。
缓存设计不合理
缓存击穿
描述:
缓存击穿是指短时间涌入大量对缓存中没有但数据库中有的数据的数据,缓存中没有是因为
- 数据新增
- 或者缓存过期
上面两个的场景:场景比如秒杀商品上线,没有做缓存预热,或者秒杀商品在秒杀期间缓存过期,本来缓存可以轻易应付几千人并发,数据库只能应付几百。这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成大量用户无响应。
- 或者缓存系统崩溃重启
如果压力过大导致缓存系统如果崩溃,这时候系统热点尚未过去的话,很容易造成重启后依然崩溃的现象。
注意:很多人讲缓存击穿,不讲新增和系统崩溃这种情况,其实这两种情况很常见也更容易被忽略,后者还可能导致系统长时间不可用等严重问题。
解决方案:
- 对于缓存过期:设置热点数据永远不过期(或者超长时间),进行手动更新或删除缓存。
- 针对于新增数据:热点数据进行缓存预热,也就是在热点爆发之前,先通过内部脚本或者其他方式,把数据加载到内存中。
- 针对于缓存系统崩溃:通过流量限制或者业务层加锁的方式来限制缓存预热的时候,对缓存和数据库访问的量,尽量把流量拦截在用户端(比如app和浏览器)和站点以及逻辑层这些上游区域,而不是数据层直接面对压力。
缓存雪崩
描述:
缓存雪崩是指缓存中数据大数据批量到过期时间,流量如同雪崩一样直接打到了数据库,引起数据库压力过大甚至down机。和缓存击穿不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期。另外缓存击穿那写到的系统崩溃在这里也可能发生。
解决方案:
- 缓存数据的过期时间设置随机(最好是素数),防止同一时间大量数据过期现象发生。
- 设置热点数据永远不过期,进行手动更新或删除缓存。
- 同缓存击穿一样,进行上游限流。
本文是个人知识和经验的总结,很多场景都是自己或者看别人经历过才知道,比如秒杀场景的缓存系统怎么都重启不起来,就是因为缓存击穿,前端和逻辑层这些上游没有做好限流。