平常当项目处于并发架构时,往往数据的读取是不可能直接接触数据库的。面对这样的场景 一种办法可以把数据“外包”给cdn,压力全部由cdn来承受,还有一种办法就是使用Redis缓存来将数据放在里面,避免用户直接访问DB数据,当缓存失效后才能访问数据库。但在缓存的使用中,往往可能出现雪崩、穿透和击穿事件,这些问题生成的场景,危害,和解决办法都是什么呢,我来简单的讲解一下。

雪崩

雪崩,顾名思义,厚重的雪把支撑点压垮,进而形成不可估量的灾难,缓存中的雪崩是什么情况呢。比如我们实际开发中,key大多都是通过定时任务自动生成的,往往过期时间都会被设置在同一个时间点,数据多的时候就会有同一批key同时过期的情况,这是一种场景;另一种场景是当你的redis服务器突然挂掉或者重启以后。这两种场景都会使缓存层同一时刻访问key失效,降级改为通过DB访问,大量的请求会击垮后端服务。

解决办法:

1.不是N多个key在同一时间內过期失效吗,我们可以把过期时间为每一个key设置一个随机数,这样就会避免批量缓存失效的问题

2.当缓存失效时,为Redis加互斥锁处理,setnx,排队进入DB

3.备份N台缓存服务器,当主服务器出现问题时将并发请求转移到次服务器中

穿透

穿透,顾名思义,举个例子就像是在一场战争时,敌方军队设置了多道防线,但我发射巡航导弹却能够绕过这些防线,实现精准打击。缓存中的穿透是由于高并发的请求去访问一个不存在的key,甚至是一个不存在的DB数据,平常生活中很难出现此问题,但偶尔项目的bug上线,带上了一个不存在的id,更有甚者哪一家黑客盯上了你的服务器,带着某个不存在的参数一顿降维打击,嗯~让你的DB查去吧,直到把你的资源占用殆尽。

解决办法:

1.当接收参数时,首先在客户端进行校验,对一些一看就知道有问题的请求做过滤处理,不让其访问服务器

2.在后端方面,当首次查出DB中没有的数据时,对其参数进行Redis缓存,但过期时间应该设的短一点,下次再访问的时候就会走缓存逻辑

3.如果有黑客恶意的访问一个奇怪的请求,那我们可以在nginx层面直接把超过访问阀值的IP用户屏蔽掉

击穿

击穿,还是顾名思义......容我再举个例子:就像个不锈钢水桶,你拿一个铁锥不停的对着一个点凿,只要锲而不舍,那等到一段时间后,这个点总会有崩溃掉的时候,这时候就可以趁虚而入了。缓存中的击穿是当一个热点key存在着大量并发请求的时候,大家都在不停的访问这个key,那终有一天这个热点key会过期失效,当过期后大量的并发就会走DB的逻辑去请求数据。对服务器造成巨大的压力。

其实我个人认为,击穿和雪崩还是有一些相似之处的,前者是对某个key持续打击,后者是对批量key持续打击,雪崩就好比拿N多个铁锥在多个点反复钻凿,多个点也会有崩溃的时候,当所有点同时崩溃掉的时候就像极了升级版的击穿,那应该是万箭击穿了......

解决办法:

1.对热点数据缓存设置永不过期

2.对Redis设置互斥锁,setnx一个参数,当访问完毕时对其销毁,不存在时加锁,并走查找数据逻辑,当有锁时请求sleep后并重复请求直到解锁为止