java 社招面试题:假如 Redis 里有 1 亿个 key,如何找出那 10 万个“同姓的人”?

16 阅读5分钟



前几天,一个粉丝私信我,说他在面试时被 Redis 狠狠“教育”了一波。

面试官微微一笑:“Redis 里有 1 亿个 key,其中 10 万个以固定前缀开头,你怎么把它们找出来?”

他脱口而出一句 keys prefix* ,然后……就没有然后了。

这道题,真的只是考你会不会用命令吗?

故事开始:一座住着 1 亿人的城市

我们先不聊 Redis,先来讲个故事。

想象一下,有一座超级城市,里面住了 1 亿人。每个人都有姓名、身份证、门牌号,而他们的名字,就是 Redis 里的 key。这座城市的户籍系统,就是 Redis。

有一天,市长(面试官)突然问你:“小米啊,这座城市里,有 10 万个人,他们的姓都叫『张』,你怎么把这 10 万个人全部找出来?”

你想了想,拍着胸脯说:“简单!我翻一遍全城户口本,看到姓张的,全记下来!”

市长点点头:“嗯,说说你怎么翻?”

你说:“我用 KEYS 张*。”

恭喜你,第一问答对了

第一反应:KEYS,简单粗暴

回到 Redis 世界。如果我们要找出某个固定前缀的 key,比如:

最直觉的方式就是:

示例代码

是不是很爽?

  • 不用分页
  • 不用游标
  • 一条命令,全给你

就像翻户口本,一口气从第一页翻到最后一页。

面试官的“死亡追问”

这时候,面试官一般会身体前倾,语气放慢:“那如果这个 Redis,正在给线上的业务提供服务呢?”

你如果此时还在说:“那也用 KEYS 呗,很快的。”

那我只能说一句:兄弟,你已经站在事故复盘会上了。

关键点来了:Redis 的灵魂——单线程

这道题真正考的,不是命令,而是Redis 的核心特性

Redis 是单线程的。

什么意思?我们再回到那座城市。这座城市的户籍系统只有一个窗口、一个工作人员。

平时:

  • 查一个人
  • 改一个地址
  • 新增一条记录
  • 都很快

但你现在要干什么?

  • 翻 1 亿条记录
  • 挨个看姓是不是“张”

那这个窗口会发生什么?所有人排队等着,窗口被你一个人占死。

KEYS 命令的真正问题

在 Redis 中,KEYS 有几个致命特点:

1、会遍历整个 keyspace

  • 不管你只想要 10 万个
  • Redis 都要把 1 亿个 key 全扫一遍

2、是同步执行的

  • Redis 是单线程
  • 执行 KEYS 时:
    • 不能处理读请求
    • 不能处理写请求
    • 不能处理过期 key
    • 不能处理心跳

3、线上表现:服务“假死”

你会看到:

  • RT 飙升
  • 接口超时
  • 连接堆积
  • 业务报警狂响

面试官想听到的关键词: “KEYS 会阻塞 Redis 主线程,导致线上服务停顿。”

表格总结:KEYS 的问题在哪里?

那怎么办?换个思路:不要“一口气翻完”

市长这时候又问你:“那有没有一种办法,不霸占窗口,一点点翻,翻完再走?”

你眼睛一亮:“有!我们可以分批翻!”

这,就是 SCAN

SCAN:像翻书一样,慢慢来

SCAN 的设计思想就一句话:不要一次干完,分多次慢慢扫。

SCAN 的特点

  • 每次只扫一小部分
  • 不阻塞 Redis
  • 用游标(cursor)记录进度
  • 允许中途被打断

基本用法:

SCAN 示例:一步步找 key

返回结果大概是:

说明什么?

  • "13976":下一个游标
  • 后面是本次扫描到的部分 key

接着你继续:

一直扫,直到 cursor 变成 "0"。

SCAN 的“坑”:会有重复 key

这里是很多人容易翻车的地方。为什么会重复?

  • Redis 在 scan 过程中
  • key 可能发生:
    • 扩容
    • rehash
    • 迁移

所以 Redis 不保证每个 key 只返回一次

官方态度也很坦荡: “SCAN 可能返回重复元素,但不会漏。”

解决方案:客户端去重

既然 Redis 不帮你去重,那就我们自己来。

Java 示例代码(思路版)

关键点:

  • 使用 Set 去重
  • 不关心是否重复返回
  • 最终结果是完整的

KEYS vs SCAN 对比总结

面试官想要的“标准答案”

如果你在面试中,这样回答,基本就稳了:

“可以使用 KEYS 指令匹配前缀,但它会阻塞 Redis 主线程。

因为 Redis 是单线程模型,KEYS 会遍历整个 keyspace,在线上环境可能导致服务不可用。

更安全的做法是使用 SCAN 指令分批扫描,虽然可能返回重复 key,但可以在客户端进行去重。”

这一段,建议你直接背下来。

总结:技术不是会用命令,而是懂后果

很多人学 Redis,停留在:“我知道这个命令怎么用。”

但面试官真正想考的是:“你敢不敢在生产环境用?”

KEYS 就像一把大锤:

  • 小数据:很爽
  • 大数据:砸死自己

而 SCAN,就像耐心和工程经验的结合体。

技术的成熟,不是更快,而是更稳。

END

如果你觉得这篇文章对你有帮助,欢迎点个**「在看」,也可以转给**那个总爱在生产上敲 **KEYS *** 的同事。

我是小米,一个喜欢分享技术的31岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!