redis的使用与问题

130 阅读8分钟

前言

其中包含了Redis篇、数据库篇、框架篇、微服务篇等题

Redis 篇

redis使用场景

redis使用场景

其中 缓存、分布式锁是比较常见的。

其他的还有 redis集群redis事务

缓存

  • 缓存穿透:请求不存在的 key
  • 缓存击穿:Redis 中 key 过期,请求数据库
  • 缓存雪崩:大量 key 过期或 Redis 宕机

缓存穿透

正常使用 redis 的情况

正常使用redis

缓存穿透:查询一个不存在的数据,myqsl查询不到数据也不会直接写入缓存,就会导致每次请求都会查询数据库。

解决方案一:缓存空数据,查询返回的空数据,让把这个空数据写入缓存。

优点:实现简单

缺点:大量数据都为空,会消耗内存,可能发生不一致问题(本来查询的数据为空,存入缓存,后来添加了该数据,但是缓存仍然为空)。

解决方案二:布隆过滤器

添加布隆过滤器

优点:内存占用较少,没有多余key

缺点:实现复杂,存在误判

缓存击穿

缓存击穿:给某个 key 设置了过期时间,当 key 过期的时候,恰好这时间点对这个 key 有大量的并发请求,这些请求可能会瞬间把 DB 压垮

缓存击穿

解决方案一:互斥锁(分布式锁)

互斥锁

特点:强一致性,但是性能较差(需要等待互斥锁)

解决方案二:逻辑过期

逻辑过期

特点:高可用,性能较优(不需要等待互斥锁)

缓存雪崩

缓存雪崩:在同一时间段大量的缓存key同时失效或者 Redis 服务宕机,导致大量请求到达数据库,给数据库带来巨大压力。

解决方案

  • 给不同的 key 的 TTL(过期时间)添加随机值
  • 利用 Redis 集群提高服务的可用性(Redis宕机情况) 哨兵模式、集群模式
  • 给缓存业务添加降级限流策略(可作为系统的保底策略,适用于穿透、击穿、雪崩) ngxin或者spring cloud gateway
  • 给业务添加多级缓存

一道面试题

面试官: 什么是缓存雪崩 ?怎么解决 ?

答:

缓存雪崩意思是设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效,请求全部转发到数据库,数据库 瞬时压力过重雪崩。与缓存击穿的区别: 雪崩是很多key,击穿是某一个key缓存。

解决方案主要是可以将缓存失效时间分散开,比如可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

双写一致性

双写一致性:缓存 和 数据库 保持数据一致

根据业务场景可分为:要求高一致性允许延迟一致性

读写数据流程

  • 读数据:查询缓存,命中,直接返回;未命中,查数据库,写入缓存,设置超时时间

  • 写数据:延迟双删(极大降低脏数据风险,但仍可能出现脏数据)

    删除缓存 ---> 修改数据库 ---(延时)---> 删除缓存

    延时的目的:为了等待主数据库往从数据库同步数据

保持强一致性:使用读写锁,读加共享锁,写加排他锁。当然性能必然会下降

允许短暂不一致

  • 异步通知保持最终一致性

    异步通知保持一致性

  • 基于 Canal 的异步通知

    基于canal通知保持一致性

一道面试题

面试官: redis做为缓存,mysql的数据如何与redis进行同步呢? (双写一致性)

答:我最近做的这个项目,里面有xxxx (根据自己的简历上写)的功能,数据同步可以有一定的延时(符合大部分业务) 我们当时采用的阿里的canal组件实现数据同步:不需要更改业务代码,部署一个canal服务。canal服务把自己伪装成mysql的一个从节点,当mysql数据更新以后,canal会读取binlog数据,然后在通过canal的客户端获取到数据,更新缓存即可。

持久化

  1. RDB
  2. AOF

RDB 全称 Redis Database Backup file(Redis数据备份文件),也叫数据库备份快照。就是把内存中的所有数据记录到磁盘中,当 Redis 实例故障重启后,从磁盘读取快照文件,回复数据。

主动备份

[root@localhost ~]# redis-cli
127.0.0.1:6379>save	# 由Redis主线程执行RDB,会阻塞所有命令
ok
127.0.0.1:6379>bgsave # 开启子线程执行RDB,避免主线程受到干扰
Background saving started

被动备份,Redis 内部有出发 RDB 的机制,可以在 redis.conf 文件中找到,格式如下

# 900秒内,至少有一个 key 被修改,则执行bgsave
save 900 1
save 300 10
save 600 10000

RDB的执行原理:以后补充

AOF 全称 Append Only File(追加文件)。Redis 处理的每一个命令都会记录在 AOF 文件,可看作是命令日志文件。

AOF 默认是关闭的,需要在 redis.conf 配置文件中开启;

# 是否开启 AOF,默认为 no
appendonly yes
# AOF的文件名称
appendfilename "appendonly.aof"

AOF 的命令记录的频率,也可以通过 redis.conf 文件配置;

# 表示每执行一次写命令,立即记录到AOF文件
appendfsync always
# 写命令执行完先放入AOF缓冲区,然后表示每隔1秒将缓冲区数据写到AOF文件,是默认方案
appendfsync everysec
# 写命令执行完先放入AOF缓冲区,由操作系统决定何时将缓冲区内容写回磁盘
appendfsync no
配置项刷盘时机优点缺点
Always同步刷盘可靠性高,几乎不丢失数据性能影响大
everysec每秒刷盘性能适中最多丢失1秒数据
no操作系统控制性能最好可靠性较差,可能丢失大量数据

对比

RDB和AOF各有自己的优缺点,如果对数据安全性要求较高,在实际开发中往往会结合两者来使用

RDBAOF
持久化方式定时对整个内存做快照记录每一次执行的命令
数据完整性不完整,两次备份之间会丢失相对完整,取决于刷盘策略
文件大小会有压缩,文件体积小记录命令,文件体积很大
宕机恢复速度很快
数据恢复优先级低,因为数据完整性不如AOF高,因为数据完整性更高
系统资源占用高,大量CPU和内存消耗低,主要是磁盘IO资源。但AOF重写时会占用大量CPU和内存资源
使用场景可以容忍数分钟的数据丢失,追求更快的启动速度对数据安全性要求较高常见

一道面试题

面试官:redis做为缓存,数据的持久化是怎么做的?

:在Redis中提供了两种数据持久化的方式: 1、RDB 2、AOF

面试官:这两种持久化方式有什么区别呢?

:RDB是一个快照文件,它是把redis内存存储的数据写到磁盘上,当redis实例宕机恢复数据的时候,方便从RDB的快照文件中恢复数据。 AOF的含义是追加文件,当redis操作写命令的时候,都会存储这个文件中,当redis实例宕机恢复数据的时候,会从这个文件中再次执行一遍命令来恢复数据

面试官:这两种方式,哪种恢复的比较快呢?

:RDB因为是二进制文件,在保存的时候体积也是比较小的,它恢复的比较快,但是它有可能会丢数据,我们通常在项目中也会使用AOF来恢复数据,虽然AOF恢复的速度慢一些,但是它丢数据的风险要小很多,在AOF文件中可以设置刷盘策略,当时设置的就是每秒批量写入一次命令

数据过期策略

  • 惰性删除策略 惰性删除:设置该key过期时间后,我们不去管它,当需要该key时,我们在检查其是否过期,如果过期,我们就删掉它,反之返回该key

    优点:对CPU友好,只会在使用该key时才会进行过期检查,对于很多用不到的key不用浪费时间进行过期检查

    缺点:对内存不友好,如果一个key已经过期,但是一直没有使用,那么该kev就会一直存在内存中,内存永远不会释放

  • 定期删除策略

    定期删除:每隔一段时间,我们就对一些key进行检查,删除里面过期的key(从一定数量的数据库中取出一定数量的随机key进行检查,并删除其中的过期key)。

    定期清理有两种模式:

    • SLOW模式是定时任务,执行频率默认为10hz,每次不超过25ms,以通过修改配置文件redis.conf 的hz 选项来调 整这个次数
    • FAST模式执行频率不固定,但两次间隔不低于2ms,每次耗时不超过1ms

    优点:可以通过限制删除操作执行的时长和频率来减少删除操作对 CPU 的影响。另外定期删除,也能有效释放过期键 占用的内存。

    缺点:难以确定删除操作执行的时长和频率

Redis的过期删除策略:惰性删除 + 定期删除两种策略进行配合使用