缓存策略、分布式锁与 Spring 集成

共 74 题
#

1. @CachePut/@CacheEvict 与一致性

A @CacheEvict 删除缓存并配合先更新 DB 的时序,比直接写缓存更不易产生脏数据 ✓ 正确答案
B 两者都无需考虑数据库时序
C @CacheEvict 会写入缓存值
D @CachePut 一定比 @CacheEvict 更安全
#

2. @Cacheable/@CacheEvict 与 Redis 缓存管理器

A RedisCacheManager 无法配置 TTL
B 注解不依赖 CacheManager
C 缓存键固定为 cacheNames,不含方法参数
D @Cacheable 命中缓存不执行方法,未命中则执行并写入;RedisCacheManager 决定序列化与 TTL ✓ 正确答案
#

3. Cache-Aside(旁路缓存)的工程实现

A 读未命中回填缓存,写路径先更新 DB 再删除缓存,避免并发脏数据 ✓ 正确答案
B 写路径先更新缓存再更新数据库
C 写路径无需删除缓存
D 回填不需要 TTL
#

4. GETSET/GETEX(Redis 6.2)的工程价值

A GETSET 只读不写
B GETEX 不能设置过期时间
C GETSET 与 GETEX 完全相同
D GETSET 原子地设置并返回旧值,GETEX 读取并设置过期时间,两者都避免多命令竞态 ✓ 正确答案
#

5. INCR/DECR 的原子计数应用

A INCR 在高并发下会丢失更新
B INCR 只能自减不能自增
C INCR 不保证原子性
D INCR 由 Redis 单线程保证原子,返回新值可用于判断阈值,配合 Lua 可实现秒杀扣减 ✓ 正确答案
#

6. JDK 25 虚拟线程在 Lettuce 长连接场景的栈复用与连接泄漏防范

A 虚拟线程可无限放量,无需任何超时或关闭
B 虚拟线程阻塞时挂起并复用载体线程,但长连接仍需超时、关闭与连接池限制来防泄漏 ✓ 正确答案
C 虚拟线程每条连接都需独立平台线程
D 连接无需关闭释放
#

7. Lua 脚本在分布式锁的应用(CAS 重入)

A Lua 把校验持有者与删除/计数原子化,实现 CAS 防误删与可重入 ✓ 正确答案
B Lua 脚本不能保证原子性
C 解锁无需校验持有者
D Lua 只能实现非可重入锁
#

8. Lua 脚本在原子操作的应用

A Lua 在 Redis 端原子执行,可封装判断-扣减等复合逻辑,避免客户端多命令竞态 ✓ 正确答案
B Lua 不能包含条件判断
C Lua 脚本执行期间可被其他命令穿插
D Lua 与多条独立命令的原子性相同
#

9. Redis 7 的 FUNCTION 与分布式锁

A FUNCTION 与 EVAL 一样需每次维护脚本哈希
B FUNCTION 不支持原子性
C FUNCTION 把锁逻辑封装为可版本管理的函数库,集群一致加载,FCALL 原子执行 ✓ 正确答案
D FUNCTION 只能一次性执行不能复用
#

10. Redis 7 的 只读函数调用(FCALL_RO) 性能

A 只读函数调用(FCALL_RO) 通过只读变体与分片并行执行,提升集群跨槽只读操作的性能 ✓ 正确答案
B 只读函数调用(FCALL_RO) 与普通 Functions 完全等价
C 只读函数调用(FCALL_RO) 不支持分片
D 只读函数调用(FCALL_RO) 不保证原子性
#

11. Redis 7 的 latency-tracking 与 INFO LATENCY

A 只能查看整体延迟,无法细分到命令
B 延迟监控与调优无关
C LATENCY 命令不能用于运维
D latency-tracking 记录命令级延迟直方图,配合 INFO LATENCYSTATS/commandstats 可定位慢命令 ✓ 正确答案
#

12. Redis 7.x 的 Client-Side Caching(客户端缓存,TRACKING)与 RESP3 协议

A 客户端缓存无法感知 Redis 数据变更
B 客户端缓存只在 RESP2 下可用
C TRACKING 推送后无需处理
D CLIENT TRACKING 通过 RESP3 的 Push 推送失效通知,客户端据此失效本地缓存,保持一致性 ✓ 正确答案
#

13. Redis 7.x 的 RedLock(红锁)分布式锁在 Spring Boot 3.5+ 的 Redisson 集成

A RedLock 只要一个节点成功即可
B RedLock 与普通单节点锁完全一样
C RedLock 要求多数派节点加锁成功,Redisson 用 RedissonRedLock 组合多个 RLock 实现 ✓ 正确答案
D RedLock 不依赖时钟,无任何争议
#

14. Redis Cluster 的 Spring 集成

A Spring 无法使用 Redis Cluster
B 通过 RedisClusterConfiguration 配置节点,Lettuce 负责槽路由与拓扑刷新,多 key 操作需同槽(hash tag) ✓ 正确答案
C Cluster 下多 key 操作无任何限制
D 配置后无需处理故障转移
#

15. Redis Pub/Sub 在 Spring 的 MessageListenerAdapter

A Pub/Sub 消息会持久化保存
B MessageListenerAdapter 把消息适配到业务方法,RedisMessageListenerContainer 管理订阅消费,但 Pub/Sub 不持久化 ✓ 正确答案
C Pub/Sub 适合可靠消息队列
D Pub/Sub 订阅者离线消息会保留
#

16. Redis Sentinel 的 Spring 集成

A Sentinel 不参与故障转移
B Sentinel 集成后客户端永远连固定节点
C 配置 RedisSentinelConfiguration(master + 哨兵节点),客户端通过 Sentinel 发现 master 并支持故障转移 ✓ 正确答案
D 读写分离到从库无任何一致性风险
#

17. Redisson 分布式锁的看门狗(Watchdog)续期机制

A 看门狗每 10 秒校验持有者并重置 30 秒 TTL,持有者崩溃则续期停止、锁自动过期释放 ✓ 正确答案
B 看门狗续期不需要校验持有者
C 看门狗会导致死锁
D 看门狗把锁续期为永不超时
#

18. 分布式锁与 Redisson 同步器(Semaphore/CountDownLatch)

A RSemaphore 是分布式限流(最多 N 并发),RCountDownLatch 是跨实例聚合等待,与锁的互斥语义不同 ✓ 正确答案
B RSemaphore 与分布式锁完全相同
C 同步器无法跨 JVM 使用
D RCountDownLatch 用于限流
#

19. Redis Stream 在 Spring Data Redis(2.6+)

A 只能手动调用 XREAD 不能注解消费
B 消费无需 ack
C Stream 不支持消费者组
D StreamMessageListenerContainer 封装阻塞消费与消费者组,@StreamListener 声明式消费,支持手动/自动 ack ✓ 正确答案
#

20. Redis 与本地缓存(Caffeine/Guava Cache)

A 本地缓存天然与 Redis 一致,无需失效处理
B Caffeine 作 L1 提供低延迟,Redis 作 L2 共享,但多实例本地缓存需失效/广播维持一致 ✓ 正确答案
C 本地缓存命中率低无意义
D 多级缓存只能用于强一致场景
#

21. Redis 关键性能参数(maxmemory/maxmemory-policy)

A allkeys-lru 对所有键按 LRU 淘汰,缓存场景常用,淘汰可能影响性能需监控 evicted_keys ✓ 正确答案
B volatile-lru 淘汰所有键而不限于有 TTL 的键
C 淘汰不影响主线程延迟
D noeviction 会淘汰最久未用的键
#

22. Redis 慢查询日志(slowlog-log-slower-than)

A 慢查询与命令优化无关
B slowlog 记录网络与排队时间
C slowlog 无长度限制
D slowlog-log-slower-than 设阈值,超过的执行命令进日志,用 SLOWLOG GET 查看服务端慢命令 ✓ 正确答案
#

23. Redis 的 BZPOPMIN/BLMPOP(阻塞操作)

A 阻塞命令立即返回空
B 阻塞命令不会占用连接
C 无元素时命令阻塞至超时返回,实现任务/优先级队列,但会占用连接需设好超时 ✓ 正确答案
D 只能用于 List 不能用于 ZSet
#

24. Redis 的 Lua 脚本与 Spring 的 RedisScript

A RedisScript 需要手动 EVALSHA 维护哈希
B DefaultRedisScript 封装脚本与返回类型,execute 传入 KEYS/ARGV,Spring 自动管理脚本缓存 ✓ 正确答案
C RedisScript 不支持返回类型
D 脚本只能传 KEYS 不能传 ARGV
#

25. Redis 的 OBJECT 子命令

A OBJECT ENCODING 返回键的值
B OBJECT ENCODING 返回键的内部编码与内存布局 ✓ 正确答案
C OBJECT IDLETIME 返回键的过期时间
D OBJECT 命令会修改数据
#

26. Redis 的 Pipeline 与 Spring Data Redis

A executePipelined 批量发送命令减少网络往返提升吞吐,但不保证原子性 ✓ 正确答案
B executePipelined 保证原子性
C pipeline 会逐条往返
D pipeline 无内存开销
#

27. Redis 的 Pub/Sub 在缓存失效的应用

A 实例离线时也能收到失效消息
B Pub/Sub 广播可完全替代 TTL
C 更新后通过 Pub/Sub 广播失效通知,各实例删除本地缓存,但消息不持久,离线会漏收需 TTL 兜底 ✓ 正确答案
D 失效广播不能跨实例
#

28. Redis 的 hotkey 检测(redis-cli --hotkeys)

A --hotkeys 不依赖淘汰策略
B --hotkeys 不会阻塞主线程
C --hotkeys 只能识别冷键
D --hotkeys 依赖 LFU 策略的 OBJECT FREQ 统计访问频率识别热键,但全量扫描成本高需低峰执行 ✓ 正确答案
#

29. Redis 的 io-threads-do-reads 配置

A 它让命令逻辑多线程执行
B 它让网络 IO 的读写并行化到多线程,命令执行仍单线程,缓解网络瓶颈 ✓ 正确答案
C 它对 CPU 密集逻辑收益最大
D 开启后无需再配置 io-threads
#

30. Redis 的 jemalloc 与内存分配器

A Redis 默认使用 glibc malloc
B Redis 默认用 jemalloc,其 size class 与线程缓存减少碎片、提升小对象分配性能 ✓ 正确答案
C jemalloc 无法替换
D 内存分配器不影响碎片率
#

31. Redis 的 latency 子命令的工程价值

A LATENCY 只能看客户端延迟
B LATENCY 与调优无关
C LATENCY LATEST/HISTORY/DOCTOR 定位服务端延迟事件(fork/fsync/阻塞),配合阈值监控告警 ✓ 正确答案
D LATENCY 无法重置
#

32. Redis 的事务(MULTI/EXEC)与 Lua 的取舍

A MULTI/EXEC 原子执行预排命令但无回滚,Lua 可含条件逻辑也原子,都无自动回滚,复杂逻辑优先 Lua ✓ 正确答案
B Lua 出错会自动回滚
C MULTI/EXEC 支持条件逻辑
D MULTI/EXEC 比 Lua 更灵活
#

33. Redis 的内存碎片率(mem_fragmentation_ratio)

A 碎片率 <1 表示内存充足
B 碎片率 = RSS/逻辑内存,持续 >1.5 说明碎片严重,可用 active-defrag 整理 ✓ 正确答案
C 碎片无法治理
D 碎片率恒等于 1
#

34. RedisBloom/RedisSearch 等模块的性能影响

A 模块把复杂结构下沉到服务端提升效率,但复杂计算在单线程执行可能阻塞主线程并占内存 ✓ 正确答案
B 模块命令不占用主线程
C 模块无内存开销
D 模块命令一定很快
#

35. RedisTemplate 的事务支持(SessionCallback)

A SessionCallback 绑定同一连接执行 multi/exec,保证事务命令原子提交 ✓ 正确答案
B SessionCallback 让多条命令在不同连接执行
C Redis 事务支持回滚
D SessionCallback 与事务无关
#

36. RedisTemplate.opsForHash() 的批量 HSET

A putAll 只能写一个字段
B putAll 每次只发一条命令逐字段
C putAll 一次 HSET 写入多个字段,减少往返,适合批量更新 Hash ✓ 正确答案
D putAll 会覆盖数据库
#

37. RedisTemplate.opsForValue() 的常用 API

A opsForValue() 封装 String 操作,含 setIfAbsent(分布式锁)与 increment(原子计数)等 ✓ 正确答案
B setIfAbsent 不保证原子
C increment 不保证原子
D 只能 set/get 不能设过期
#

38. RedisTemplate/StringRedisTemplate 的序列化器

A StringRedisTemplate 用 JDK 序列化
B RedisTemplate 默认用 JSON 序列化
C RedisTemplate 默认 JDK 序列化(二进制不可读),生产常用 key 用 String、value 用 Jackson JSON ✓ 正确答案
D key 与 value 序列化器必须相同
#

39. Redisson 的 LockPubSub 与解锁通知

A 锁等待者持续忙轮询占用大量请求
B LockPubSub 与锁实现无关
C 解锁不通知等待者
D 加锁失败通过 LockPubSub 订阅解锁事件,解锁 publish 唤醒等待者,避免忙轮询 ✓ 正确答案
#

40. Redisson 的 RLock/RFairLock/RReadWriteLock

A RFairLock 是抢占式非公平
B 读锁与写锁互斥关系相同
C 三者完全等价
D RLock 非公平可重入,RFairLock 按请求顺序公平,RReadWriteLock 读锁共享写锁互斥 ✓ 正确答案
#

41. RedissonClient 的 tryLock(timeout, unit) 与阻塞

A tryLock 会无限阻塞直到成功
B tryLock 传租期时仍开启看门狗
C tryLock(waitTime) 最多等待 waitTime,超时返回 false,配合租期控制锁生命周期 ✓ 正确答案
D tryLock 无参也会长时间等待
#

42. Redlock(Redis 分布式锁算法)的争议与边界

A Redlock 与单节点锁完全等价
B Redlock 在任何情况下都能保证互斥
C Redlock 不依赖时钟
D Redlock 依赖时钟与网络分区,无法保证强互斥,适用于可容忍极小概率并发的场景 ✓ 正确答案
#

43. Spring 7 中 @TransactionalEventListener 与 Redis Pub/Sub 的事件驱动架构

A 监听器在事务提交前触发
B 事务内即可安全发布事件
C AFTER_COMMIT 让事件在事务提交后发出,配合 Pub/Sub 跨实例解耦,但 Pub/Sub 不持久需 Outbox 兜底 ✓ 正确答案
D Pub/Sub 广播可靠持久
#

44. Spring Data Redis 的 RedisConnectionFactory 配置

A 默认使用 JedisConnectionFactory
B 连接工厂无需配置序列化
C 默认 LettuceConnectionFactory,需配置地址、超时、序列化与 ClientResources,连接池可选 ✓ 正确答案
D 超时配置不影响稳定性
#

45. redis-cli --bigkeys 的内存分析

A --bigkeys 精确统计所有键内存
B --bigkeys 不会执行任何命令
C --bigkeys 只分析 String
D --bigkeys 基于 SCAN 抽样扫描各类数据结构中的最大 key,用于发现大 key,建议低峰执行 ✓ 正确答案
#

46. redis-cli --latency-history 的实时延迟采样

A --latency 工具无法测延迟
B --latency-history 只测一次延迟
C --latency-history 分时间段输出延迟采样,用于观察延迟随时间的波动与尖刺 ✓ 正确答案
D 延迟采样只反映服务端 CPU
#

47. redis-cli --memkeys 的内存细分

A --memkeys 用 MEMORY USAGE 逐个 key 精确统计内存分布,帮助内存治理与容量规划,但开销较大 ✓ 正确答案
B --memkeys 与 --bigkeys 完全一样
C --memkeys 不执行任何命令
D --memkeys 只统计一类 key
#

48. volatile-lru/allkeys-lfu 的取舍

A volatile-lru 只淘汰有 TTL 的键保护长期数据,allkeys-lfu 全键按频率淘汰,LFU 更抗偶发访问 ✓ 正确答案
B allkeys-lfu 只淘汰有 TTL 的键
C volatile-lru 会淘汰所有键
D 淘汰策略与数据保护无关
#

49. 分布式锁的 GC 停顿与 Redis 假死问题

A GC 停顿不会影响锁
B 锁值唯一标识无意义
C 只要续期就能绝对避免并发
D 长 GC 停顿可使锁过期导致并发,靠唯一标识+续期+服务幂等组合缓解,无法完全消除 ✓ 正确答案
#

50. 分布式锁的公平性(FairLock)与读写锁(R/W Lock)

A FairLock 是抢占式
B RFairLock 按请求顺序公平排队避免饿死,RReadWriteLock 读锁共享写锁互斥且写优先 ✓ 正确答案
C 读写锁读锁互斥
D 公平锁开销与普通锁相同
#

51. 分布式锁的可重入性(Reentrant Lock)

A 可重入锁任意线程都能重入
B 通过持有者标识+计数,同一线程重复加锁计数+1、解锁计数-1 归零才释放 ✓ 正确答案
C 可重入锁不支持嵌套
D 可重入无需校验持有者
#

52. 分布式锁的超时与释放语义

A 解锁无需校验持有者
B 租期防止崩溃死锁,解锁校验持有者防止误删他人锁,续期覆盖业务时长 ✓ 正确答案
C 超时越长越安全
D 锁一旦加锁永不释放
#

53. 基于 Binlog + Canal 的缓存一致性

A Canal 直接修改数据库
B Canal 订阅 Binlog 解析变更事件,异步删除/更新缓存,与业务解耦且以数据库日志为准 ✓ 正确答案
C Binlog 事件无延迟
D 该方案侵入业务代码
#

54. 热点 key 如何被发现(客户端统计/代理层探测),拆分(key 分片)与本地缓存兜底各如何缓解单分片压力

A key 分片会加重单节点压力
B 热点 key 无法被发现
C 通过客户端统计/代理探测发现,key 分片分散单 key 压力,本地缓存兜底减少请求量 ✓ 正确答案
D 本地缓存无法缓解热点
#

55. 热点 key 突发流量下,多级缓存(Caffeine + Redis)与请求合并(singleflight)如何避免缓存击穿

A 击穿只能靠增大 TTL 解决
B singleflight 会放大并发
C 多级缓存本地兜底 + singleflight 合并同 key 并发查询,避免热点 key 过期瞬间打穿数据库 ✓ 正确答案
D 多级缓存不减少 DB 压力
#

56. 缓存与数据库的最终一致性(先更新 DB,再失效缓存)

A 先更新缓存再更新数据库最安全
B 先更新 DB 再删缓存以数据库为准,删除失败用补偿/延迟双删/TTL 兜底收敛 ✓ 正确答案
C 缓存永远与数据库同一致
D 删除缓存无需补偿
#

57. 缓存容量规划与 maxmemory-policy 选型

A 容量规划与 TTL 无关
B noeviction 会淘汰键
C 需评估数据量/TTL/QPS 与内存预算,纯缓存用 allkeys-lru/lfu,留余量并监控 evicted_keys 扩容 ✓ 正确答案
D 淘汰策略选型不影响可用性
#

58. 缓存层整体不可用时如何降级与熔断,直连数据库的保护性预案(限流、降级开关、静态兜底)应如何设计

A 降级只影响缓存不影响 DB
B 缓存故障时可直接放开直连 DB 无限制
C 用熔断快速失败 + 限流保护 DB + 降级开关/静态兜底,分层有损降级避免雪崩 ✓ 正确答案
D 静态兜底会加重 DB 压力
#

59. 缓存穿透(Cache Penetration)的布隆过滤器(Bloom Filter)

A 布隆过滤器会漏掉真实存在的 key
B 布隆过滤器不能减少 DB 压力
C 布隆过滤器把不存在的 key 直接挡在 DB 前,用 O(k) 查询与可控误判率,误判只多查 DB 不漏真实数据 ✓ 正确答案
D 布隆过滤器误判率可以无限降低且无代价
#

60. 缓存穿透(Cache Penetration)的成因与解决方案

A 穿透只发生在缓存存在时
B 空值缓存无需设 TTL
C 布隆过滤器能拦截合法 key
D 查询不存在的 key 反复打 DB 即穿透,用空值缓存短 TTL + 布隆过滤器 + 参数校验多层防护 ✓ 正确答案
#

61. 缓存雪崩(Cache Avalanche)的成因与防护

A 大量 key 同时过期或缓存宕机会导致雪崩,用过期随机化、多级缓存、高可用与限流熔断防护 ✓ 正确答案
B 缓存宕机无法防护
C 随机化会加重雪崩
D 雪崩与过期时间无关
#

62. 缓存雪崩(Cache Avalanche)的过期时间随机化与多级缓存(Redis + Caffeine)

A TTL 随机化错峰失效 + Caffeine 本地兜底,避免同时过期或宕机时大量请求打 DB ✓ 正确答案
B 随机化让所有 key 同时过期
C 多级缓存无法兜底宕机
D 随机化与多级缓存无关
#

63. 缓存预热(Warm-up)与冷启动策略

A 预热无需挑选热点数据
B 冷启动命中率天然很高
C 启动/发布前把热点数据预载入缓存,配合限流与 singleflight 兜底冷启动,避免冷启动打库 ✓ 正确答案
D 预热只在运行时随机发生
#

64. @Cacheable 注解的 Spring 集成

A @Cacheable 通过 AOP 先查缓存命中返回,未命中执行并写入,需 @EnableCaching 与 CacheManager,方法内部自调用不生效 ✓ 正确答案
B 无需开启 @EnableCaching
C @Cacheable 命中缓存也执行方法
D 自调用也生效
#

65. CLIENT LIST 与客户端连接分析

A CLIENT LIST 只能查看数量
B 无法断开异常连接
C 连接分析无运维价值
D CLIENT LIST 展示连接地址/空闲/阻塞/缓冲等,用于分析连接数、僵尸连接,配合 CLIENT KILL 治理 ✓ 正确答案
#

66. CONFIG GET/CONFIG SET 的动态调参

A CONFIG SET 必须重启才能生效
B CONFIG SET 动态修改运行期参数,CONFIG REWRITE 持久化到配置文件,用于在线调优 ✓ 正确答案
C 配置修改后永久生效无需重写
D CONFIG GET 只能精确匹配
#

67. INFO 命令的工程价值(memory/commandstats/stats)

A INFO 只能看版本
B INFO 的 memory/stats/commandstats 分别反映内存、运行统计与命令耗时,用于监控、告警与慢命令定位 ✓ 正确答案
C INFO 无法提供命令统计
D INFO 与监控无关
#

68. Multi-Level Cache(L1+L2)的设计

A L1 本地缓存低延迟,L2 Redis 共享,读逐级查找回填,难点是 L1 多实例一致性维护 ✓ 正确答案
B 多级缓存无需失效处理
C L1 是 Redis、L2 是本地缓存
D L1 容量无限
#

69. PIPELINE 与 MGET/MSET 的批量优化

A MGET 每次只读一个 key
B 同类型批量读用 MGET 一次往返,混合操作用 PIPELINE 打包,两者都减少网络往返 ✓ 正确答案
C MGET 在 cluster 下无同槽限制
D PIPELINE 比 MGET 一定更快
#

70. Read-Through/Write-Through/Write-Behind 的差异

A Write-Through 只写缓存不写数据库
B Read-Through 读透自动回填,Write-Through 同步双写保证一致,Write-Behind 异步刷盘优化写但可能丢数据 ✓ 正确答案
C Write-Behind 写后立即同步落库
D 三者一致性完全相同
#

71. SCAN/KEYS 的安全差异

A KEYS 在大库上安全
B SCAN 与 KEYS 完全等价
C SCAN 会阻塞主线程
D KEYS 全量扫描会阻塞主线程,SCAN 用游标增量遍历不阻塞,生产批量操作应用 SCAN ✓ 正确答案
#

72. active-defrag 的自动碎片整理

A active-defrag 需要重启服务
B active-defrag 不消耗 CPU
C 碎片整理与碎片率无关
D active-defrag 在后台在线整理碎片,用阈值与 CPU 占比参数控制,避免重启但占 CPU ✓ 正确答案
#

73. redis-benchmark 的性能压测

A redis-benchmark 只能测连接数
B 压测结果与机器无关
C 用 -c/-n/-d/-t/-P 控制并发、请求数、数据大小、命令与管道,输出吞吐与延迟用于性能评估 ✓ 正确答案
D 压测无需指定命令
#

74. 延迟双删(Delay Double Delete)模式

A 延迟双删保证强一致
B 延迟双删只删一次缓存
C 更新 DB 后删缓存、延迟再删一次,清理"回填旧值"竞态产生的脏数据,实现最终一致 ✓ 正确答案
D 延迟时间越短越好