今天看到了一篇Redis的文章觉得很好,就总结一下写在Java后端知识体系中。
1、使用场景
- 缓存:做数据缓存,对于大量请求DB的情况下,为了减少DB的压力,使用Redis做缓存,从而减轻DB的压力,在高并发的情况下缓存可以极大的提高性能。但是使用缓存也会带来一些问题:
1:数据库与缓存一致性的问题
、2:缓存雪崩、缓存击穿、缓存穿透的问题
- 消息中间件:Redis包含了五种数据结构,
String
、Hash
、List
、Set
、SortedSet
,这五种数据结构中可以使用List
来实现消息中间件的需求,在Redis中可以通过生产者:LPUSH
和消费者:RPOP
来实现。
2、Redis持久化
在Redis中存在两种持久化机制:
RDB
:Redis DataBaseAOF
:Append Only File
2.1、RDB
- RDB持久化机制是将当前进程的数据以快照的形式持久化到磁盘中,会保存在一个指定文件中(
默认是dump.rbd
) - RDB的实现原理是在当前主线程运行的情况下
fork
一条子线程
来做持久化数据的操作,这样的操作也会导致一个问题就是Redis宕机时会丢失最后一次
快照的数据。 - RDB优点:
- 持久化数据时快速,
- 恢复数据时更快。
2.2、AOF
AOF持久化机制是记录Redis中的每一次的增删改的操作,将这些操作以日志的形式记录下来保存到指定的文件中(默认为appendonly.aof
),类似与MySQL中的binlog
日志。
-
AOF的实现原理是Redis每执行一个增删改的命令,都会把这个命令添加到AOF文件中,当Redis重启时,将会读取AOF文件进行数据恢复。时间截至到 Redis宕机前的最后时刻。
-
AOF优点:
- 保存数据的完整性能够持久化到最后时刻的数据。
- 数据的可读性,在aof的恢复文件中可以很清楚的阅读Redis中的每个操作利于恢复数据。
-
AOF缺点:
- 大量的写入操作数据会导致aof文件过大
- aof写入操作会产生重复写入的问题
- 在恢复大量数据时性能不如RDB。
3、缓存问题解析
3.1、缓存雪崩
缓存雪崩的场景:大量的缓存失效,导致大量的请求打到DB上,导致DB崩溃。
解决策略:
- 给缓存的过期时间设定随机值,这样将缓存过期时间尽可能的分散,避免大量的缓存时间在同一时间失效。
- 通过设定主从模式
3.2、缓存击穿
缓存击穿的场景:大量的请求都去请求同一个key,造成的该key扛着大量的高并发,当该key失效的瞬间所有的请求就会打到DB上,瞬间的大量请求造成DB崩溃
解决策略:
- 通过分布式锁来解决此类问题,通过分布式锁限定同一时刻只有一个请求到该key中。
3.3、缓存穿透
缓存穿透的场景:用户频繁的请求缓存中以及DB中都不存在的数据(例如请求id=-1),当大量的这些数据请求过来时会导致数据库压力过大,使数据库崩溃
解决策略:
- 对于请求不存在的数据可以通过布隆过滤器过滤掉垃圾请求。
- 还可以通过在接口中进行判断将无效的请求进行拦截
3.4、缓存一致性
缓存一致性场景:
- 用户更新数据时若直接更新DB数据,然后再删除缓存数据再进行同步,此时其它用户请求过来,在删除缓存之前读取了缓存,那么用户获取到的数据就是脏数据,造成了数据不一致问题。
- 若先删除缓存再更新数据库,然后再同步数据到缓存中,此情况下会出现当两个线程请求,一个线程更新,另一个线程查询,更新线程删除缓存中的数据,但是还没有更新DB,查询线程发现缓存中没有数据会获取DB的数据然后将数据同步到缓存中,更新缓存再去更新DB,这样就导致了缓存与DB数据不一致的问题。
解决策略: 使用队列解决先删缓存再更新数据库的问题(该解决方案还没想明白如果实现,但是觉得用队列应该可以实现,将更新的操作放入队列,查询的队列也放入队列,这样线程的执行顺序会顺序执行,必须等更新操作完整之后才能继续查询操作,具体如何实现希望下方评论能给与思路
)
我是一个会敲代码的汤姆猫!