布隆过滤器本质是一个位数组,位数组就是数组的每个元素都只占用 1 bit 。每个元素只能是 0 或者 1。这样申请一个 10000 个元素的位数组只占用 10000 / 8 = 1250 B 的空间。布隆过滤器除了一个位数组,还有 K 个哈希函数。
等一下,是不是有点绕,不太好理解。
我们知道hash函数可以根据一个值生成一个对应的数字,然后与一个长度可以取模可以得到一个下标值 (你不知道?看看HashMap的实现吧)
或者你根本不知道hash是怎么实现的,没关系,也可以先理解下面的,我们先把这个函数假设为 int getIndex (String value), 根据值获取到一个下标
假设我们现在有一个数组,长度是5,每个元素的值都是0
0 , 0 , 0 , 0 , 0
现在我们数据库中一共有五个id
a , b , c , d , e
现在我们对id们执行getIndex函数可以得到
getIndex(a) = 0
getIndex(b) = 1
getIndex(c) = 1 // 假设函数有一些误差
getIndex(d) = 2
getIndex(e) = 3
想一想,现在来了一个新元素,f 怎么样判断在id里面存在不存在呢?
我们把开始的数组和getIndex关联起来, 将getindex的值作为下标,设置值为1,数组就会变成
1 , 1 , 1 , 1 , 0
然后我们再来判断f是否存在,假设 getIndex(f) = 4
ok了,我们只需要判断数组里的下标4是否是1,是1就存在,0就不存在了嘛
那如果 getIndex(f) = 2 呢? 我们开了上帝视角,很明显f不存在呀。
布隆过滤器不能100%判断一个元素是否真的存在数组中,但能100%判断它不存在与数组中,这取决于hash函数的算法程度
布隆过滤器防止缓存穿透
通过对布隆过滤器的理解,我们能就过滤掉大部分的无效请求了,把数据库中所有的id都getindex解析一次放到布隆过滤器中,请求过来的时候判断,如果不存在就直接返回空就行了
缓存雪崩如果缓存集中在一段时间内失效,发生大量的缓存穿透,所有的查询都落在数据库上,造成了缓存雪崩。
其实与缓存击穿的理论差不多,都是突然失效导致的击穿数据库。
雪崩与击穿的不同点在于雪崩强调集中失效两个字
想象~ 我现在有三个缓存key存在redis中,过期时间是一天
一天后,由于key有可能是同时设置的缓存,导致这三个key同时失效了,即使我的缓存击穿问题已经解决,这时候因为集中的key失效,也会造成击穿!,这是量级发生了改变,就像x和y的关系, x表示key的多少,y表示请求的多少。。。
解决方案
设置不同的过期时间
热度数据你永远不可能每个缓存都能命中的。什么是好的缓存策略,好的缓存策略是能够识别热点数据,并在热点被读取的时候能够保证命中,这是一个好的缓存策略所必须的条件之一。
缓存一致性数据库的数据和缓存的数据是不可能一致的,数据分为最终一致和强一致两类。
强一致 不可以使用缓存
缓存能做的只能保证数据的最终一致性。
我们能做的只能是尽可能的保证数据的一致性。
不管是先删库再删缓存 还是 先删缓存再删库,都可能出现数据不一致的情况,因为读和写操作是并发的,我们没办法保证他们的先后顺序。
具体应对策略根据业务需求来制订。
缓存过期和淘汰
Redis设置的过期时间。这个key过期时是怎么删除的?
Redis采用的是定期删除,注意不是定时删除,不可能为每一个key做一个定时任务去监控删除,这样会耗尽服务器资源。
默认是每100ms检测一次,遇到过期的key则进行删除,这里的检测也不是顺序检测,而是随机检测。
另外为了防止有漏网之鱼,例如在100ms检查的中间间隙,某个key过期,但同时key访问又进来了,这时触发 惰性删除策略 redis会在读取时判断是否已经过期,过期则直接删除。
内存淘汰是指一部分key在内存不够用的情况下会被Redis自动删除,从而会出现从缓存中查不到数据的情况。
例如我们的服务器内存为2G、但是随着业务的发展缓存的数据已经超过2G了。但是这并不能影响我们程序的运行。所以redis会从key列表中抽取一定的热度低的数据进行淘汰策略,腾出空间存储新的key
...持续更新
github: https://github.com/294678380/redis-lerning