当前位置: 首页 > news >正文

面试被问 Redis?这 3 个问题 90% 的人都答不对

🔥 问题一:Redis 单线程为什么还能支撑 10w+ QPS?

面试官潜台词:考察你对 Redis 高性能原理的理解深度。

90% 的人答错:

“因为 Redis 是纯内存操作,所以快。”

❌ 太浅了!内存操作只是基础,单线程设计才是精髓。

正确答案:

// Redis 的核心设计:单线程 + IO多路复用 // 类比 Java NIO 的 Selector 机制 // 传统阻塞IO(低效) while (true) { Socket socket = serverSocket.accept(); // 阻塞! handle(socket); // 处理完才能接受下一个 } // Redis 的 IO多路复用(高效) while (!stop) { // 1. 批量获取就绪的 socket(非阻塞) readySockets = epoll_wait(epfd, events, maxevents, timeout); // 2. 逐个处理(纯内存操作,极快) for (i = 0; i < readySockets; i++) { handle(events[i].data.fd); } }

核心原因 3 点:

设计作用
纯内存操作纳秒级响应,比磁盘快 10 万倍
单线程模型避免上下文切换、锁竞争,代码简单高效
IO多路复用一个线程管理数万连接,epoll 性能炸裂
💡一句话总结:Redis 把”单线程”做成了优势——没有锁、没有切换、没有竞争,把内存性能压榨到极致。

🔥 问题二:缓存穿透、击穿、雪崩,到底啥区别?

面试官潜台词:考察你对缓存架构风险的理解和解决方案。

90% 的人混淆:

“都是缓存失效了,然后请求打到数据库…”

❌ 概念不清!三者场景和解决方案完全不同。

一张图讲清楚:

缓存穿透 缓存击穿 缓存雪崩 ↓ ↓ ↓ 查询不存在的数据 热点key过期 大量key同时过期 ↓ ↓ ↓ 缓存无 -> DB无 缓存无 -> DB有 缓存集体失效 ↓ ↓ ↓ 每次都查DB 瞬间高并发查DB DB压力暴增

代码级解决方案:

1️⃣ 缓存穿透 — 布隆过滤器

@Service public class CacheService { @Autowired private RedissonClient redisson; @Autowired private StringRedisTemplate redisTemplate; // 布隆过滤器:快速判断"一定不存在"或"可能存在" public String getData(String key) { RBloomFilter<String> bloomFilter = redisson.getBloomFilter("user:bloom"); // 1. 布隆过滤器拦截 if (!bloomFilter.contains(key)) { return null; // 一定不存在,直接返回 } // 2. 查缓存 String value = redisTemplate.opsForValue().get(key); if (value != null) { return value; } // 3. 查数据库(布隆过滤器说有,但实际可能没有) return queryDB(key); } }

2️⃣ 缓存击穿 — 互斥锁 + 逻辑过期

public String getHotData(String key) { String json = redisTemplate.opsForValue().get(key); // 1. 判断是否逻辑过期 RedisData redisData = JSON.parseObject(json, RedisData.class); if (redisData.getExpireTime().isAfter(LocalDateTime.now())) { return redisData.getData(); // 未过期,直接返回 } // 2. 已过期,尝试获取锁重建缓存 String lockKey = "lock:" + key; boolean isLock = tryLock(lockKey, 10); if (isLock) { // 双重检查,防止重复重建 json = redisTemplate.opsForValue().get(key); redisData = JSON.parseObject(json, RedisData.class); if (redisData.getExpireTime().isBefore(LocalDateTime.now())) { // 开启独立线程重建缓存 CACHE_REBUILD_EXECUTOR.submit(() -> { try { String newData = queryDB(key); saveRedisWithLogicalExpire(key, newData, 30L); } finally { unlock(lockKey); } }); } } // 3. 返回过期数据(保证可用性) return redisData.getData(); }

3️⃣ 缓存雪崩 — 多级缓存 + 随机过期

@Configuration public class CacheConfig { @Bean public CacheManager cacheManager() { // Caffeine 本地缓存 + Redis 分布式缓存 CaffeineCacheManager localCache = new CaffeineCacheManager(); localCache.setCaffeine( Caffeine.newBuilder() .maximumSize(1000) .expireAfterWrite(10, TimeUnit.MINUTES) ); return new CompositeCacheManager(localCache, redisCacheManager()); } } // 设置随机过期时间,避免同时失效 public void setWithRandomExpire(String key, String value, long baseExpire) { // 基础过期时间 + 随机 0-300 秒 long expire = baseExpire + RandomUtil.randomLong(0, 300); redisTemplate.opsForValue().set(key, value, expire, TimeUnit.SECONDS); }
💡记忆口诀:
  • 穿透查不到(布隆挡)
  • 击穿过期了(锁来保)
  • 雪崩集体挂(多级+随机)

🔥 问题三:分布式锁用 setnx 就够了吗?

面试官潜台词:考察你对分布式锁完整实现的理解。

90% 的人踩坑:

// 错误示范!生产环境别这么写 public void wrongLock(String key) { Boolean success = redisTemplate.opsForValue() .setIfAbsent(key, "1"); // setnx if (success) { // 执行业务逻辑... // 如果这里抛异常或宕机,锁永远释放不了! redisTemplate.delete(key); } }

❌ 3 个致命问题:

  1. 没设置过期时间 → 死锁
  2. 业务没执行完就过期 → 误删别人的锁
  3. 不是原子操作 → 竞态条件

正确姿势:Redisson 实现

@Service public class OrderService { @Autowired private RedissonClient redisson; public void createOrder(Long userId) { // 1. 获取锁(可重入、自动续期) RLock lock = redisson.getLock("order:user:" + userId); try { // 等待10秒,锁30秒自动过期,看门狗自动续期 boolean isLock = lock.tryLock(10, 30, TimeUnit.SECONDS); if (!isLock) { throw new RuntimeException("获取锁失败,请稍后重试"); } // 2. 执行业务(锁内操作要尽可能快!) doCreateOrder(userId); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw new RuntimeException("获取锁被中断"); } finally { // 3. 释放锁(判断是不是自己加的锁) if (lock.isHeldByCurrentThread()) { lock.unlock(); } } } }

Redisson 看门狗原理:

业务线程 │ ├── 获取锁成功 ──┐ │ │ │ ▼ │ 启动看门狗(Watch Dog) │ 每隔 10 秒检查:锁还在吗? │ │ │ ├── 还在 → 续期到 30 秒 │ └── 不在了 → 停止看门狗 │ ├── 业务执行中... ──┐ │ │ └── 业务完成 ───────┘ │ ▼ 释放锁 + 停止看门狗
💡核心要点:
  • 原子性:加锁必须带过期时间(Lua脚本保证)
  • 可重入:同一线程可以多次获取锁
  • 自动续期:看门狗防止业务未完成锁过期
  • 谁加谁删:释放锁前判断持有者

📝 面试总结

问题核心考点一句话答案
单线程快?IO模型、内存操作单线程+IO多路复用,无锁无切换
三大问题?缓存架构风险穿透布隆挡、击穿孔锁保、雪崩多级+随机
分布式锁?锁的完整性setnx+过期+看门狗+Lua原子性
http://www.jsqmd.com/news/509211/

相关文章:

  • OpenCore Auxiliary Tools:黑苹果配置的终极图形化解决方案
  • OpenESS嵌入式音频框架:轻量实时音频服务设计与实现
  • Java最全面试题及答案整理,共1200多道常见面试题,包含各个技术栈!
  • 2026宜兴沉淀池填料厂商五强解析:专业选型指南与深度竞争洞察 - 2026年企业推荐榜
  • Pixel Dimension Fissioner中小企业应用:替代高价文案工具的开源像素解决方案
  • Qwen-Image+RTX4090D效果实测:Qwen-VL对短视频关键帧图像的时序逻辑理解能力
  • AI大模型岗位薪资揭秘:年薪百万!10大AI高薪职位深度解析,清华北大毕业生的就业“黄金赛道”与高薪秘诀!
  • SAM 3图像分割真实案例:电商商品抠图、照片背景替换实战
  • ESP32内存不够用?PlatformIO分区表修改实战(VScode环境)
  • 2026年普陀区半包装修服务深度测评:五家实力团队横向解析与选型指南 - 2026年企业推荐榜
  • 小白也能玩转mPLUG:本地部署视觉问答,轻松看懂图片内容
  • 量化交易系列(十):AI Agent + 量化实战——从论文到真金白银
  • TreeATE vs 传统测试工具:开源自动化测试平台在工业物联网中的优势解析
  • REX-UniNLU与Unity集成:游戏对话系统智能化
  • PP-DocLayoutV3模型原理浅析:Transformer在文档图像理解中的应用
  • UltiBlox-SensorAnalog:嵌入式模拟传感器校准与滤波库
  • DASD-4B-Thinking效果展示:Chainlit中连续追问‘能否更简洁?’‘换种思路?’的自适应优化
  • 通信家电薄膜开关触点选型优质产品推荐指南:滑动开关/滑块开关/滑移开关/薄膜按键/薄膜键盘/薄膜面板/设定开关/选择指南 - 优质品牌商家
  • Phi-4-reasoning-vision-15B在政务办公中的应用:红头文件OCR+政策要点摘要
  • lingbot-depth-pretrain-vitl-14从零开始:PyTorch 2.6+cu124环境配置与模型加载避坑指南
  • 2026年企业形象墙设计服务商综合实力评估与选型指南 - 2026年企业推荐榜
  • FreeRTOS任务管理机制深度解析:状态机、调度与生命周期
  • nomic-embed-text-v2-moe参数详解:MoE中Gating Network训练策略与温度控制
  • Palworld存档修复工具:3步解决跨平台迁移与GUID不匹配问题
  • CoPaw长文本处理极限测试:万字技术文档摘要与QA
  • Anything V5图像生成服务常见问题解决:端口占用、内存不足怎么办?
  • 安徽包装机市场新观察:2026年智能化浪潮下,如何甄选优质供应商? - 2026年企业推荐榜
  • 2026年名牌箱包回收服务商五强解析:谁是你的最佳选择? - 2026年企业推荐榜
  • OpenClaw学习助手:Qwen3-32B自动生成复习笔记与练习题
  • LC_neoPixel库:嵌入式NeoPixel高效驱动与色彩对象化方案