开篇:缓存用得好是加速器,用不好是定时炸弹
缓存就像你家门口的便利店——大部分日常需求在这里就能搞定,不用跑去市中心的大超市(数据库)。但便利店如果管理不好,缺货、过期、标错价,反而比没有还麻烦。
实际项目中,缓存带来的问题往往不是"用不用"的问题,而是"用了之后怎么兜底"的问题。这篇文章带你逐一拆解缓存体系中最常见的几颗"定时炸弹":穿透、雪崩、击穿、数据一致性,以及大 Key 和热 Key 问题。每个问题都配有真实场景和可直接落地的方案。
先用一张图鸟瞰全局:
缓存就像你家门口的便利店——大部分日常需求在这里就能搞定,不用跑去市中心的大超市(数据库)。但便利店如果管理不好,缺货、过期、标错价,反而比没有还麻烦。
实际项目中,缓存带来的问题往往不是"用不用"的问题,而是"用了之后怎么兜底"的问题。这篇文章带你逐一拆解缓存体系中最常见的几颗"定时炸弹":穿透、雪崩、击穿、数据一致性,以及大 Key 和热 Key 问题。每个问题都配有真实场景和可直接落地的方案。
先用一张图鸟瞰全局:
你开了一家生意火爆的奶茶店,只有一台收银机。某天收银机坏了——全店停业,排队的顾客全走了。这就是单点故障的代价。
Redis 单节点也面临同样的三大问题:
很多人对 Redis 的印象停留在"缓存"二字。实际上,Redis 更像一把瑞士军刀——五大基本类型、三大特殊类型,外加分布式锁、布隆过滤器、限流器……几乎每个后端高频场景都能找到 Redis 的身影。
这篇文章不罗列命令手册,而是按照"数据结构 → 使用场景 → 实战方案"的思路,把 Redis 的核心用法串起来。
Redis 有九大数据类型。其中五个是经典类型:String、Hash、List、Set、Sorted Set。三个常用特殊类型:Bitmap、HyperLogLog、GEO。还有一个 Stream(消息队列场景,但生产环境一般用 Kafka/RocketMQ)。
上一篇我们学了 Redis 的核心用法,知道了 String、Hash、List、Set、ZSet 各自适合什么场景。但你有没有想过:为什么 Hash 小的时候特别省内存?为什么 ZSet 的范围查询能做到 O(log N)?为什么 Redis 不用 C 语言原生的 char* 而要自己搞一个 SDS?
这些问题的答案都藏在底层数据结构里。这篇文章,我们就深入 Redis 内部,看看它到底是怎么把数据组织起来的。
在 Redis 中,每个键值对都会有一个 dictEntry,里面存着指向 Key 和 Value 的指针。Key 统一用 SDS(简单动态字符串)存储,Value 则存储在 redisObject 结构体中。
面试里有个经典问题:"Redis 为什么这么快?" 几乎每个后端开发都被问过。但很多人背完答案就忘了,因为没有真正理解背后的设计思路。
这篇文章,我们就从零开始,把 Redis 的核心设计理念搞清楚。不背答案,理解本质。
一句话概括:Redis 是一个基于内存的键值存储系统。
但它远不只是缓存。Redis 支持丰富的数据结构(String、Hash、List、Set、Sorted Set 等),还能做分布式锁、消息队列、排行榜、计数器……可以说是后端开发的瑞士军刀。
你在北京,数据在杭州的 Redis 服务器上。即使网络再快,一次网络往返(RTT)也要 1~2 毫秒。
但如果数据就在你的应用进程内存里呢?访问时间大约 0.01~0.1 毫秒——比 Redis 快了 10~100 倍。
这就是本地缓存的价值:把最热的数据放在离应用最近的地方,省掉网络开销,实现极致的读取速度。
当然,本地缓存不是来替代 Redis 的,而是和 Redis 配合,形成多级缓存架构:
本地缓存是 L1(一级缓存),Redis 是 L2(二级缓存),数据库是最终的数据源。越往前越快,但容量越小、一致性越难保证。