赞
踩
redis的缓存穿透,如何解决? 所谓的缓存穿透: 在客户端去查询数据的时候,数据库中没有数据,缓存中也没有,按照redis源码的执行流程 这就会出现情况-->当客户端发送请求查询数据的时候,并不会直接查询数据库,无论有没有数据都会先去查询redis,如果redis没有,则再查数据库,数据库也没有 相当于每一次访问请求的时候都会查询两次 当缓存的次数请求的过多的时候(这个时候redis不会造成宕机),redis就会认为你要搞他,所以redis就会不工作--->造成非常严重的现象,会跳过缓存直接去查询数据库,缓存就相当于没有用,本来缓存是为了提升效率(节省时间的),项目的效率就会大大降低(缓存命中率) 当直接跳过缓存的时候,数据库的访问量就会增加到非常大的地步,数据库可能就会存在宕机的风险(这就是当黑客开始攻击的时候-->不会直接攻击数据库-->先攻击redis缓存-->redis就会开启自我保护不再工作-->开始大量发送并发攻击数据库) 这也就是所谓的缓存穿透 和case穿透很像 int i = 3; switch(i){ case 1: "今天很开心"; case 2: "今天更开心"; case 3: } 用网络上获取的数据都会以抓包的形式拿取(tcp/udp协议) 短连接:从百度爬回来的数据--->只管发(按照规定时间(2s))--->不管项目是否接收到了 长连接:不但要管发送数据,还要操心数据是否发送到了,如果没有发送到就会一直等待,直到连接超时 数据包攻击:大量使用并发发送数据包到目标项目,导致目标项目因为性能问题无法接收到任何一个包的数据-->开始给你指定另外一条路(这些正确的数据就会被黑客模拟出来的路所接收到),黑客为了获取数据,还会一直不断的向真正服务器所发送假数据,让其一直处于崩溃状态
附图:redis的缓存同步流程。
解决方案有两种: 一:使用布隆过滤器 1.首先先规定好redis集群中需要存储什么样的数据(redis中所要存放的数据就是商品信息,那么就规定存入的数据就是商品信息,如果存入的是身份证号信息,就规定是身份证号信息,如果两个都存,那么两个都规定就行了) 规定好了之后,就会把这些可能出现的文字/字母/数字的哈希值给列举出来(理想状态是找到所有文字/字母/数字的所有可能性),把这些所有的可能性都存到bitmap,当有一个根本不可能的查询过来的时候,直接会被整个bitmap给拦截,这样就节省了查询压力 哈希值: MD5的加密方式使用的就是哈希加密 现在有一个密码zhangsan1234,这个密码肯定不能以明文暴露,必须要加密 (shiro就是这么做的) 把明文密码拆分成char数组--->char[] = {"z","h","a","n"....} 这个时候就会用到一个算法(散列算法(自己百度))-->散列算法的作用就是计算出char数组中每一个元素的散列坐标值 z-->124 h-->dh1 a-->ffi8 n-->zzj7 zhan ---> 124dh1ffi8zzj7 所产生的这些不规则的数据(字母,符号(-),数字)就是哈希值 在讲数据库索引的时候是否知道位图索引(bitmap) 位图:当照片被无限极放大之后就会发现这个照片是一块一块的,那么这一个小块就称之为一个位图 二:简单粗暴,也非常好用,也比较常用(称之为懒人专用) redis中永远不会给你报错空指针(就算你去redis中查询数据,这个key不存在,返回的数据也是nil-->null,并不是会空指针异常) 当在去查询的时候,无论是数据真的不存在,还是系统出现了各种问题 这个时候查询的redis是null,然后就会去查询数据库(redis的源码执行流程) ,但是数据库中也没有数据,那么就会给前端返回一个null值 但是这个时候如果并发特别大,会造成无用的很多次查询 当第一个人过来查询的时候,查询缓存和数据库都没有数据,因为返回的是一个"null" 作为缓存存到数据库中 -->以user为key的数据-->redis.get("user")-->是null的,又去查询数据库,发现这个数据库返回的也是null-->就把这个"null"-->以user的为key存入到redis中 redis.set("user","null")(重点注意对象:必须要设置失效时间,当时我所设置的失效时间是10分钟,而且强制规定一定不能大于10分钟) 那么为什么非得设置的这么短呢? (体现严谨性的时候到了) 有没有一种可能就是当时数据库中没有数据,但是后来数据库中有数据了,如果这个时候缓存中时间设置的非常长,就会一直去走缓存,不会走数据库 mybatis的二级缓存集成redis,什么时候数据会进入redis中?当实现了一次从数据库中查询数据的时候才会进入redis中 从redis中查redis.get("user"); List<User> userListRedis 从数据库中查select * from user; List<User> userListMybatis if(userListRedis.size() == userListMybatis.size()) { return userListRedis; } else{ 把多余的数据以追加的形式存入到redis中 redis.set("user", JSON.toString(userListMybatis)); return userListMybatis; } 如果缓存不过期,则就不会去请求数据库,会保护了数据库被请求的并发次数 解耦!!!! Redis-3.2.5--->在两分钟之内4000的并发一直在不断请求redis(而且所查询的数据都是null) redis.get("key");--->key一定是不存在的 1s:4000 2s:4000 3s:4000 应该是在一分多钟的时候就不会再走redis了,会直接抛异常了
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。