生命无罪,健康万岁,我是laity。
我曾七次鄙视自己的灵魂:
第一次,当它本可进取时,却故作谦卑;
第二次,当它在空虚时,用爱欲来填充;
第三次,在困难和容易之间,它选择了容易;
第四次,它犯了错,却借由别人也会犯错来宽慰自己;
第五次,它自由软弱,却把它认为是生命的坚韧;
第六次,当它鄙夷一张丑恶的嘴脸时,却不知那正是自己面具中的一副;
第七次,它侧身于生活的污泥中,虽不甘心,却又畏首畏尾。
关于缓存异常,我们常见的有三个问题:缓存雪崩、缓存击穿、缓存穿透。 这三个问题一旦发生,会导致大量请求直接落到数据库层面。如果请求的并发量很大,会影响数据库的运行,严重的会导致数据库宕机。
为了避免异常带来的损失,我们需要了解每种异常的原因以及解决方案,提高系统的可靠性。
Redis中的数据大面积失效(时间过期)的情景
均匀过期:给热点数据设置不同的过期时间,给每个key的失效时间加一个随机值;
设置热点数据永不过期:不设置失效时间,有更新的话,需要更新缓存;服务降级:指服务针对不同的数据采用不同的处理方式:
Redis 缓存实例发生故障宕机的场景
举个例子:比如业务系统正常运行时,请求入口每秒最大允许进入的请求数是1万个,其中9000请求个可以被缓存处理,余下1000个会发送给数据库处理。一旦发生雪崩,数据库每秒处理的请求突然增加到1万个,此时我们就可以启动限流机制。在前端请求入口处,只允许每秒进入1000个请求,其他的直接拒绝掉。这样就可以避免大量并发请求发送给数据库。
就是去查询一个一定不存在的数据
后期可能又有这个条数据了)。一个key过期,但是被高访问
zookeeper与etcd,用来做锁都比redis要好很多
关于缓存异常有兴趣的同学可以看下这篇:关于缓存异常:缓存雪崩、击穿、穿透的解决方案
关于分布式锁有兴趣的同学可以看下这篇:Redis分布式锁的正确打开方式
布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。
布隆过滤器本质上是一个初始值都为 0 的 二进制数组和 N 个哈希函数组成。
当我们想标记某个数据存在时(例如,数据x已被写入数据库),布隆过滤器会通过三个操作完成标记:
如下图所示:

三次哈希,对应的二进制数组下标分别是 1、3、7,将原始数据从 0 变为 1。
同样的,我们标记数据y的逻辑也是一样的。如下图:

三次哈希,对应的二进制数组下标分别是 1、5、9,将原始数据从 0 变为 1。
下标 1,之前已经被操作设置成 1,则本次认为是哈希冲突,不需要改动。
Hash 规则:如果在 Hash 后,原始位它是 0 的话,将其从 0 变为 1;如果本身这一位就是 1 的话,则保持不变。
正是因为存在哈希冲突,导致布隆过滤器的判断存在误差。
也因为哈希冲突的存在,导致布隆过滤器不能轻易删除数据,存在误删的风险。
比如,当查询一件商品的缓存信息时,我们首先要判断这件商品是否存在。
如下图:

注意:布隆过滤器只能精确判断数据不存在情况,对于存在我们只能说是可能,因为存在Hash冲突情况,当然这个概率非常低。
至于在Java应用中使用布隆过滤器,我们可以通过Redisson实现,它内置了布隆过滤器。
首先引入依赖
<!-- Redis锁 - 红锁:分布式锁,分布式对象等功能的框架 -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.17.7</version>
</dependency>
代码示例:
package com.laity.product;
import org.junit.jupiter.api.Test;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/**
* @author: Laity
* @Project: JavaLaity
* @Package: com.laity.product.config.MyRedissonConfig
* @Date: 2022年10月18日 01:39
* @Description: 测试基于redisson使用布隆过滤
*/
@SpringBootTest
public class RedissonBloomFilter {
@Autowired
private RedissonClient redissonClient;
@Test
void redissonBloom(){
RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter("test-bloom-filter");
// 初始化布隆过滤器,数组长度100W,误判率 1%
bloomFilter.tryInit(1000000L, 0.01);
// 添加数据
bloomFilter.add("Shawn");
// 判断是否存在
System.out.println(bloomFilter.contains("laity"));
System.out.println(bloomFilter.contains("itlaity"));
}
}
运行结果:
false // 肯定不存在
true // 可能存在,有1%的误判率
与其让平凡与胆怯缚住自己的手脚,不如倾生命的全部能量奋力一搏。我是Laity,正在前行的Laity。