目录
redis双写一致性
如果将redis作为缓存,当修改了数据库中的数据同时也要更新缓存的数据,缓存和数据库中的数据应该如何保持一致呢?这里就出现了redis双写一致性的问题
方法一:延迟双删

那么这时候又出现了一个问题,究竟是先删除缓存中的数据呢,还是先修改数据库呢?其实不管是先删除缓存还是先删除数据库,其实都存在一些问题,接下来一个一个来分析
先删除缓存,再操作数据库的情况:

通过上图中就可以发现,出现线程不安全问题,就会导致最终缓存与数据库中的值不一致问题,那么接下来我们来看看先操作数据库再删除缓存的情况:

此时通过上图中就可以发现,出现线程不安全问题,也会导致最终缓存与数据库中的值不一致问题
那么我们现在来讨论一下为什么要删除两次缓存,这是因为在分布式下,一般数据库都存在主从模式,那么主数据库需要将数据同步到从数据库,这时候redis可能会往从数据库更新缓存,这时候就会出现脏数据问题,所以需要延迟一会等待从数据库也更新完毕,但是这样子也只是控制一一大部分脏数据的风险,并不能完全解决,没有办法做到绝对的强一致性,那么如果需要保持一致应该怎么做呢?
方法二:分布式锁
想必大家心里都知道,对于线程安全问题我们可以通过加锁来解决这个问题,那么解决这个问题就可以保证数据强一致啦。

但是加锁往往带来的是性能问题,创建锁和销毁锁的开销加上阻塞的时间,这都会产生性能上的问题,那么这个问题应该如何进行优化呢?
对于大部分情况下,对于redis的操作都是读多写少,那么这时候我们就可以使用共享锁+排他锁来进行性能优化
共享锁:读锁readLock,加锁之后,其他线程可以共享读操作,但是不能进行写操作
排他锁:独占锁writeLock,加锁之后,阻塞其他线程的读写操作

通过共享锁+排他锁的引入,那么在修改数据的时候不允许读写操作,那么就不会出现数据不一致问题,但是当读数据的时候,其他线程也可以进行读操作,不会影响多个线程读操作优化了性能问题,但是性能还是不太高的
所以redis双写一致性问题,需要进行业务进行具体分析,如果需要数据强一致性,那么就采用redisson中的读写锁来保证数据同步,如果对实时性要求没那么高只需要保证最终一致性的话,那么采用异步的方案同步数据是比较好的

redis持久化
redis作为一种数据库,我们需要保证数据的持久化,那么下面我们就来了解一下redis中是如何保证数据的持久化的
RDB
RDB全称Redis Database Backup file(Redis 数据备份文件),也叫做Redis数据快照,就是将内存中的所有数据都记录到磁盘中,当Redis出现故障重启后,从磁盘读取快照文件进行数据恢复
RDB可以进行主动备份:
save命令:由Redis主进程来执行RDB,会阻塞所有命令
basave命令:开启子进程执行RDB,避免主进程收到影响
Redis内部有触发RDB的机制:
#900秒内,如果至少有1个key被修改,则执行bgsave
save 900 1
#300秒内,如果至少有10个key被修改,则执行bgsave
save 300 10
#60秒内,如果至少有10000个key被修改,则执行bgsave
save 60 10000
这里的配置也可以在redis.conf文件中自定义配置
RDB执行原理:
Redis 主进程调用
fork()生成子进程子进程和主进程共享同一块内存物理页面,不拷贝数据,瞬间完成创建
子进程:遍历内存数据,全程阻塞写入 .rdb 文件,生成快照
主进程:继续正常处理客户端读写请求
若主进程修改某数据:触发写时复制,单独拷贝一份新页面给主进程,子进程依旧保留快照旧数据,互不干扰
客户端/配置触发 bgsave
↓
Redis 主进程
│
├─ 调用 fork() 创建子进程
│ ↓
│ 子进程(专门做RDB)
│ │
│ │ 共享主进程内存页(COW写时复制)
│ │
│ ├─ 遍历所有DB、所有Key
│ │
│ ├─ 按Redis二进制格式序列化
│ │
│ ├─ 写入临时 .rdb 临时文件
│ │
│ └─ 写完原子替换为 dump.rdb → 子进程退出
│
↓
主进程继续正常处理 增删改查 请求
│
└─ 若有客户端修改数据 → 触发COW,复制新内存页
子进程依然用旧快照数据,互不干扰
AOF
AOF全称为Append Only File(追加文件) redis处理的每一个写命令都会记录在AOF文件中,可以看作是一个记录命令日志的文件
AOF默认是关闭的,需要在redis.conf配置文件中开启:appendonly yes(默认是no)
AOF的命令记录频率也可以通过redis.conf文件来配置:
appendfsync always //表示每执行一次写命令,立即记录到AOF文件中
appendfsync everysec //写命令执行完后先放入AOF缓冲区,每隔1秒中将缓冲区中的数据写入到AOF文件中,是默认方案
appendfsync no //写命令执行完后先放入AOF缓冲区,由操作系统决堤的那个什么时候将缓冲区的内容写入磁盘
AOF重写:AOF重写是指AOF会记录对同一个key的多次写操作,但是只有最后一次写操作才有意思,那么通过执行bgrewriteaof命令,就可以让AOF文件执行重写操作,用最少的命令达到相同的效果,使得AOF文件不那么大

在redis中也有触发自动重写的阈值,可以在redis.conf中配置:
auto-aof-rewrite-percentage 100 // 表示AOF比上一次文件,增长超过多少百分比就触发重写
auto-aof-rewrite-min-size64mb //表示AOF文件体积最小多大以上触发重写
RDB和AOF对比:

RDB和AOF都有自己的优缺点,如果对数据安全性要求比较高,那么实际开发中往往会结合两者使用,日常RDB 存全量快照做备份,AOF 记增量命令保数据;重启优先读 AOF,redis4.0 混合持久化(AOF 文件开头是 RDB 全量快照 + 后面是增量 AOF 命令日志)把 RDB 嵌进 AOF,兼顾速度和安全。
redis数据过期策略
在redis中key过期后需要将数据从内存总删除掉,那么就可以按照不同的规则进行删除,这种删除策略就被称之为数据的过期策略
惰性删除
惰性删除:当设置了key的过期时间后,就需要去管了,当需要该key时,再进行检查是否过期,如果过期了就删除,没过期就返回
优点:对CPU友好,只会在使用key时才会进行过期检查,对于很多用不到的key不用浪费时间进行过期检查
缺点:如果一个key过期了,但是一直没有使用,那这个key就会一直存在在内存中,内存永远得不到释放
定期删除
定期删除:每隔一段时间,就会对一些key进行检查,删除里面过期的key(随机key进行检查,并删除过期key)
定期清理的两种模式:
SLOW:执行频率默认为10hz,每次不超过25ms
FAST:执行频率不固定,但是两次间隔不低于2ms,每次耗时不超过1ms
优点:可以通过限制删除操作和执行的时长和频率来减少删除操作对CPU的影响,也能有效释放过期key占用的内存
缺点:难以确定删除操作执行时长和频率
在redis中的过期删除策略中,是惰性删除和定期删除两种策略进行配合使用的
redis数据淘汰策略
当redis内存不够的时候,这时候再向redis中添加新数据,那么redis就会按照某一种规则将内存中的数据删除掉,这种数据删除规则被称之为内存淘汰策略
| 策略分类 | 策略名称 | 淘汰数据范围 | 核心淘汰规则 | 典型适用场景 |
|---|---|---|---|---|
| 不淘汰类 | noeviction | 无(不删除任何数据) | Redis 默认策略,内存达上限后,所有写操作直接返回错误,仅支持读操作 | 核心数据不允许丢失、可接受写失败的业务场景 |
| 全量 Key 淘汰类(所有 Key 均参与淘汰) | allkeys-lru | 整个 Redis 实例的所有 Key(无论是否设置过期时间) | 淘汰 最近最少使用(LRU)的 Key,优先删除长时间未访问的数据 | 通用业务场景,大部分 Redis 集群的首选策略,兼顾性能与内存利用率 |
| 全量 Key 淘汰类 | allkeys-lfu | 整个 Redis 实例的所有 Key(无论是否设置过期时间) | 淘汰 访问频率最低(LFU)的 Key,优先删除累计访问次数最少的数据 | 热点流量、高频访问业务,如电商秒杀、热门内容缓存,精准保留高价值热数据 |
| 全量 Key 淘汰类 | allkeys-random | 整个 Redis 实例的所有 Key(无论是否设置过期时间) | 完全随机选择 Key 进行删除,无任何访问规则偏好 | 对数据访问无明显冷热区分、业务逻辑简单的场景 |
| 过期 Key 专属淘汰类(仅参与设置了过期时间的 Key) | volatile-lru | 仅设置了过期时间的 Key | 在过期 Key 范围内,淘汰 最近最少使用(LRU) 的 Key | 业务数据有明确过期周期,同时需优先保留近期访问的有效数据 |
| 过期 Key 专属淘汰类 | volatile-lfu | 仅设置了过期时间的 Key | 在过期 Key 范围内,淘汰 访问频率最低(LFU) 的 Key | 有过期规则的高频访问业务,如限时活动、会员权益缓存,精准保留高访问量的有效数据 |
| 过期 Key 专属淘汰类 | volatile-random | 仅设置了过期时间的 Key | 在过期 Key 范围内,完全随机选择 Key 进行删除 | 对过期数据无访问偏好、业务逻辑简单的场景 |
| 过期 Key 专属淘汰类 | volatile-ttl | 仅设置了过期时间的 Key | 在过期 Key 范围内,淘汰剩余存活时间(TTL)最短的 Key,优先删除马上就要过期的数据 | 业务数据有明确的生命周期,需优先清理即将失效的数据,如订单超时、验证码缓存 |


