Bootstrap

[每周一更]-(第124期):模拟面试|缓存面试思路解析

在这里插入图片描述

文章目录

31 为什么 Redis 不立刻删除已经过期的数据?

  1. Redis 是怎么删除过期 key 的?
  2. Redis 为什么不立刻删除已经过期的 key?
  3. Redis 为什么不每个 key 都启动一个定时器,监控过期时间?
  4. Redis 是如何执行定期删除的?
  5. 为什么 Redis 在定期删除的时候不一次性把所有的过期 key 都删除掉?
  6. 当你从 Redis 上查询数据的时候,有可能查询到过期的数据吗?
  7. 当 Redis 生成 RDB 文件的时候,会怎么处理过期的 key?
  8. 当 Redis 重写 AOF 文件的时候,会怎么处理过期的 key?
  9. Redis 定期删除的循环是不是执行得越频繁就越好?
  10. 如果设计一个本地缓存,你会怎么实现删除过期 key 的功能?
  11. 你是怎么确定过期时间的?过期时间太长会怎样,太短又会怎样?

1. Redis 是怎么删除过期 key 的?

Redis 使用惰性删除(lazy deletion)和定期删除(periodic deletion)两种策略来删除过期的 key。

  • 惰性删除:当客户端尝试访问某个 key 时,Redis 会检查该 key 是否过期,如果已经过期,则在查询时删除它。
  • 定期删除:Redis 会周期性地扫描一部分存储的数据,删除其中已经过期的 key。

2. Redis 为什么不立刻删除已经过期的 key?

立刻删除过期的 key 会导致性能开销大,影响 Redis 的响应速度。因为 Redis 是高性能的内存数据库,频繁地执行删除操作可能会造成阻塞,从而影响其他请求的处理。因此,Redis 采用惰性删除和定期删除的策略,以平衡性能与内存的利用。

3. Redis 为什么不每个 key 都启动一个定时器,监控过期时间?

如果每个 key 都启动一个定时器,Redis 的内存和 CPU 开销将会非常大。Redis 可能会有成千上万的 key,创建和维护大量定时器不仅复杂,还会影响 Redis 的性能。因此,Redis 选择了在查询时检测过期(惰性删除)和周期性扫描一部分 key(定期删除)来管理过期数据。

4. Redis 是如何执行定期删除的?

Redis 会在设定的时间间隔内(默认 100ms)随机抽取一部分设置了过期时间的 key 进行检查,并删除已过期的 key。Redis 并不会一次性遍历所有的 key,而是通过抽样的方式控制开销,以保证数据库的稳定性和高性能。

5. 为什么 Redis 在定期删除的时候不一次性把所有的过期 key 都删除掉?

如果一次性删除所有过期的 key 可能会引起系统短暂的停顿,导致响应变慢,尤其在有大量过期 key 的情况下会引发性能瓶颈。因此,Redis 采取分步的方式,避免删除操作对性能的集中影响。

6. 当你从 Redis 上查询数据的时候,有可能查询到过期的数据吗?

可能会。在使用惰性删除策略时,Redis 只有在访问一个 key 时才会检查其是否过期,因此存在查询到已经过期但尚未被删除的 key 的可能性。

7. 当 Redis 生成 RDB 文件的时候,会怎么处理过期的 key?

在生成 RDB 文件时,Redis 会检查并跳过已过期的 key。只有未过期的 key 才会被写入到 RDB 文件中,以保证备份文件的有效性和数据的准确性。

8. 当 Redis 重写 AOF 文件的时候,会怎么处理过期的 key?

在 AOF 重写过程中,Redis 会跳过已过期的 key,确保重写后的 AOF 文件只包含有效数据。因此,在 AOF 文件重写完成后,可以减少文件体积,提升持久化效率。

9. Redis 定期删除的循环是不是执行得越频繁就越好?

不一定。定期删除的循环过于频繁会占用过多的 CPU 资源,影响正常的请求处理。因此需要合理地设置频率,找到删除操作与性能之间的平衡点。一般情况下,Redis 的默认设置已经比较合理。

10. 如果设计一个本地缓存,你会怎么实现删除过期 key 的功能?

可以考虑与 Redis 类似的策略,结合惰性删除和定期删除:

  • 惰性删除:在访问缓存数据时检查是否过期,如果过期则删除。
  • 定期删除:设定一个定时任务,周期性地随机检查一部分缓存数据并删除过期的 key。

11. 你是怎么确定过期时间的?过期时间太长会怎样,太短又会怎样?

过期时间的确定取决于业务需求:

  • 如果过期时间太长,缓存会占用更多的内存,但可以减少缓存失效导致的数据库访问压力。
  • 如果过期时间太短,虽然节省了内存,但可能会频繁访问后端数据库,增加负载。因此,需要权衡存储资源和访问效率来合理设定。

32 缓存淘汰策略:怎么淘汰缓存命中率才不会下降?

  1. 你知道什么是 LFU,什么是 LRU 吗?可不可以手写一个?
  2. 什么情况下使用 LFU,什么情况下使用 LRU?
  3. Redis 支持哪些淘汰策略?你们公司的 Redis 上的淘汰策略使用了哪个?为什么用这个?
  4. 你使用的本地缓存是如何控制内存使用量的?
  5. 你业务里面的缓存命中率有多高?还能不能进一步提高?怎么进一步提高?
  6. 假如说 A 和 B 两个业务共用一个 Redis,那么有办法控制 A 业务的 Redis 内存使用量吗?怎么控制?
  7. 现在我的业务里面有普通用户和 VIP 用户。现在我希望在缓存内存不足的时候,优先淘汰普通用户的数据,该怎么做?

1. 你知道什么是 LFU,什么是 LRU 吗?可不可以手写一个?

  • LFU(Least Frequently Used):最少使用策略。缓存会优先淘汰访问频率最低的数据,即被访问次数最少的元素。
  • LRU(Least Recently Used):最近最少使用策略。优先淘汰一段时间内没有被访问的数据,即最近最少使用的元素。

示例代码展示一个简单的 LRU 缓存,可以使用 Python 的 OrderedDict 实现:

python复制代码from collections import OrderedDict

class LRUCache:
    def __init__(self, capacity: int):
        self.cache = OrderedDict()
        self.capacity = capacity

    def get(self, key: int) -> int:
        if key not in self.cache:
            return -1
        self.cache.move_to_end(key)  # 将访问的 key 移到末尾
        return self.cache[key]

    def put(self, key: int, value: int) -> None:
        if key in self.cache:
            self.cache.move_to_end(key)
        self.cache[key] = value
        if len(self.cache) > self.capacity:
            self.cache.popitem(last=False)  # 删除最旧的

# 使用示例
cache = LRUCache(2)
cache.put(1, 1)
cache.put(2, 2)
print
;