Redis:从缓存王者到数据“瑞士军刀”,你玩明白了吗?

目录

什么是redis,他是用来做什么的

redis除了用做缓存,还可以做什么

redis线程模型

redis持久化

RDB方式

AOF方式

redis事务

key过期策略

redis和mysql如何保证数据一致

缓存穿透

问题

解决方案

布隆过滤器

优点:

缺点:

布隆过滤器案例

缓存击穿

问题:

解决办法:

缓存雪崩

问题:

解决方案:


什么是redis,他是用来做什么的

nosql(not only sql)不仅仅是sql,泛指非关系型数据库,一般把非关系型数据库称为nosql数据库

redis,mongodb

redis是一个nosql类型的数据库(非关系型数据库)数据在内存中以键值对形式存储。

读写速度快,也提供数据持久化方式

一般最常用的场景就是把redis用来做缓存

redis除了用做缓存,还可以做什么

1、缓存

2、计数器  点赞

3、排行榜  数据结构  zset按照分数排序

4、数据排重  去除重复数据

5、消息队列  redis中有一个list结构

6、分布式锁

redis线程模型

为什么设计单线程模型速度也很快?

1、数据都存储在内存中,读写的速度都是内存级别的,所有快

2、基于哈希的结构存储,通过key可以快速在哈希表中找到对应的数据

3、避免了上下文切换,由于是单线程模式,可以不存在切换的开销

redis持久化

我们现在除了缓存数据外,还将一些例如点赞等数据也是存储到redis的,这样服务万一断电,那么内存中的数据就丢失了

所以redis提供了持久化功能

redis提供了两种持久化机制

RDB方式

是redis中默认的持久化机制(默认开启)

当满足条件时,会对我们内存中的数据进行拍照,以快照的方式把数据存储到.rdb文件中

快照把(key:value)数据直接存储在rdb文件中

触发持久化规则:在redis.conf文件中

save 900 1

save 300 10

save 60 1000

也可以执行save命令

AOF方式

也是redis持久化的一种方式,默认是没有启用的

需要在redis.conf文件中配置

appendonly no-->yes

aof方式是以执行日志的方式记录的,将所有写操作的命令按顺序追加记录到"appendonly.aof"文件中,还原数据时,逐行执行这些命令即可

配置规则

appendfsync always 每次执行都会记录,消耗大

appendfsync everysec 每秒执行一次 sync,可能会丢失这 1s 的数据(默认)

redis事务

redis中的事务相比mysql事务,简单很多

redis中的事务,保证同一个事务在执行时,事务或者的多条命令执行时,不会有其他事务插入到中间执行,因为redis是单线程

redis事务执行时,不保证多条指令执行的原子性,多条指令执行时,中间如果有错误的命令,不会影响其他命令的执行。

mutil 命令开启事务

  set key value  加入事务

  set key value  加入事务

exec 执行事务中的命令

 

key过期策略

redisTemplate.opsForValue().set("k","v",10,TimeUnit.SECONDS);

redis中可以为key维护一个状态,表示是否过期

当定时时间过期后,将状态改为已过期,并没有立即删除key

在redis中有两种策略删除过期的key

1、惰性删除:在key过期后,在下次使用此key时,发现key已经过期,然后再删除过期的key,不足之处,浪费内存空间,优点,不需要有额外的线程定时定点的跟踪删除

2、定期删除:每隔指定的周期,对redis中过期的key进行清理

redis和mysql如何保证数据一致

此问题讲的是如何尽可能的保证,redis中和mysql中的数据保持一致的(主要是发生修改时)

采用延时双删策略,在更新mysql之前先删除redis中的数据,在mysql没有完全更新数据完成时,其他线程可以先读取旧的数据,在mysql更新完之后,再次删除redis中的数据,后来的线程确保读到的就是最新的mysql中的数据

缓存穿透

问题

key对应的数据在数据库不存在,每次先查询缓存,缓存中没有,然后去查询数据库,数据库也不存在,返回null,为null,没有往缓存中放,每次都是直接查询的mysql

解决方案

id10:值

id-1:null/-1

1、当mysql中查询不到时,可以向redis中存储一个key-value,value可以为null/--1,表名mysql中不存在

2、对参数进行校验不满足,不查询

3、使用布隆过滤器

布隆过滤器

是一个二进制数组,用于判断元素是否存在

使用k个哈希函数对某个值进行哈希计算,计算出来的哈希存储到对应的数组位置,把数组原来位置的0变为1,查询是否存在时,同样用哈希函数计算哈希值,如果每个位置上都是1,表明数据是可能存在,只要有一个数据是0,那么数据是肯定不存在的

会有一定误判率

优点:

1. 时间复杂度低,增加和查询元素的时间复杂为 O(N)

2. 保密性强,布隆过滤器不存储元素本身

3. 存储空间小,布隆过滤器是非常节省空间的

缺点:

1. 误判

2. 无法删除

布隆过滤器案例

基于谷歌 guava

实现布隆过滤器添加依赖

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>30.1-jre</version>
</dependency>

配置布隆过滤器

Configuration
public class BloomFilterConfig {
    @Bean
    public BloomFilter<String> bloomFilter() {
        //100000:布隆过滤器容量 0.01 为 误判率
        return BloomFilter.create(Funnels.stringFunnel(Charset.defaultCharset()),100000, 0.01);
    }
}

注入测试

@Autowired
BloomFilter bloomFilter;
@GetMapping(path = "/test")
public CommonResult test(){
    bloomFilter.put("aa");
    System.out.println(bloomFilter.mightContain("aa"));
    System.out.println(bloomFilter.mightContain("bb"));
    return new CommonResult(200, null,"查询成功");
}

缓存击穿

问题:

数据在数据库中是存在的,只是在redis中的热点key是过期了,这时有大量的请求到来,同时请求到mysql,导致mysql压力过大,一般在秒杀这类场景中会发生的

模拟秒杀:1、写后台管理  管理秒杀商品  100

                   2、前端界面  卖商品

解决办法:

1、热点数据设置较长过期时间

2、跑定时任务,在缓存失效前刷新新的缓存

3、加锁,可以查询mysql的代码进行加锁,一个线程查询完后,把数据放到redis中,对访问mysql进行控制

缓存雪崩

问题:

大量的热点key过期,或者redis服务中出现了问题,大量请求访问到mysql

解决方案:

1、可以给热点key设置随机过期时间,避免同时过期

2、可以使用集群部署,如果有一台redis服务出现问题,其他redis服务仍然可以使用,还可以将热点的key,存储到不同的redis库中

3、跑定时任务,在缓存失效前刷进新的缓存

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值