redis系列2---高频面试题

106 阅读3分钟

说说缓存穿透?缓存雪崩?缓存击穿?

这个可以说是八股中的八股了,看名字好像都差不多,那怎么区分?

先说缓存穿透,穿透的意思就是透过你的缓存,直接访问数据库,因为咱们代码平时写的都是if redis不存在,就去查数据库,那如果别人疯狂调你接口,传的还都是不存在的key怎么办?都去查数据库还是无效的,很快db就死了。解决方案很简单,查不到的时候,放一个空缓存就是了,比如set一个"{}"的字符串,查询的时候如果看到这种数据,就可以直接返回,不用走db了。当然我们可以设置过期时间,比如10分钟之类的,如果数据库插入这个数据,还要想办法清除这个空对象缓存。

缓存击穿的意思是热key可能会导致的问题,比如现在要秒杀一个商品,n个请求过来查询,发现缓存没有,大家一起去数据库查,数据库直接挂了,或者活动正在办着,然后修改了商品属性,缓存需要重建,在这个瞬间来了大量查询,直接打到mysql了。解决方案也比较简单粗暴,要么就在缓存重建的时候加锁或者提前缓存好不允许修改,要么就是设置永不过期,当然如果你的活动明知道20填,你设置21天缓存也可以。

缓存雪崩,从名字看,就是连环事件,比如缓存在某一个阶段同时到期,数据库压力暴增导致事故。解决方案就是尽量让缓存失效的 时间不要统一,所以我们平时写代码的时候给过期值在范围内随机是个不错的选择。当然,本地缓存,限流等等都可以很大程度的辅助解决这些问题。

说说布隆过滤器?

简单的介绍下,如果你想判断一万个数字中是否包含某个数字,大家一般会想到用list放1W个数(假设都是int),然后用list.contains判断。但是这里耗费的空间就是1w*4字节=4W字节 大约40K,这里数组的每个单位就是4字节,但是如果我们把这个单位换成位,就能足足省下32倍空间,比如我们声明长度为1W的位数组,初始位0,把一万个数字,每个数字在add的时候,hash n次得到n个值,再用这些值取模1W,那每个数字最终都会在这个位上有个标记(0变成1),当然由于hash操作不可避免的会有hash冲突,所以数字1和6是有可能定位到同一个位置的(空间越大,冲突发生的几率就越小),所以你想判断7这个数字在这个数组内吗?很明显如果他在,你确定不了,因为你无法判断7对应这个位置上的1标识是不是他打的,也许是10打的呢?但是,如果7对应的位置是0,那一定不存在,因为其他数据和自己都没打这个位置标识。所以当他给你返回不存在,那一定是真的,如果他告诉你存在,则不一定是真的,有可能并不在,是别的数据影响到了。应用点有很多,比如判断这个新闻有没有给你推送过,你有一批500W数据需要去重,用java去重可能会耗费大量内存,但是用redis只需要1M左右。