Redis面试题

什么是Redis

Redisopen in new window 是一个基于 C 语言开发的开源数据库,与传统数据库不同的是 Redis 的数据是存在内存中的(内存数据库),读写速度非常快,被广泛应用于缓存方向。并且,Redis 存储的是 KV 键值对数据。 Redis 内置了多种数据类型实现(比如 String、Hash、Sorted Set、Bitmap)。并且,Redis 还支持事务 、持久化、Lua 脚本、多种开箱即用的集群方案(Redis Sentinel、Redis Cluster)。

Redis为什么快

Redis 内部做了非常多的性能优化,比较重要的主要有下面 3 点:

  • Redis 基于内存,内存的访问速度是磁盘的上千倍;
  • Redis 基于 Reactor 模式设计开发了一套高效的事件处理模型,主要是单线程事件循环和 IO 多路复用;
  • Redis 内置了多种优化过后的数据结构实现,性能非常高。
什么是缓存穿透?怎么解决

当用户访问的数据,既不在缓存中,也不在数据库中,导致请求在访问缓存时,发现缓存缺失,再去访问数据库时,发现数据库中也没有要访问的数据,没办法构建缓存数据,来服务后续的请求。那么当有大量这样的请求到来时,数据库的压力骤增,这就是缓存穿透的问题。

缓存穿透的发生一般有这两种情况:

  • 业务误操作,缓存中的数据和数据库中的数据都被误删除了,所以导致缓存和数据库中都没有数据;
  • 黑客恶意攻击,故意大量访问某些读取不存在数据的业务;

应对缓存穿透的方案,常见的方案有三种:

  • 第一种方案,非法请求的限制;
  • 第二种方案,缓存空值或者默认值;
  • 第三种方案,使用布隆过滤器快速判断数据是否存在,避免通过查询数据库来判断数据是否存在;
什么是缓存雪崩?怎么解决

当大量缓存数据在同一时间过期(失效)或者 Redis 故障宕机时,如果此时有大量的用户请求,都无法在 Redis 中处理,于是全部请求都直接访问数据库,从而导致数据库的压力骤增,严重的会造成数据库宕机,从而形成一系列连锁反应,造成整个系统崩溃,这就是缓存雪崩的问题。

可以看到,发生缓存雪崩有两个原因:

  • 大量数据同时过期;
  • Redis 故障宕机;

针对大量数据同时过期问题:

  • 均匀设置过期时间;
  • 互斥锁;
  • 双key策略;
  • 后台更新缓存;
    针对Redis故障宕机
  • 服务熔断或请求限流机制;
  • 构建Redis缓存高可靠集群;
什么是缓存击穿?怎么解决

如果缓存中的某个热点数据过期了,此时大量的请求访问了该热点数据,就无法从缓存中读取,直接访问数据库,数据库很容易就被高并发的请求冲垮,这就是缓存击穿的问题。
应对缓存击穿可以采取前面说到两种方案:

  • 互斥锁方案,保证同一时间只有一个业务线程更新缓存,未能获取互斥锁的请求,要么等待锁释放后重新读取缓存,要么就返回空值或者默认值。
  • 不给热点数据设置过期时间,由后台异步更新缓存,或者在热点数据准备要过期前,提前通知后台线程更新缓存以及重新设置过期时间;
    在这里插入图片描述
如何保证缓存一致性?

对于旁路缓存模式来说,一般使用:先更新数据库,再删除缓存这种策略。因为删除缓存这一步相对于操作MySQL来说速度快很多,所以很难出现并发问题。如果先删除缓存再更新数据库就可能在更新数据库期间导致并发问题,从而使数据不一致的问题。
如果更新数据库成功,删除缓存失败的话,有两种解决方法:

  • 重试机制,可以引入消息队列MQ来进行 ,操作成功则移除队列,操作失败则重试,重试次数过多则抛出异常。
  • 订阅MySQL binlog,再次操作缓存,使用阿里巴巴的canal中间件解析binglog。
AOF 持久化

AOF持久化方式是Redis每执行一条写操作命令时,就把该命令以追加的方式写到一个文件里,重启Redis时直接执行这个文件进行恢复数据。注意只会记录写操作命令,读操作命令是不会被记录的。

Redis是先执行写操作,写操作成功以后才将该命令记录到AOF日志中,这样做的好处是避免了额外的检查开销以及不会阻塞当前写操作命令的执行(但是可能会阻塞下一条命令)。

这样做的风险是执行写操作命令和记录日志是两个过程,那当 Redis 在还没来得及将命令写入到硬盘时,服务器发生宕机了,这个数据就会有丢失的风险。且可能会给「下一个」命令带来阻塞风险。

AOF写回策略

Redis 写入 AOF 日志的过程:

  • 1.Redis 执行完写操作命令后,会将命令追加到 server.aof_buf 缓冲区;
  • 2.然后通过 write() 系统调用,将 aof_buf 缓冲区的数据写入到 AOF 文件,此时数据并没有写入到硬盘,而是拷贝到了内核缓冲区page cache,等待内核将数据写入硬盘;
  • 3.具体内核缓冲区的数据什么时候写入到硬盘,由内核决定。

在 redis.conf 配置文件中的 appendfsync 配置项可以有以下 3 种参数可填:

  • Always,这个单词的意思是「总是」,所以它的意思是每次写操作命令执行完后,同步将 AOF 日志数据写回硬盘;
  • Everysec,这个单词的意思是「每秒」,所以它的意思是每次写操作命令执行完后,先将命令写入到 AOF
    文件的内核缓冲区,然后每隔一秒将缓冲区里的内容写回到硬盘;
  • No,意味着不由 Redis 控制写回硬盘的时机,转交给操作系统控制写回的时机,也就是每次写操作命令执行完后,先将命令写入到 AOF文件的内核缓冲区,再由操作系统决定何时将缓冲区内容写回硬盘。

这三种策略只是在控制 fsync() 函数的调用时机。当应用程序向文件写入数据时,内核通常先将数据复制到内核缓冲区中,然后排入队列,然后由内核决定何时写入硬盘。

AOF的重写机制

Redis 为了避免 AOF 文件越写越大,提供了 AOF 重写机制。AOF 重写机制是在重写时,读取当前数据库中的所有键值对,然后将每一个键值对用一条命令记录到**「新的 AOF 文件」**(避免污染现有的日志文件),等到全部记录完后,就将新的 AOF 文件替换掉现有的 AOF 文件。

写入 AOF 日志的操作虽然是在主进程完成的,因为它写入的内容不多,所以一般不太影响命令的操作。但是Redis 的重写 AOF 过程是由后台子进程 bgrewriteaof 来完成的。

当子进程完成 AOF 重写工作后,会向主进程发送一条信号,信号是进程间通讯的一种方式,且是异步的。主进程收到该信号后,会调用一个信号处理函数,该函数会将 AOF 重写缓冲区中的所有内容追加到新的 AOF 的文件中,使得新旧两个 AOF 文件所保存的数据库状态一致;将新的 AOF 的文件进行改名,覆盖现有的 AOF 文件。

RDB持久化

RDB是快照持久化,所以RDB 快照就是记录某一个瞬间的内存数据,记录的是实际数据,而 AOF 文件记录的是命令操作的日志,而不是实际的数据。因此在 Redis 恢复数据时, RDB 恢复数据的效率会比 AOF 高些,因为直接将 RDB 文件读入内存就可以。

  • 900 秒之内,对数据库进行了至少 1 次修改;
  • 300 秒之内,对数据库进行了至少 10 次修改;
  • 60 秒之内,对数据库进行了至少 10000 次修改。

只要满足上面条件的任意一个,就会执行 bgsave,执行快照是一个比较重的操作,如果频率太频繁,可能会对 Redis 性能产生影响。如果频率太低,服务器故障时,丢失的数据会更多。

RDB 快照的缺点,在服务器发生故障时,丢失的数据会比 AOF 持久化的方式更多。

在持久化过程中,Redis通过写时复制技术实现了执行 bgsave 过程中,Redis 依然可以继续处理操作命令的,也就是数据是能被修改的。发生了写时复制后,RDB 快照保存的是原本的内存数据,而主线程刚修改的数据,是没办法在这一时间写入 RDB 文件的,只能交由下一次的 bgsave 快照。

AOF和RDB混合持久化

当开启了混合持久化时,在 AOF 重写日志时,fork 出来的重写子进程会先将与主线程共享的内存数据以 RDB 方式写入到 AOF 文件,然后主线程处理的操作命令会被记录在重写缓冲区里,重写缓冲区里的增量命令会以 AOF 方式写入到 AOF 文件,写入完成后通知主进程将新的含有 RDB 格式和 AOF 格式的 AOF 文件替换旧的的 AOF 文件。

也就是说,使用了混合持久化,AOF 文件的前半部分是 RDB 格式的全量数据后半部分是 AOF 格式的增量数据

Redis过期策略

Redis 是可以对 key 设置过期时间的,因此需要有相应的机制将已过期的键值对删除,而做这个工作的就是过期键值删除策略。

每当我们对一个 key 设置了过期时间时,Redis 会把该 key 带上过期时间存储到一个过期字典中,也就是说「过期字典」,字典实际上是哈希表,保存了数据库中所有 key 的过期时间。当我们查询一个 key 时,Redis 首先检查该 key 是否存在于过期字典中:

  • 如果不在,则正常读取键值;
  • 如果存在,则会获取该 key 的过期时间,然后与当前系统时间进行比对,如果比系统时间大,那就没有过期,否则判定该 key 已过期。

Redis 选择「惰性删除+定期删除」这两种策略配和使用,以求在合理使用 CPU 时间和避免内存浪费之间取得平衡。

惰性删除:Redis 在访问或者修改 key 之前,都会调用 expireIfNeeded 函数对其进行检查,检查 key 是否过期:如果过期,则删除该 key,选择异步删除,还是选择同步删除,然后返回 null 客户端;如果没有过期,不做任何处理,然后返回正常的键值对给客户端;
定期删除:每隔一段时间「随机」从数据库中取出一定数量的 key 进行检查,并删除其中的过期key。

Redis内存淘汰策略

1、不进行数据淘汰的策略:触发OOM
2、进行数据淘汰的策略

  • volatile-random:随机淘汰设置了过期时间的任意键值;
  • volatile-ttl:优先淘汰更早过期的键值。
  • volatile-lru(Redis3.0 之前,默认的内存淘汰策略):淘汰所有设置了过期时间的键值中,最久未使用的键值;
  • volatile-lfu(Redis 4.0 后新增的内存淘汰策略):淘汰所有设置了过期时间的键值中,最少使用的键值;
  • allkeys-random:随机淘汰任意键值;
  • allkeys-lru:淘汰整个键值中最久未使用的键值;
  • allkeys-lfu(Redis 4.0 后新增的内存淘汰策略):淘汰整个键值中最少使用的键值。
Redis 的大key问题

大 key 并不是指 key 的值很大,而是 key 对应的 value 很大。

一般而言,下面这两种情况被称为大 key:

  • String 类型的值大于 10 KB;
  • Hash、List、Set、ZSet 类型的元素的个数超过 5000个;

大 key 会带来以下四种影响:

  • 客户端超时阻塞。
  • 引发网络阻塞。
  • 阻塞工作线程。
  • 内存分布不均

如何删除大key

  • 分批次删除
  • 一步删除
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sklit88

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值