什么是缓存

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

你是否遇到过这些问题?

  • 用户点击一个按钮,页面转圈 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,几行注解搞定!


十、结语

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

相关推荐
深蓝轨迹5 小时前
Redis 消息队列
java·数据库·redis·缓存·面试·秒杀
于樱花森上飞舞6 小时前
【Redis】初识Redis
数据库·redis·缓存
山楂树の8 小时前
【计算机系统原理】Intel 与 AT&T 汇编指令格式转换
汇编·学习·缓存
山楂树の8 小时前
【计算机系统原理】 直接映射(模映射) Cache 地址划分与访问过程
学习·缓存
cyforkk8 小时前
缓存穿透难题:当 Value 为空字符串时,该如何优雅处理?
缓存
呆子也有梦8 小时前
redis 的延时双删、双重检查锁定在游戏服务端的使用(伪代码为C#)
redis·后端·游戏·缓存·c#
roman_日积跬步-终至千里9 小时前
【2025下半年系统架构设计师案例分析】电商平台 MySQL + Redis 与缓存击穿治理
mysql·缓存·系统架构
入瘾10 小时前
Redis 服务启动失败
数据库·redis·缓存
cyforkk12 小时前
分布式缓存一致性:从核心争议到企业级解决方案
缓存
爱丽_12 小时前
大型系统构建与性能优化:缓存、负载均衡、分库分表与会话方案
jvm·缓存