从「背场景」到「做决策」:Redis 选型决策树

深度技术分析

封面

从「背场景」到「做决策」:Redis 选型决策树

每次有人问我"Redis 能做什么",我都想反问一句——你是在问它能做什么,还是在问你该让它做什么

这两个问题差了一整个段位。

打开任何一篇 Redis 使用场景文章,你会看到相似的清单:缓存、分布式锁、排行榜、消息队列、限流器、布隆过滤器……11 种,15 种,甚至有人凑出 16 种。背下来不难。面试时像报菜名一样说出来也不难。

难的是什么?

面对一个具体业务需求,你怎么在 3 分钟内判断"该不该让 Redis 做这件事"?

背 11 种场景是记忆力。给定需求,快速判断用不用 Redis、用哪种数据结构、什么时候该撤退——这才是决策力。后者在面试中更有区分度。

我见过太多开发者掉进一个陷阱:因为"Redis 能做 X"就让 Redis 做了 X,然后在生产环境踩坑。能做和该做之间,隔着一道判断题。

这篇文章给你一棵决策树。沿着 3 个问题往下走,每个场景的答案会自己浮出来。不用背,用推导。


1 决策树全貌:3 个问题定生死

先给结论。决策 Redis 是否适合某个场景,你只需要回答 3 个问题:

  1. 读写比如何?(读多写少 / 写多读少 / 均衡)
  2. 一致性要求到什么级别?(最终一致 / 强一致 / 事务级)
  3. 数据量级和内存的关系?(热数据 < 内存 / 热数据 > 内存 / 全量远超内存)

为什么偏偏是这 3 个?不是 4 个,不是 5 个?

因为它们直接对应 Redis 的 3 个核心架构特征:

  • 内存存储 → 容量有天花板,数据量级是硬约束
  • 单线程命令执行 → 原子性天然强,但一条慢命令阻塞全局
  • 丰富数据结构 → 不同结构匹配不同读写模式,选错结构等于自废武功

其他维度当然也重要,但它们是二级问题。先用上面 3 个问题定方向,再用以下清单细化:

  • 延迟 SLA:P99 要求 < 1ms?需要评估网络拓扑和持久化策略对延迟的影响
  • 运维复杂度:团队有没有 Redis Cluster / Sentinel 的运维经验?
  • 内存成本:云环境 Redis 内存 GB 单价远高于磁盘存储,中小团队要算账
  • 持久化需求:RDB fork 在大数据集(>10GB)上可阻塞数百毫秒,AOF rewrite 同理

3 个问题定方向,4 个维度做细化。先过了主线再走支线。

Redis选型决策树

抽象看不够直观。走几个真实场景试试。

走树演示:3 个场景

场景 A:电商秒杀库存扣减

  • 读写比?→ 高并发写(瞬时数万请求同时扣减)
  • 一致性?→ 强一致(超卖不可接受,一件都不能多)
  • 量级?→ SKU 级别,万级热门商品

决策路径走到了"Redis 原子操作 + 额外保障"。具体方案:用 Lua 脚本做原子"检查库存 > 0 再扣减"。注意,单纯 DECR 只是原子递减,不检查下界,库存可以减到负数,不能防超卖。Redis 在这个场景是最优解:纯内存操作,微秒级响应,单线程天然避免竞争。

但有退出条件:如果扣减需要跨多个服务(比如同时扣库存 + 扣优惠券 + 扣积分),单靠 Redis 的原子性不够,需要分布式事务方案(如 TCC)兜底。

场景 B:社交 Feed 流排序

  • 读写比?→ 读远多于写(用户发帖少,刷 Feed 极频繁)
  • 一致性?→ 最终一致(晚 3 秒看到新动态完全可接受)
  • 量级?→ 单用户 Feed 百级条目,但用户量千万级

走到"Redis 缓存-经典场景"。用 ZSET 按时间戳排序,每个用户一个 ZSET 存 Feed ID 列表。读取用 ZREVRANGE 取最新 N 条,O(log N + K) 响应。

退出条件:如果 Feed 需要个性化推荐算法介入(不是简单的时间排序),Redis 只能做缓存层,排序逻辑必须在应用层或推荐引擎中完成。

场景 C:订单状态机

  • 读写比?→ 均衡(状态流转频繁,查询也频繁)
  • 一致性?→ 事务级(订单从"待支付"变"已支付"不能出错,不能丢)
  • 量级?→ 日百万订单

走到了"不推荐 Redis 做主存储"。订单状态机需要的是:持久化保证 + 事务性状态流转 + 审计日志。这些都不是 Redis 的强项。

正确方案:MySQL/PostgreSQL 做订单主存储(InnoDB 行锁保证状态流转原子性),Redis 做热订单的查询加速缓存。各司其职。

三场景走树演示

3 个场景,每个 30 秒内有答案。这就是决策树的价值,不用背,用推。


2 缓存——Redis 的甜蜜区

缓存是 Redis 的主场。绝大多数 Redis 实例都在做缓存相关的工作(据 Redis Labs 历年调查,缓存是排名第一的用途)。

但我想说的不是"Redis 能做缓存"这种废话。我想说的是:缓存场景里,Redis 的甜蜜区到底在哪?你的用法在不在甜蜜区里?

答案藏在数据结构的底层编码方式中。

编码切换对比

编码决定效率

Redis String 有两种内部编码:

  • embstr(value ≤ 44 字节):Redis 对象头(16 字节)和 SDS 字符串体在同一块连续内存中。一次 malloc,零碎片,CPU cache 友好。
  • raw SDS(value > 44 字节):对象头和字符串体分开分配。两次 malloc,有内存碎片风险,且访问需要多一次指针跳转。

这意味着一个被大多数人忽略的设计原则:如果你的缓存 value 能控制在 44 字节以内,内存效率最高。

什么东西适合?session token(通常 32-40 字符)、UUID(36 字符)、短数字 ID、布尔标记、小计数器。这些是 String 缓存的绝对甜蜜区。

Hash 也有类似的分水岭。Redis 7.x 中,field 数量 ≤ 128(hash-max-listpack-entries 默认值)且每个 field 值 ≤ 64 字节时,使用 listpack 编码(紧凑的线性字节数组,取代了旧版的 ziplist)。一旦超过任一阈值,自动升级为 hashtable。

差距有多大?listpack 的内存效率比 hashtable 高出约 3-5 倍(100 field 场景)。同样存 100 个用户属性字段,listpack 编码可能只占几 KB,hashtable 编码占用要翻几番。

这个阈值很多教程都写错——旧版 ziplist 时代默认确实是 512,Redis 7.x 换成 listpack 后改成了 128。别踩这个坑。listpack 是线性结构,查找是 O(N)。field 越多,HGET 越慢。实践中建议将单个 Hash 控制在 100 field 以内——既在默认阈值安全线内享受 listpack 的内存优势,又不让查找成为瓶颈。

设计原则:用户 profile 拆成多个小 Hash(每个控制在 100 field 以内),比塞进一个 500 field 的巨型 Hash 省内存也更快。

ZSET 同理:元素 ≤ 128 时用 listpack(紧凑但查找 O(N)),超过后升级为 skiplist + hashtable(O(log N) 但内存消耗翻 2-3 倍)。排行榜设计的第一步是预估你的最大元素量——这决定了底层编码,进而决定了内存成本和查询模式。

缓存模式的选择

Cache-Aside(旁路缓存)是最常见的模式。但它有一个天然弱点:读取 miss 后写入缓存,到下次更新 DB 前,缓存数据可能已过期。

三种缓存模式的适用条件:

模式 一致性 适用场景 Redis 角色
Cache-Aside 最终一致 读多写少,容忍秒级延迟 旁路加速
Write-Through 高一致 读写均衡,不容忍脏读 同步写入
Write-Behind 弱一致 写极多,容忍数据丢失 写缓冲

注:Write-Through 和 Write-Behind 在 Redis 中无原生支持,需要应用层代码实现同步/异步写入逻辑。Write-Through 的"高一致"也非严格线性一致——并发写入时仍存在一致性窗口。

缓存模式选择

大部分业务场景用 Cache-Aside 就够了。如果你发现自己在实现 Write-Through 的复杂逻辑——停下来想想,是不是场景本身就不适合缓存。

缓存的退出条件

什么时候 Redis 缓存不该用?两个核心信号:

  1. 热数据集远超可用内存,或数据更新极其频繁且无规律:经验上,缓存命中率低于 85-90% 时(具体阈值因业务而异),缓存带来的收益会被 miss 后回源 DB 的开销抵消。监控你的 keyspace_hits / (keyspace_hits + keyspace_misses)。如果 TTL 设 10 秒,数据 3 秒就变了,缓存命中那 3 秒拿到的是脏数据,其余 7 秒是 miss,这种场景缓存是负优化。
  2. 一致性要求到了"不允许任何脏读"的级别:Cache-Aside 模式天然有窗口期(DB 更新后缓存失效前的那个瞬间)。如果这个窗口不可接受,别硬上缓存,改架构。

满足任意一个,重新评估方案。不是 Redis 不行,是场景不对。


3 分布式锁——边界在哪

分布式锁用 Redis?可以。但先问清楚边界在哪。

大部分教程告诉你 SET key value NX EX 30 就完事了。在单 Redis 实例、并发不高、允许偶尔失败的场景里,确实够用。Redisson 框架把这件事封装得更好——加上了看门狗续期、可重入支持、公平锁等特性。

问题不在于"怎么加锁"。问题在于:你的"分布式锁"到底需要多强的互斥保证?

脑裂场景:锁为什么会失效

Redis 主从复制是异步的。这一句话背后藏着一个致命的边界条件。

构造一个时序,你就明白问题有多真实:

T0  客户端A → Master: SET lock:order NX EX 30 → 成功,获得锁
T1  Master 宕机(锁数据尚未同步到 Replica)
T2  Sentinel 检测到 Master 不可达,开始 failover(通常需要数秒)
T3  Replica 被提升为新 Master(但它没有 lock:order 这个 key!)
T4  客户端B → 新Master: SET lock:order NX EX 30 → 成功,也获得了锁
T5  💥 客户端A 和 客户端B 同时持有锁 → 互斥性被打破

脑裂时序

从 T0 到 T5,可能只有 3-5 秒。但这几秒足以让两个客户端同时操作同一份资源。

你可能想说:这个概率很低。没错,低——但"概率低"不等于"可以无视"。如果锁保护的是支付扣款操作,一次失效就是一笔资金损失,一个 P0 级事故。

Redisson 的看门狗能解决这个问题吗?不能。看门狗解决的是"锁过期但业务没执行完"的问题,解决不了"Master 宕机数据丢失"的问题。这是两个完全不同层面的风险。

Redlock:复杂度陷阱

Redis 作者 antirez 为了解决上述问题,提出了 Redlock 算法:向 N(推荐 5)个完全独立的 Redis 实例同时申请锁,获得多数派(≥ N/2 + 1 = 3)响应且总耗时未超过锁的有效期,才视为加锁成功。

听起来合理。但 Martin Kleppmann 在 2016 年那篇经典文章("How to do distributed locking")里提出了尖锐批评:Redlock 依赖节点时钟大致同步,但时钟跳变(NTP 校准、VM 迁移)会让过期计算不可靠;客户端拿到锁后遭遇 GC pause 或网络分区,锁可能早已过期但客户端不知道。更根本的问题是——Redis 不是共识系统,让它承担互斥保证,是用错误的工具解决问题。

我认为 Kleppmann 的分析在理论层面是对的。不过 antirez 在回应文章"Is Redlock safe?“中反驳:Redlock 不要求绝对时钟同步,只要时钟漂移远小于 TTL 就够了(现代硬件通常满足);GC pause 导致锁过期是所有分布式锁的通病,不是 Redlock 特有的问题。

两边都有道理。但工程实践中,判断不能只看理论——还要看成本。

我的决策建议是这样的:

  • 90% 的场景:单 Redis 实例锁 + 合理过期时间(业务执行时间的 3 倍以上) + 业务层幂等设计 = 足够安全。脑裂是极低概率事件,用业务补偿兜底。
  • 锁失效会造成资金损失:etcd 或 ZooKeeper。它们基于 Raft/ZAB 共识算法,互斥保证是协议级别的。但注意:etcd/ZK 写入吞吐通常在千级 QPS,获锁并发量极高(万级/秒)时需要应用层排队或分段锁。
  • Redlock:要维护 5 个独立 Redis 实例,运维成本不低,但安全性提升有限(Kleppmann 的批评仍然成立)。性价比很差,不推荐作为首选。

一句话决策:锁失效会造成不可逆损失(资金/数据)?会 → etcd/ZK。不会 → Redis 单实例 + 幂等补偿。 Redlock 是一个复杂度陷阱——花了 5 倍的运维成本,买了一个"好一点但仍然不完美"的保证。

锁方案决策

分布式锁考验的是一致性边界。接下来换个维度——看数据结构选择怎么影响性能天花板。


4 排行榜/计数器——选对结构

ZSET 天生就是排行榜的数据结构。O(log N) 插入,O(log N + M) 范围查询(M 为返回元素数),O(log N) 查排名。看起来无可挑剔。

但"用 ZSET 做排行榜"不是一句话就能搞定的事。数据量从 1 万到 1000 万,最优方案完全不同。拍脑袋选了方案 A,等数据量涨到百万级才发现扛不住——代价是重构。

ZSET 底层:skiplist 的代价

先搞清楚 ZSET 的底层。当元素超过 128 个(或单元素超过 64 字节),ZSET 从 listpack 升级为 skiplist + hashtable 双结构。

skiplist 的查找是 O(log N)——这是期望值。Redis 的 skiplist 提升概率 p=0.25,搜索深度按 log₄(N) 计算。N = 1 万时,平均约 7 层。N = 1000 万时,平均约 12 层。每多一层就是一次内存随机访问(pointer chase),CPU cache miss 率随之上升。

7 层和 12 层,看起来差距不大对吧?但乘以每秒数万次操作,这 5 层的差距就是 QPS 天花板的分水岭。

三方案性能推演

⚠️ 以下推演基于 Redis 时间复杂度和官方 benchmark 数据(redis-benchmark 单实例 ~10 万 QPS 基线),非同环境直接对比实测

三方案性能对比

方案 A:单 ZSET 全量存储

最简单直接的方案。一个 ZSET 装所有参与者的分数。

  • 更新分数:ZADD key score member → O(log N)
  • 查 Top-100:ZREVRANGE key 0 99 WITHSCORES → O(log N + 100)
  • 查某人排名:ZREVRANK key member → O(log N)

N = 1 万时,每次操作约 7 跳,单实例轻松达到十万级 QPS。N = 100 万时,约 10 跳,QPS 仍在万级以上。N = 1000 万时,约 12 跳加上内存压力(单个 ZSET 占内存可达 GB 级),QPS 进一步下降但仍可用。

能用吗?当然能。但数据量从万级到千万级,性能衰减是肉眼可见的。千万级 ZSET 还有 Big Key 风险:DEL 可能阻塞主线程数秒(Redis 4.0+ 推荐用 UNLINK 异步删除),Cluster 迁移容易超时。

方案 B:分桶 ZSET(按分数段或时间段分片)

核心思路:把一个大 ZSET 拆成多个小 ZSET。

比如按分数区间:score 0-999 放 rank:bucket:0,score 1000-1999 放 rank:bucket:1。每个桶的 N 小,skiplist 层数少,单桶操作更快。

但代价是:

  • 查 Top-K 可能需要跨桶合并(从最高分桶开始取,不够再取次高桶)
  • 实现复杂度显著上升
  • 查某人全局排名需要计算低分桶的总人数作为偏移

适合的场景:写入 QPS 极高(万级以上且持续增长)、分数分布相对均匀、可以接受实现复杂度的团队。

方案 C:ZSET + Hash 缓存热数据

ZSET 仍然存完整排行,但将 Top-100(或 Top-1000)用一个 Hash 单独缓存。定时任务(比如每 5 秒)从 ZSET 取最新 Top-K 写入 Hash。

读 Top-100 变成 HGETALL → O(K)(K=100,不随排行榜总规模增长)。写入仍然打到 ZSET(O(log N)),但高频的"查看排行榜"请求被 Hash 挡住了,不再重复扫 skiplist。

代价:排行榜有最多 5 秒的数据延迟。对于游戏排行、内容热度榜——完全可接受。对于实时竞拍——不行。

方案选择决策

数据量 写入压力 推荐方案 核心理由
万级 方案 A 简单即正义,ZADD + ZREVRANGE 性能绰绰有余
十万-百万级 中等 方案 C 读写解耦,查询不受 N 增长影响
百万级以上 方案 B 分桶分压,每个桶维持高效操作
千万级以上 任意 Redis Cluster 分片 + B/C 组合 单实例内存和 CPU 都扛不住。注意:Cluster 模式下分桶 ZSET 需用 hash tag {rank}:bucket:N 保证同 slot 操作

10 万以下闭眼方案 A。10 万以上先试方案 C,最小改动最大收益。百万级数据量才需要动分桶的心思。

排行榜和计数器的决策核心是数据结构选型。下一个场景换个赛道——消息队列,这里要决策的不是"用什么结构”,而是"用不用 Redis"。


5 消息队列——进退线

Redis Stream 在 5.0 引入,到 7.x 已经相当成熟。消费者组(Consumer Group)、消息确认(XACK)、消息持久化(AOF)、消费进度追踪——该有的功能都有了。

但"能当消息队列用"和"该当消息队列用"是完全不同的两个命题。

我的判断是:Redis Stream 是一个优秀的"轻量级异步解耦"工具,但它不是、也不该是你的"企业级消息中间件"。

Redis Stream vs Kafka:维度拆解

⚠️ 以下对比基于官方文档和公开 benchmark 推演,非同环境直接对比实测

Stream vs Kafka

吞吐量差距:Redis Stream 单实例约 10-15 万 msg/s(消息体 < 1KB)。Kafka 单 broker 可达约 100 万 msg/s。差一个数量级。Redis 是纯内存操作所以延迟低,但吞吐上限受单线程模型限制。

持久化保证:Redis Stream 的持久化依赖 AOF(append-only file)。如果用 everysec 策略,极端宕机可能丢 1 秒数据。如果用 always 策略,性能打折。Kafka 的分区副本机制(acks=all + ISR)提供的持久化保证强得多——Leader 写入后等待所有 ISR 副本确认。

消息堆积容忍度:Redis Stream 的数据全在内存。堆积 100 万条小消息就要占几百 MB 内存。通常用 MAXLEN 或 MINID 做截断。Kafka 是磁盘顺序写,百 GB 甚至 TB 级堆积都是正常操作。

运维成本:Redis Stream 零额外部署——你已有的 Redis 集群就能承载。Kafka 需要独立集群:以前是 ZooKeeper + broker,现在 KRaft 模式好一些,但仍需要独立运维。对于小团队,这不是小事。

消费语义:Redis Stream 的 XREADGROUP + XACK 机制实现了 at-least-once 语义。但如果消费者崩溃后没有 XACK,消息会留在 pending 列表里等待认领(XCLAIM)。这个机制能用,但没有 Kafka Consumer Group 的 rebalance 那么成熟和自动化。

场景分界线

用 Redis Stream 的信号

  • 日消息量在十万级以下
  • 消息体小(< 1KB,典型的事件通知类)
  • 允许极端场景丢少量尾部消息
  • 团队已有 Redis 运维经验,不想为了一个异步需求引入 Kafka 全家桶
  • 需求本质是"轻量级解耦"——A 服务通知 B 服务做某件事

切换到 Kafka 的信号

  • 日消息量十万级以上
  • 消息不能丢(金融级可靠性要求)
  • 需要 TB 级堆积能力和任意时间点消息回溯
  • 多个消费者组需要独立消费同一份数据流
  • 已有 Kafka 集群和运维团队

灰色地带(日十万到百万之间):取决于你的团队。有 Kafka 经验就直接上 Kafka,省得以后迁移。没有的话,Redis Stream 先扛着,监控好内存和堆积量,什么时候扛不住再迁移。迁移成本不高,因为 Stream 和 Kafka 的消费模型很接近。

一句话决策:日消息量十万级以下、允许极端场景丢数据 → Redis Stream。超过这个线 → Kafka。 先用 Stream 扛着,扛不住再迁 Kafka,迁移成本不高。


6 冷门场景:快速决策

有些 Redis 场景不需要一整章来展开。但面试时经常被问到。给你每个场景的快速决策结论和边界条件。

冷门场景卡片

布隆过滤器

用它的唯一正当理由:你需要快速回答"这个元素一定不在集合中"。

注意"一定不在"这个措辞。布隆过滤器说"不在",那就真不在。说"在",有一定概率是误判(false positive)。它解决的是"确定性否定"问题。

典型场景:缓存穿透防护(拦截不存在的 key 请求)、爬虫 URL 去重、推荐系统已曝光过滤。

内存开销多大?基于 BloomFilter 最优参数公式(m = -(n × ln p) / (ln 2)²)推算:

预期元素数 误判率 1% 内存 误判率 0.1% 内存 最优哈希函数数
100 万 ~1.14 MB ~1.71 MB 7 / 10
1000 万 ~11.4 MB ~17.1 MB 7 / 10
1 亿 ~114 MB ~171 MB 7 / 10

千万级以下,Redis BF 模块(RedisBloom)一条 BF.ADD 命令搞定,内存开销极低(十几 MB)。不用自己实现哈希函数,不用自己管理位数组。

不用 Redis 布隆过滤器的信号

  • 需要精确判断"在/不在"(布隆有误判,不适合)
  • 需要删除元素(标准布隆不支持删除,Cuckoo Filter 可以但换了个数据结构)
  • 元素量超过亿级且内存敏感(占用 100MB+ 的 Redis 内存,要权衡是否划算)

延时队列

Redis 实现延时队列的经典姿势:ZSET 中 score 设为消息到期的时间戳(Unix timestamp),消费者轮询 ZRANGE key min max BYSCORE(Redis 6.2+ 推荐语法,旧版用 ZRANGEBYSCORE)取出到期消息,然后 ZREM 删除。

为什么用 ZSET?因为 score 排序天然就是时间排序,按当前时间过滤就是取"已到期的所有任务"。O(log N + M) 的时间复杂度,M 是到期任务数。

本质上这是一个"穷人版"延时队列。功能够用、部署简单、不引入新依赖。适合日任务量不大(十万级以下)、精度要求秒级、不需要严格 exactly-once 语义的场景。ZRANGE…BYSCORE + ZREM 不是原子操作,需要 Lua 脚本或分布式锁配合。

什么时候该换?任务量到了百万级(轮询压力大,ZSET 内存膨胀),或者需要毫秒级精度,或者需要严格消息不丢。这时候 RocketMQ(原生延时消息)或 XXL-JOB 是更合适的选择。够用就用,扛不住再换,迁移成本很低。

社交关系(共同好友/关注列表)

Set 的交集运算 SINTER 看起来天然适合"共同好友"。两个用户各一个 Set 存关注列表,SINTER 取交集,完事。

用 Redis Set 的条件

  • 用户总量 < 百万
  • 单用户关注/好友列表 < 5000 人
  • 查询不频繁(非每次打开页面都算共同好友)

这个量级下,SINTER 操作耗时在毫秒级以内。内存占用需要留出余量——100 万用户 × 平均 500 关系 × 每个 member 实际占用约 60-70 字节(含 dictEntry、SDS header、内存对齐等 Redis 元数据开销)≈ 30-35 GB。一台大内存 Redis 能扛,但要做好容量规划。

不用 Redis Set 的信号

  • 用户量千万级以上 → 内存装不下(千万用户 × 1000 关系 = 百亿 member)
  • 单用户关系数超万 → SINTER 两个万级 Set 的耗时会到达几十毫秒,阻塞单线程
  • 需要多跳关系查询(好友的好友)→ Set 只能做一跳交集,多跳需要图计算

大规模社交图谱该用图数据库(Neo4j、TigerGraph)做离线分析,或者用 Spark/Flink 预计算共同好友列表存入缓存。Redis 只适合做"热点用户"的关系缓存——微博大 V 的粉丝列表 Top-N,而不是全量关系图。如果用 Redis Cluster,注意 SINTER 要求 key 在同一 slot,需用 hash tag(如 {user}:friends)保证。


决策速查表

回到最开头的问题:Redis 能做什么?

答案是它能做很多事。但你该让它做什么,取决于你的 3 个业务约束条件。

决策速查表

场景 推荐数据结构 推荐度 退出条件(触发任一则重新评估)
缓存 String / Hash 强推 热数据远超内存 / 不容忍任何脏读
分布式锁 String + NX 推荐 锁失效会造成资金损失
排行榜 ZSET 强推 数据量千万级以上且写入压力极高
计数器/限流 String INCR 强推 需要跨实例全局精确计数
消息队列 Stream 条件推荐 日消息量十万级以上 / 消息不能丢
延时队列 ZSET 条件推荐 任务量大 / 需要毫秒级精度
布隆过滤器 BF 模块 推荐 需要精确判断 / 需要删除元素
社交关系 Set 条件推荐 用户量千万以上 / 需要多跳查询
会话存储 Hash 推荐 会话数据需要复杂查询或联表

面试时怎么用这棵树

面试官问"Redis 有哪些使用场景"时,不要报菜名。

“缓存、分布式锁、排行榜、消息队列……” 这种回答和百度第一页搜索结果没区别。面试官听了几百遍了。

试试这样回答:

“我不会去背 Redis 有几种用法。在做场景选型时,我会从 3 个维度判断:读写比、一致性要求、数据量级。

举个例子——缓存场景,读多写少 + 最终一致 + 热数据可控,这是 Redis 的绝对甜蜜区,闭眼用。

但分布式锁就不一样了。如果涉及资金安全,我不会用 Redis——因为主从异步复制在 failover 时有锁失效风险。这种场景我会建议 etcd。

Redis Stream 做消息队列也是。日十万级以下、允许极端情况丢消息——可以。超过这个线就该上 Kafka。

关键是知道每种用法的边界在哪、什么时候该退出。”

这段回答包含了决策框架、具体判断、边界认知和替代方案。

比罗列场景更有说服力。

最后一句

Redis 强在特定约束条件下,它是那个最优解。

你的工作是判断:在你的具体场景里,它到底是不是最优解。如果不是,果断换。

决策能力 > 记忆力。这是这篇文章想说的全部。


原文发布于 止语Lab


关于止语Lab

一个工程师的深度技术笔记。

不写入门教程,不追热点。只写那些真正折腾过、想通了的东西。

了解更多 →