【面试分享】面试题——redis

一、题目

  • Redis的数据持久化策略有哪些
  • 什么是缓存穿透,怎么解决
  • 什么是布隆过滤器
  • 什么是缓存击穿,怎么解决
  • 什么是缓存雪崩,怎么解决
  • redis双写问题
  • Redis分布式锁如何实现
  • Redis实现分布式锁如何合理的控制锁的有效时长
  • Redis的数据过期策略有哪些
  • Redis的数据淘汰策略有哪些
  • Redis集群有哪些方案, 知道嘛
  • 什么是 Redis 主从同步
  • 你们使用Redis是单点还是集群 ? 哪种集群
  • Redis分片集群中数据是怎么存储和读取的
  • redis集群脑裂
  • 怎么保证redis的高并发高可用
  • 你们用过Redis的事务吗 ? 事务的命令有哪些
  • Redis是单线程的,但是为什么还那么快?

二、答案

1、Redis的数据持久化策略有哪些

Redis的数据持久化策略主要有两种:

  • RDB(Redis Database)持久化:RDB持久化通过fork子进程将Redis在某个时间点的数据保存到磁盘上的快照文件中(通常为dump.rdb)。这种方式的好处是可以在磁盘上创建非常紧凑的数据文件,适用于备份和灾难恢复。但是,它可能会丢失最后一次快照之后的数据,且在恢复大量数据时可能会导致Redis的启动时间较长。
  • AOF(Append Only File)持久化:AOF持久化将Redis的每个写操作(包括写命令和删除命令)追加到一个文件中(AOF文件)。当Redis重启时,会重新执行AOF文件中的命令来恢复数据。这种方式的好处是可以保证数据的完整性和一致性,但缺点是日志文件通常比RDB文件大,且恢复数据时需要执行较多的命令,可能会导致恢复速度较慢。

为了充分利用持久化的优势,Redis也支持同时启用RDB和AOF持久化。

2、什么是缓存穿透,怎么解决

缓存穿透指的是恶意用户或攻击者通过请求不存在于缓存和后端存储中的数据来使得所有请求都落到后端存储上,导致系统瘫痪。

解决方案包括:

  • 使用布隆过滤器:将所有可能存在的数据哈希到一个足够大的bitmap中,一个不存在的数据会被这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。
  • 缓存空结果:如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),仍然把这个空结果进行缓存,但它的过期时间会很短。
  • 使用黑白名单:通过维护一个黑白名单来过滤掉无效的请求。
  • 加入缓存预热机制:在系统启动或低峰时段,预先将一些热点数据加载到缓存中,以减少缓存穿透的发生。

3、什么是布隆过滤器

**布隆过滤器(Bloom Filter)**是1970年由布隆提出的,它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中,其优点是空间效率和查询时间都比一般的算法要好得多,但缺点是有一定的误识别率和删除困难。

4、什么是缓存击穿,怎么解决

缓存击穿指的是在高并发访问下,某个热点数据失效后,大量请求同时涌入后端存储,导致后端存储负载增大、响应时间变慢,甚至瘫痪。

解决方案包括:

  • 使用互斥锁或分布式锁:对热点数据的访问进行加锁控制,避免多个请求同时访问后端存储。
  • 热点数据预加载:提前将热点数据加载到缓存中,并在其失效时快速刷新缓存。
  • 设置合理的过期时间:避免大量热点数据的过期时间集中在同一时间段。

5、什么是缓存雪崩,怎么解决

缓存雪崩指的是因为某些原因导致缓存中大量的数据同时失效或过期,导致后续请求都落到后端存储上,从而引起系统负载暴增、性能下降甚至瘫痪。

解决方案包括:

  • 避免缓存集中失效:设置不同的过期时间,避免大量缓存同时失效。
  • 使用分布式缓存:通过分布式部署来分散缓存的访问压力。
  • 设置缓存预热和自动刷新机制:在系统启动或低峰时段,预先将一些热点数据加载到缓存中,并在缓存即将失效时自动刷新缓存。
  • 应用程序限流:对访问缓存的请求进行限流,避免过多的请求同时访问后端存储。

6、redis双写问题

在分布式系统中,双写问题通常是指数据在多个存储系统(例如数据库和缓存)中更新时出现的不一致性。在使用Redis作为缓存层时,双写问题尤为常见。具体来说,当数据在数据库和Redis缓存中存在副本时,任何对数据的更新操作都需要在两个地方进行,即"双写"。这可能导致以下问题:

  • 数据库更新成功,缓存更新失败。
  • 缓存更新成功,数据库更新失败。
  • 数据库和缓存的更新顺序不同步。

解决双写问题的方法包括:

  • Cache Aside Pattern(旁路缓存模式):最常用的缓存策略。先从缓存中读取数据,如果缓存中没有数据,从数据库中读取数据,然后将数据写入缓存。更新数据库时,使缓存中的数据失效或更新缓存。
  • Write Through Cache(写通缓存):写操作直接更新缓存,缓存负责同步更新数据库。
  • Write Behind Cache(写回缓存):写操作更新缓存,由缓存异步地更新数据库。

7、Redis分布式锁如何实现

Redis实现分布式锁主要有以下几种方式:

  1. SETNX(SET if Not eXists)命令
    • 尝试将一个指定的键设置为某个值,只有当该键不存在时才能设置成功。可以将某个键作为锁的标识,多个客户端竞争将该键设置为某个值,设置成功的客户端获得了锁。
    • 优点:简单、易于理解和实现。
    • 缺点:无法处理锁的超时和释放问题。
  2. EXPIRE命令
    • 为锁设置一个过期时间,避免锁被永久持有。即使锁没有被有效释放,也能保证在一定时间后自动释放。
    • 优点:可以避免锁被永久持有,自动释放锁。
    • 缺点:无法处理锁的重入问题。
  3. GETSET命令
    • 原子性地获取锁的当前值并设置新的值。通过比较旧的值与自己的标识是否相同,如果相同则表示获取锁成功,否则表示获取锁失败。
    • 优点:可以实现锁的重入和安全释放。
    • 缺点:无法直接处理锁的超时问题,需要结合其他机制。
  4. Lua脚本
    • 利用Redis的Lua脚本功能,可以在Redis端执行一系列原子操作,保证分布式锁的正确性。通过编写Lua脚本,可以复杂地控制锁的获取、续期、释放等逻辑。
    • 优点:可以实现复杂的锁逻辑,保证操作的原子性。
    • 缺点:相对复杂,需要编写和维护Lua脚本。

8、Redis实现分布式锁如何合理的控制锁的有效时长

合理控制Redis分布式锁的有效时长,可以通过以下方式实现:

  1. 根据操作预期时间设置过期时间
    • 估算操作需要的时间,并加上一些缓冲时间,以应对网络延迟和其他不确定因素。
  2. 使用锁续命机制
    • 对于一些可能超过预期时间的长时间操作,可以在锁快要过期时,通过续命机制延长锁的有效时间。客户端可以定期检查锁是否仍然持有,并尝试续命。
  3. Watchdog机制
    • 在许多分布式锁实现中(如Apache Curator的分布式锁),Watchdog机制会自动续命直到客户端明确释放锁。获取锁时,启动Watchdog线程,该线程定期检查并续命。释放锁时,停止Watchdog线程。

9、Redis的数据过期策略有哪些

Redis的数据过期策略主要有以下几种:

  1. 定时删除策略
    • 在设置键的同时,设置键的过期时间,Redis通过定时任务删除过期键值对。
  2. 惰性删除策略
    • 在访问键时,如果发现键已经过期,Redis删除该键值对。
  3. 定期删除策略
    • 使用定期任务扫描数据库,删除过期键值对。
  4. 过期检查策略
    • 在执行某些命令时,Redis检查键是否过期,如果过期则删除。
  5. 定期删除和惰性删除结合策略
    • 结合定期删除策略和惰性删除策略,提高过期键的删除效率。
  6. 随机删除策略
    • 随机选择一定数量的键进行检查和删除,减少删除过期键的压力。

10、Redis的数据淘汰策略有哪些

Redis的数据淘汰策略主要有以下几种(这些策略在内存不足以容纳新写入数据时触发):

  1. Noeviction(默认)
    • 当内存不足以容纳新写入数据时,新写入操作会报错,表示写入失败。不会删除任何已有的key,也不会释放任何内存空间。
  2. Allkeys-lru
    • 从所有key中选择最近最少使用的key进行删除,以释放内存空间。
  3. Volatile-lru
    • 从设置了过期时间的key中选择最近最少使用的key进行删除,以释放内存空间。
  4. Allkeys-random
    • 从所有key中随机选择一个进行删除,以释放内存空间。
  5. Volatile-random
    • 从设置了过期时间的key中随机选择一个进行删除,以释放内存空间。
  6. Volatile-ttl
    • 从设置了过期时间的key中选择剩余生存时间最短的key进行删除,越早过期的键优先被淘汰。
  7. Volatile-lfu
    • 根据使用频率和剩余生存时间来决定淘汰顺序,使用频率低且剩余生存时间短的键优先被淘汰。
  8. Allkeys-lfu
    • 根据使用频率来决定淘汰顺序,使用频率低的键优先被淘汰。

11、Redis集群有哪些方案

Redis集群方案主要有三种:

  1. 主从同步:主节点负责写数据,从节点负责读数据,实现读写分离,提高并发能力。
  2. 哨兵模式:在主从复制的基础上,增加了一个或多个哨兵节点来监视主节点和从节点的状态。当主节点出现故障时,哨兵节点可以自动将一个从节点升级为新的主节点,从而保证系统的高可用性。
  3. 分片集群(Redis Cluster):将数据分散到多个节点中,每个节点都存储部分数据,实现数据的水平扩展。Redis Cluster使用哈希槽(Hash Slot)进行数据分片,并通过Gossip协议进行节点间的通信和故障检测。

12、什么是 Redis 主从同步

Redis主从同步是一种数据复制方式,用于实现读写分离和提高系统的可用性。在主从同步中,有一个主节点(master)和多个从节点(slave)。主节点负责处理客户端的写请求,并将数据变更同步到从节点。从节点则负责处理读请求,通过复制主节点的数据来保持数据的一致性。主从同步可以配置为全量同步或增量同步,具体取决于从节点是否已有主节点的数据副本以及数据变更的情况。

13、你们使用Redis是单点还是集群?哪种集群

这个问题需要针对具体的组织或项目来回答。一般来说,为了保证高可用性和数据的一致性,大多数生产环境都会使用Redis集群而不是单点部署。至于使用哪种集群方案,则取决于具体的需求和场景。例如,如果需要实现数据的水平扩展和高并发读写,可能会选择Redis Cluster;如果主要关注高可用性和故障自动转移,可能会选择哨兵模式。

14、Redis分片集群中数据是怎么存储和读取的

在Redis分片集群中,数据按照一定规则(如一致性哈希算法)分配到多个节点上进行存储。每个节点只负责部分数据的存储和处理,这样可以提高系统的吞吐量和可扩展性。当客户端发送写入请求时,Redis分片集群会根据键的哈希值确定数据应该存储在哪个节点上,并将写入请求发送到对应的节点。同样地,当客户端发送读取请求时,Redis分片集群也会根据键的哈希值确定数据所在的节点,并将读取请求发送到对应的节点。

15、redis集群脑裂

Redis集群脑裂是一个在分布式系统中可能发生的严重问题。在网络分区或其他故障的情况下,Redis集群的多个节点之间失去通信,导致它们各自形成独立的、都认为自己是主节点的分区。这时,每个分区都可以接受写请求,从而可能导致数据不一致和冲突。为了解决这个问题,可以采取一些措施,如使用Redis Cluster的原生支持、合理配置Sentinel参数、进行网络隔离与恢复、定期进行节点健康检查以及数据备份与恢复等。

16、怎么保证redis的高并发高可用

保证Redis的高并发和高可用性通常涉及以下几个方面:

  1. 集群部署:通过主从复制、哨兵模式或Redis Cluster等集群方案来实现数据的冗余和故障自动转移。
  2. 负载均衡:使用负载均衡器将客户端请求分发到多个Redis节点上,以平衡各节点的负载。
  3. 资源优化:合理配置Redis服务器的硬件资源(如CPU、内存、网络带宽等)以及Redis的配置参数(如最大连接数、内存限制等),以优化Redis的性能和吞吐量。
  4. 数据持久化:通过AOF(Append Only File)或RDB(Redis Database)等持久化机制来确保数据在Redis服务器故障时不会丢失。
  5. 监控和告警:实时监控Redis服务器的性能指标和状态信息,并在发现异常时及时告警和处理。

17. 你们用过Redis的事务吗?事务的命令有哪些?

是的,Redis支持事务。Redis中的事务是通过一组命令的集合实现的,这些命令将按顺序执行并原子地提交或回滚。Redis事务主要使用的命令包括:

  • MULTI:用于标记事务的开始。在执行MULTI命令后,所有后续的命令都将被认为是事务的一部分,放入事务队列中等待执行。
  • EXEC:用于执行之前标记的事务。Redis将按顺序执行事务中的所有命令,并以原子方式提交。
  • DISCARD:用于取消事务,清空事务队列,并释放与事务关联的任何资源。
  • WATCH:用于监视一个或多个键,以便在事务执行期间检测到键的变化。如果在EXEC执行之前被监视的键发生了变化,事务将被取消。

18. Redis是单线程的,但是为什么还那么快?

Redis虽然是单线程的,但其性能却非常高,这主要得益于以下几个方面的设计:

  1. 基于内存操作:Redis将数据存储在内存中,内存的读写速度远快于磁盘。因此,Redis的数据访问速度非常快。
  2. 非阻塞I/O模型:Redis使用了事件驱动的非阻塞I/O机制。它通过一个事件循环来处理来自客户端的请求,在等待数据I/O时并不会阻塞主线程,而是继续处理其他请求。这种非阻塞I/O模型允许Redis以高效的方式处理大量的并发连接,提供高吞吐量和低延迟的性能。
  3. 高效的数据结构和算法:Redis内置了多种高效的数据结构,如字符串、哈希表、列表、集合和有序集合等。这些数据结构经过优化,能够在单线程下提供高效的数据操作。同时,Redis还使用了一些高效的算法,如快速列表、跳跃表和布隆过滤器等,以提高查询和存储的效率。
  4. 优化系统调用和线程切换:Redis对系统调用进行了优化,减少了频繁的系统调用开销。由于Redis主要使用单线程模型,避免了多线程带来的线程切换开销,从而提高了整体性能。
  5. 并发控制和事务支持:虽然Redis是单线程的,但它通过使用乐观锁和CAS(Compare and Swap)操作来实现并发控制。这种并发控制机制使得多个客户端的请求可以并行执行,而不会相互干扰。同时,Redis还提供了简单的事务支持,允许将多个命令作为一个原子操作进行执行,保证了数据的一致性和完整性。
  6. 基于Reactor模式的网络事件处理器:Redis基于Reactor模式开发了自己的网络事件处理器------文件事件处理器。这个文件事件处理器使用I/O多路复用程序来同时监听多个socket,并根据socket目前执行的任务来为socket关联不同的事件处理器。这种设计使得Redis能够高效地处理大量的并发连接,提高了整体性能。
相关推荐
Distance失落心4 分钟前
java基于数组实现队列(四)
java·开发语言·数据结构·算法·面试·java-ee·intellij-idea
Luo_LA7 分钟前
【Java 面试 八股文】JVM 虚拟机篇
java·jvm·面试
Pandaconda28 分钟前
【Golang 面试题】每日 3 题(六十五)
开发语言·经验分享·笔记·后端·面试·golang·go
Good Note1 小时前
Golang的静态强类型、编译型、并发型
java·数据库·redis·后端·mysql·面试·golang
卑微的小鬼3 小时前
Go 语言结合 Redis 实现固定窗口、滑动窗口、令牌桶和漏桶限流算法的示例代码
开发语言·redis·golang
ylfhpy3 小时前
Python常见面试题的详解16
开发语言·python·面试
苍老流年6 小时前
Redis底层数据结构
数据结构·数据库·redis
三天不学习6 小时前
Redis面试宝典【刷题系列】
数据库·redis·面试
六个点6 小时前
DNS与获取页面白屏时间
前端·面试·dns
技术蔡蔡7 小时前
Android字节码处理-函数耗时统计揭秘
算法·面试