什么是缓存

一、前言:为什么你的系统"慢如蜗牛"?

你是否遇到过这些问题?

  • 用户点击一个按钮,页面转圈 5 秒才加载出来
  • 数据库 CPU 突然飙升到 100%,服务几乎瘫痪
  • 明明数据没变,却每次都要重新查数据库

根本原因缺少缓存机制

在现代软件架构中,缓存是提升系统性能、降低数据库压力、改善用户体验的核心手段之一。本文将带你从零理解缓存的本质,并掌握其在实际项目中的应用。


二、什么是缓存?------ 用生活例子秒懂

缓存(Cache) :是一种临时存储机制 ,用于保存高频访问但不易频繁变化的数据,以便下次快速获取,避免重复计算或远程调用。

🌰 生活类比:

场景 缓存思想
你家厨房的调料架 常用的盐、酱油放在手边(缓存),不用每次都去超市(数据库)买
浏览器记住密码 下次登录自动填充,不用翻笔记本(原始存储)
快递柜 快递先存柜子(缓存),你随时去取,不用等快递员上门

核心目的用空间换时间


三、缓存的工作原理

复制代码
用户请求 → [缓存] → 有?→ 直接返回(命中)
                ↓ 否?
             [数据库/计算] → 返回结果 + 写入缓存 → 返回给用户
  • 命中(Hit):数据在缓存中找到,速度快
  • 未命中(Miss):缓存无数据,需回源(查 DB/计算),速度慢

📊 缓存命中率 = 命中次数 / 总请求次数

优秀的系统缓存命中率通常 > 95%


四、常见的缓存类型

类型 存储位置 特点 典型工具
CPU 缓存 处理器内部 速度极快(纳秒级) L1/L2/L3 Cache
本地缓存 应用内存 快(微秒级),单机有效 Caffeine、Guava Cache
分布式缓存 独立服务器 可共享,支持集群 Redis、Memcached
浏览器缓存 用户设备 减少网络请求 localStorage、HTTP Cache-Control
CDN 缓存 边缘节点 加速静态资源 阿里云 CDN、Cloudflare

📌 Web 开发中最常用本地缓存 + Redis


五、为什么需要缓存?三大核心价值

1. 提升响应速度

  • 读 Redis:0.1~1ms
  • 读 MySQL:5~50ms(甚至更高)
  • 提速 10~100 倍!

2. 降低数据库压力

  • 1000 次请求 → 若 95% 命中缓存 → 数据库只需处理 50 次
  • 避免数据库成为瓶颈

3. 提高系统可用性

  • 即使数据库短暂故障,缓存仍可提供部分数据(降级)

六、缓存的经典应用场景

场景 缓存内容 过期策略
用户信息 user:id → {name, phone} 修改时主动删除
商品详情 product:1001 → {...} 定时更新 or 修改触发
配置信息 app:config → {...} 长期有效,重启加载
热门排行榜 rank:top10 → [id1, id2...] 定时任务刷新
会话状态 session:abc123 → user_id TTL 自动过期

七、缓存的三大经典问题(面试必问!)

❗ 1. 缓存穿透(Cache Penetration)

  • 现象 :大量请求查询不存在的数据(如 id=-1),绕过缓存直击数据库
  • 危害:数据库被压垮
  • 解决方案
    • 布隆过滤器(Bloom Filter):快速判断 key 是否可能存在
    • 缓存空值:对 null 结果也缓存 1~2 分钟
java 复制代码
// 伪代码
Object data = cache.get(key);
if (data == null) {
    data = db.query(key);
    if (data == null) {
        cache.set(key, EMPTY_VALUE, 60); // 缓存空值
    } else {
        cache.set(key, data, 3600);
    }
}

❗ 2. 缓存击穿(Cache Breakdown)

  • 现象 :某个热点 key 过期瞬间,大量并发请求同时打到数据库
  • 危害:数据库瞬时压力激增
  • 解决方案
    • 互斥锁(Mutex):只让一个线程查 DB,其他等待
    • 逻辑过期:不设 TTL,后台异步更新
java 复制代码
// 互斥锁示例(Redis + SETNX)
if (cache.get(key) == null) {
    if (redis.setnx("lock:" + key, "1", 10)) {
        try {
            data = db.query(key);
            cache.set(key, data, 3600);
        } finally {
            redis.del("lock:" + key);
        }
    } else {
        Thread.sleep(50); // 短暂等待后重试
        return getFromCache(key);
    }
}

❗ 3. 缓存雪崩(Cache Avalanche)

  • 现象大量 key 同时过期,或缓存服务宕机,导致所有请求涌向数据库
  • 危害:系统整体崩溃
  • 解决方案
    • 过期时间加随机值TTL = 基础时间 + random(0~300秒)
    • 高可用部署:Redis 哨兵 / 集群
    • 熔断降级:Hystrix / Sentinel

八、如何选择缓存策略?

策略 说明 适用场景
Cache-Aside(旁路缓存) 先读缓存,miss 则查 DB 并回填 ✅ 最常用(如 Spring Cache)
Read/Write Through 缓存层代理读写,应用无感知 中间件封装(如 ORM)
Write Behind 先写缓存,异步刷 DB 高写入场景(如日志)

📌 推荐新手使用 Cache-Aside,简单可控!


九、Spring Boot 中使用缓存(快速上手)

java 复制代码
@EnableCaching
@SpringBootApplication
public class Application { }

@Service
public class UserService {

    @Cacheable(value = "users", key = "#id")
    public User getUser(Long id) {
        // 只有缓存未命中时才执行此方法
        return userMapper.selectById(id);
    }

    @CacheEvict(value = "users", key = "#user.id")
    public void updateUser(User user) {
        userMapper.updateById(user);
        // 更新 DB 后自动清除缓存
    }
}

💡 配合 spring-boot-starter-cache + Redis,几行注解搞定!


十、结语

感谢您的阅读!如果你有任何疑问或想要分享的经验,请在评论区留言交流!

相关推荐
難釋懷2 小时前
缓存更新策略
缓存
wWYy.11 小时前
详解redis(16):缓存击穿
数据库·redis·缓存
潇凝子潇17 小时前
Java 设计支持动态调整的LFU缓存: 需包含热度衰减曲线和淘汰策略监控
java·spring·缓存
派大鑫wink18 小时前
【Day57】SpringBoot 整合 Redis:吃透缓存配置与 API 实战
spring boot·redis·缓存
heartbeat..20 小时前
Redis 常用命令全解析:基础、进阶与场景化实战
java·数据库·redis·缓存
optimistic_chen1 天前
【Redis系列】分布式锁
linux·数据库·redis·分布式·缓存
不想写bug呀1 天前
Redis总结
数据库·redis·缓存
予枫的编程笔记1 天前
【Redis核心原理篇3】Redis 主从复制:数据同步的底层逻辑与实践
数据库·redis·缓存
关于不上作者榜就原神启动那件事1 天前
多级缓存必要性
缓存