Redis

Redis 简介

Redis(Remote Dictionary Server)是一个开源的、基于内存的键值存储系统,支持多种数据结构(如字符串、哈希、列表、集合等)。它广泛用于缓存、消息队列、实时分析等场景,因其高性能和低延迟特性而备受青睐。

什么是redis?

redis是一款非关系型数据(key-value),主要作用是用来作为数据缓存,数据可以存储在内存中.

为什么要用redis?

mysql中的数据直接存储在硬盘上的, 每次查询连接mysql从硬盘上查询,

所以将一些更新较少(例如新闻类型,商品类型),短时间内查询较多的(秒杀,抢购)

从内存中查询数据,减轻了mysql的压力

redis在项目中的作用?

缓存

计数器 incr key 值加1 decr key 值减1

排行榜 zset 排序

数据排重 set 不能存储重复元素

消息队列 list rput lpop

分布式锁 微服务中用到分布式

Redis 线程模型

redis6.0之前是严格意义上的单线程,执行命令和处理客户端连接都是由一个线程完成的.

redis6.0之后引入了多线程, 把处理客户端连接的任务交给一部分线程完成,

执行命令仍然由一个单线程完成,这样保证并发安全(访问量再大,都是一个一个的执行)

为什么是单线程执行命令,为什么还这么快

操作都是在内存中

底层基于哈希结构,查询/操作时,可以通过key计算出哈希值,快速的定位到位置

单线程模式,避免执行命令时,线程的切换.

Redis 持久化

redis数据默认存储在内存中,一旦断电数据就没有了

所以redis提供了数据持久化功能

有两种持久化方式:

rdb方式 :Redis DataBase 以快照方式 ,将redis中的数据写入到一个dump.rdb文件中

当满足条件时,自动执行, 也是redis中默认开启的持久化方法

自动持久化条件

save 900 1 900秒 有一次key的变化 save 300 10 save 60 10000

也可以直接执行save命令,主动的持久化

AOF 方式: 以日志的方式,记录redis中执行的写操作命令(set del), 当下次还原是,执行日志文件,逐行执行命令,还原数据.

redis中默认没有开启aof持久化方式, 如果需要开启,在redis配置文件中修改

以通过 appendfilename 参数修改

AOF 同步机制

appendfsync always

#每次修改都会 sync。消耗性能

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

重启 redis 生效

定时任务 例如点赞数量 redis-->mysql

redis事务

redis中的事务,是将我们要执行的多条命令进行打包, 当执行事务中的多条命令时作为一个整体,期间是不能插入其他命令,保证命令执行的原子性,

但是,执行时,又不保证命令执行成功的原子性, 例如3条指令,两条成功,一条失败, 即使有执行失败,不会让这3条命令回滚.

multi 开始事务

set a aa

set b bb

incr a

exec 执行事务

redisTemplate.multi(); 开启事务

ValueOperations valueOperations = redisTemplate.opsForValue();字符类型

valueOperations.set(k,v);

valueOperations.set();

valueOperations.set();

valueOperations.set();`

redisTemplate.exec();执行事务

Key 过期策略

redis 中的key可以进行定时存储

复制代码
valueOperations.set(k,v, 5, TimeUnit.MINUTES);

key的过期策略,说的是,key的到期时间到达后,redis以何种机制删除到期的key

惰性删除: 在key过期时间到达后,不会立即删除,只是将key的状态改为不可用,当下次使用时,才会删除过期的key

定期删除: 在key过期时间到达后,将key的状态改为不可用,定时定期的主动删除过期的key

key会绑定一个回调函数,到期后,自动将状态给为不可以

缓存穿透、缓存击穿、缓存雪崩

缓存穿透(重点)

当查询一个数据库中没有的数据时( 例如id=-1), redis没有,我们就去数据查询,此时缓存没有,被穿透了

如果别人恶意攻击,也会穿过redis,直接到达mysql,可能导致mysql崩溃

解决方案:

1.当mysql查询没有时, 可以向redis也存放key-value value可以为aaa(标记) ,当从redis中取出值为aaa,表名mysql不存在,不再查询了

2.对参数的合法性进行验证, 例如id没有-1的

3.使用布隆过滤器,进行验证

缓存击穿

数据库中数据存在, redis中的某个热点key突然过期,此时有大量请求同时到来,发现redis中没有,大量的请求查询mysql,导致mysql崩溃 ,

解决方案:

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

2.查询mysql时加锁,还可以在锁内二次判断是否已经查询到了,如果查询到了就不在查询mysql了

缓存雪崩

大量的key过期