目录
一.缓存穿透
1.出现场景:
请求redis获取数据时,频繁的出现查询不到的情况,这样会一直请求数据库,数据库查询不到也不会往redis里设置key,这样当别人使用不存在的数据请求时,会导致数据库压力过大
2.解决办法
(1)设置key为null
当查询数据库时,将不存在的数据设置为null存在reids中
优点:使用简单
缺点:
a.消耗内存
b.当reids将值设置为null时,数据库后面可能会更新数据,这样就会出现数据不一致的情况,如果在不是很要求强一致性的场景下,可以合理的设置不同的过期时间来解决
(2)使用布隆过滤器
布隆过滤器是什么?
布隆过滤器相当于是一串数组,数组里只存在二级制的0和1,如果存在数据,那么布隆过滤器会将key进行多次计算,并设置数组下标对应的值为1,这样请求redis时就会先使用布隆过滤器确定当前数据是否存在
优点:节省内存
缺点:布隆过滤器可能存在误判的情况
java集成redisson使用布隆过滤器
a)引入依赖
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.16.0</version>
</dependency>
b)初始化布隆过滤器
/** 预计插入的数据 */
Integer expectedInsertions = 10000;
/** 误判率 */
Double fpp = 0.01;
// Redis连接配置
Config config = new Config();
config.useSingleServer().setAddress("redis://192.168.0.1:6379");
config.useSingleServer().setPassword("123456");
// 初始化布隆过滤器
RedissonClient client = Redisson.create(config);
RBloomFilter<Object> bloomFilter = client.getBloomFilter("user");
bloomFilter.tryInit(expectedInsertions, fpp);
c)增加数据
// 布隆过滤器增加元素
for (Integer i = 0; i < expectedInsertions; i++) {
bloomFilter.add(i);
}
4)过滤数据
//判断是否存在元素
Boolean b = bloomFilter.contains(i)
二.缓存击穿
1.出现场景:
当redis中的某个key过期时,大量的请求向数据库请求,这时数据库承受不住压力崩溃
2.解决方案:
(1)互斥锁
当线程1请求数据库时,加上互斥锁,这个时候其他的线程需要等待这个锁释放,等待线程1请求完成后写入redis,其他线程才会返回数据
优点:强一致性
缺点:性能差
(2)逻辑过期
在redis存储数据时,不设置过期时间,在数据库字段中加上一个过期时间的字段,当从reids中获取数据判断该数据过期时,加上互斥锁,同时开启一个新线程去异步请求数据库,这是原线程可以直接返回,其他线程遇到互斥锁也会先使用原有的数据
优点:高可用
缺点:数据可能存在不一致
三.缓存雪崩
1,出现场景
当某个时间段内,redis缓存大量的过期或者redis宕机了,这是所有的请求都会流向数据库导致压力过大
2.解决方案
(1)redis的过期时间加随机值
(2)redis采用集群模式
(3)使用nginx或者gateway的降级限流
(4)使用多级缓存
四.双写一致性
1.出现场景:
当修改数据库数据时,不论是先删除redis再修改数据库还是先修改数据库再删除redis都会可能造成脏数据的情况
2.解决方案
(1)高可用
使用延时双删,在删除redis后修改数据库,再延迟一定时间再次删除redis
优点:大大降低了脏数据的可能性
缺点:在延迟的这段时间还是有可能会出现脏数据的情况,无法保证强一致性
(2)强一致性
使用互斥所,读写锁,来保证强一致性
优点:数据的强一致性
缺点:效率不高
五.redis的数据持久化
1.RDB:数据快照
(1)开启方式
a)手动:在命令窗口输入save(使用主进程执行,会阻塞数据) bgsqve(会开启新的进程)
b)配置文件:在redis.conf中配置 save 900 1(900秒有一次更新就执行)
(2)原理
reids的主进程中存在一个页表区域,页表会记录物理内存和虚拟地址的映射关系,当执行RDB时,会开启一个副进程,这个进程会复制一份相同的页表
当开启RDB时,主进程会读写数据,这时物理内存必须复制一份数据进行修改,从而保证数据的一致
(3)优缺点
优点:文件量小,数据恢复速度快
缺点:数据完整性不高,资源占用高
2.AOP:追加文件
(1)开启方式
需要在redis.conf中找到appendonly no,将no改成yes主动开启
(2)原理
AOF会记录每次执行的命令写入文件中,这样就会导致文件量过大,同时可以使用命令来缩减无效的命令,AOF存在三种记录刷盘方式,最常用的是appendsync everysec:1秒钟刷盘一次,效率中等,丢失的数据可能性小
(3)优缺点
优点:数据完整性高,资源占用小,仅是io的读写操作
缺点:数据文件量大,数据恢复数据较慢
六.reids的分布式锁
1.使用场景
在设计负载均衡的情况下,有多台服务请求redis,这时需要在服务外加锁
例如:抢票,购物
2.使用方式
(1)使用命令setnx
SET lock value NX PX 10
(2)使用redisson
3.可能出现问题
(1)redis分布式锁延期
a)出现场景
当线程获取锁的时候,由于网络或其他原因导致业务未执行完成从而将锁释放了
b)解决方案
使用redisson的watch dog看门狗机制,每隔三分之一的过期时间续一次锁,其他线程会进行while循环等待当前线程结束
(2)redis分布式锁主节点宕机
a)出现场景
当redis设置了组从节点,当主节点宕机,由于哨兵机制会选取一个从节点变为主节点,这是会有两个线程同时拥有锁
b)解决方案
使用redLock红锁机制,同时让多个redis服务拥有锁,缺点是性能消耗太高,不符合redis高可用的思想,建议使用zookepper来保证强一致性思想
七.redis的集群
redis的集群有主从模式,哨兵模式,集群分片模式
1.主从模式
(1)数据同步原理
a)全量同步
a.从节点向主节点发送数据同步请求,主节点判断从节点是否是第一次同步
b.是第一次同步的话,主节点会发送数据的版本号,从节点接收并同步
c.主节点生成RDB文件发送给从节点执行
d.在执行RDB文件时,主节点会将这部分信息记录到日志中发给从节点执行
b)增量同步
a.从节点向主节点发送数据同步请求,主节点判断从节点是否是第一次同步
b.不是第一次同步的话,主节点会发送RDB文件发送给从节点接收并同步
c.在执行RDB文件时,主节点会将这部分信息记录到日志中发给从节点执行
2,哨兵模式
(1)实现原理
基于心跳机制,当主节点长时间未响应从节点,那么会根据一定机制来选取一个从节点来担任主节点
(2)脑裂问题
由于网络波动,选举出新的主节点后,原来的主节点恢复了,这就会导致原主节点数据清空导致到了数据丢失
这时需要修改reids配置,设置reids最少拥有一个主节点并且主从数据同步的延迟不超过五秒
3,集群分片模式
(1)实现原理
采用多个主节点,每个主节点保存不同的数据,同时每个主节点都拥有从节点
主节点之间也会采用心跳机制互相监测
八.redis速度快的原因
1.纯内存操作
2.单线程,没有上下文之间的切换
3.不是阻塞式IO,实现了IO的多路复用