请不要用 Redis 做任何缓存之外的事

Redis 是程序员工具箱里很容易被“过度信任”的东西。 它太顺手了。 想存个值,SET 一下。想自动过期,EXPIRE 一下。想做计数器,INCR 一下。想搞队列,LPUSH / BRPOP 一下。想搞锁,SET NX PX 一下。再看一眼 Stream,好像连消息系统也能顺手安排。 于是很多系统就这么一路滑坡: 第一天:Redis 只是缓存。 第二天:这个状态先放 Redis 吧。 第三天:队列也先放 Redis 吧。 第四天:库存扣减也先放 Redis 吧。 第五天:Redis 挂了,大家开始翻日志考古。 这篇文章想讲的观点很简单: Redis 能做很多事,但不要让它单独拥有真相。 如果一份数据不能丢、不能错、不能重复处理、不能悄悄过期、不能被内存策略淘汰,那它就不应该只待在 Redis 里。 Redis 最舒服的位置是缓存。它可以让系统跑得更快,但不应该决定系统还能不能正常活下去。 先看边界:缓存可以重建,事实不能只靠 Redis 这不是 Redis 不行。 Redis 很强,而且越来越强。它有 RDB,有 AOF,有复制,有 Sentinel,有 Cluster,有 Streams,还有很多高级数据结构。Redis 8 之后,JSON、Search、Time Series、概率数据结构等能力也被合进 Redis Open Source。 所以问题不是“Redis 能不能干更多活”。 问题是:你把活交给 Redis 之后,能不能接受它的失败方式。 缓存的失败方式很朴素: Redis 没了 -> 缓存 miss -> 回源数据库 -> 重新写缓存 这很烦,但不至于让业务当场失忆。 ...

May 23, 2026 · 3 min · Icyyan

Redis 底层数据结构:一个 key 背后到底藏着什么

很多人第一次学 Redis,记住的是五种常用类型:String、List、Hash、Set、ZSet。再往后背面试题,又会遇到 SDS、quicklist、listpack、intset、skiplist、hashtable。 这些名字放在一起很容易让人迷糊:Redis 不是 key-value 数据库吗?为什么一个 Hash 后面还会有 listpack 和 hashtable 两种实现?为什么同样是 Set,有时是 intset,有时又变成哈希表? 真正要理解的不是“Redis 有哪些数据结构”这张清单,而是一个更具体的问题: Redis 为什么要让同一种对外类型,在不同场景下切换不同的内部编码? 顺着这个问题往下看,Redis 的底层数据结构会清楚很多。它不是为了把实现弄复杂,而是在内存、CPU、查询速度、扩容成本之间做了一组很工程化的取舍。 写这篇文章时(2026 年 7 月,版本信息核对于 7 月 21 日),Redis Open Source 的最新稳定版是 8.8.0,2026 年 5 月 25 日 GA,预发布阶段亮相的新数据结构 Array 也在这一版正式落地;8.6 线的最新补丁是 8.6.4。 从底层数据结构这条线看,Redis 8.6 以来最值得关注的不是“又多背几个结构名”,而是大 Hash、大 ZSet 的内存继续被优化,以及 Stream 幂等写入、HOTKEYS、key 内存大小直方图、LRM 淘汰策略这些贴近日常排查的新能力。这些在后文对应的小节里都会具体展开。 对外类型和内部编码不是一回事 平时我们写 Redis 命令,面对的是对外类型: SET name bole LPUSH queue a b c HSET user:1 name bole age 18 SADD tags redis cache ZADD rank 100 alice 这些命令分别对应 String、List、Hash、Set、ZSet。但 Redis 在内存里不会只保存“这是一个 Hash”这么简单的信息。 ...

May 23, 2026 · 6 min · Icyyan