小米二面:Redis为什么能支撑10万+QPS?

前言

最近有个朋友参加小米二面,被问到一个很经典的问题:

Redis 为什么能支撑 10 万+ QPS?

他第一反应是:

因为 Redis 是基于内存的,内存读写速度快。

这个回答不能说错,但明显不够。

面试官接着追问:

Memcached 也是内存数据库,为什么 Redis 支持的数据结构更丰富,性能还这么高?

这一下,他就有点接不住了。

其实这类问题,面试官真正想考察的并不是"你知不知道 Redis 快",而是想看你能不能从存储模型、数据结构、网络模型、线程模型、工程优化这几个角度,把 Redis 高性能的原因讲清楚。

今天这篇文章就围绕这个问题展开:
Redis 为什么能支撑 10 万+ QPS?


一、10 万+ QPS 到底是什么水平?

先简单理解一下 QPS。

QPS,全称是 Queries Per Second,也就是每秒请求数。

如果 Redis 单机能够支撑 10 万 QPS,意味着它每秒可以处理大约 10 万次请求。

在一些常见压测场景中,Redis 的表现大致如下:

  • GET请求:可以达到 10 万级 QPS;
  • SET请求:也可以达到 10 万级 QPS;
  • INCR这类简单原子操作:同样可以达到非常高的吞吐;
  • 开启 Pipeline 后,某些简单命令甚至可以冲到几十万、上百万 QPS。

当然,具体性能和机器配置、网络环境、数据大小、命令类型、持久化配置、客户端使用方式都有关系。

但是有一点基本可以确定:

Redis 的高性能,并不是单纯因为它"用内存"。

内存只是基础条件。

真正让 Redis 快起来的,是下面几类能力共同作用的结果:

  1. 内存存储,避开磁盘随机 IO;
  2. 高效的数据结构设计;
  3. 单线程命令执行,减少锁竞争;
  4. IO 多路复用,高效处理大量连接;
  5. Pipeline、批量操作、合理编码等工程优化;
  6. Redis 6.0 之后引入多线程 IO,进一步提升网络读写效率。

下面我们逐个来看。


二、第一点:数据主要在内存中,天然具备高访问速度

Redis 最直观的优势,就是数据主要存放在内存里。

和磁盘相比,内存访问速度快了好几个数量级。

大致可以这样理解:

如果一个请求需要频繁访问磁盘,即使有索引,也可能存在页读取、磁盘寻址、缓冲池命中率等问题。

而 Redis 大部分情况下直接在内存中完成数据读取和修改,所以访问路径非常短。

举个简单例子:

如果要根据用户 ID 查询用户信息。

在 MySQL 中,哪怕走索引,也可能涉及:

  1. B+ 树索引查找;
  2. 回表;
  3. 缓冲池命中或磁盘读取;
  4. SQL 解析和执行计划;
  5. 结果集返回。

而 Redis 中,如果用 String 或 Hash 存储用户信息,大致就是:

  1. 根据 key 计算 hash;
  2. 在内存哈希表中定位;
  3. 返回 value。

路径更短,访问更直接。

所以,Redis 快的第一个基础原因是:

它把核心数据放在内存中处理,减少了磁盘 IO 带来的巨大延迟。

但是,只说这一点还不够。

因为如果数据结构设计得不好,即使在内存里,也可能很慢。


三、第二点:Redis 的数据结构不是简单封装,而是深度优化

Redis 之所以好用,是因为它提供了丰富的数据结构。

常见的有:

  • String;
  • Hash;
  • List;
  • Set;
  • ZSet;
  • Bitmap;
  • HyperLogLog;
  • Stream;
  • Geo。

但 Redis 的优秀之处,不只是"支持这些结构",而是它在底层针对不同场景做了很多优化。

同样一个 Hash,在数据量小的时候和数据量大的时候,底层编码可能是不一样的。

同样一个 List,在不同版本中,也会结合压缩结构和链表结构来平衡空间与性能。

这就是 Redis 能兼顾功能丰富和高性能的重要原因。


四、SDS:Redis 为什么不用 C 原生字符串?

Redis 是用 C 语言写的。

但 Redis 并没有直接使用 C 语言原生字符串,而是自己实现了一套字符串结构,叫 SDS。

SDS 全称是 Simple Dynamic String,简单动态字符串。

它大致包含几个核心信息:

ini 复制代码
structsdshdr{
 intlen;  // 当前字符串已使用长度
 intfree;  // 剩余可用空间
 charbuf[]; // 真正存储字符串内容的数组
};
相关推荐
利威尔xu17 小时前
Go IM 源码实战(11):token 只是个 HASH,多端互踢的顺序错了就踢错人
后端·微服务·面试·架构·golang
猿究院--Cu-Sn合金18 小时前
Spring Boot + DeepSeek 求职 Agent 实践:工具注册、多轮调用与简历 JD 对比
数据库·人工智能·spring boot·后端·deepseek
程序员cxuan18 小时前
别学 subagent 了,很可能要凉了。
后端·agent·ai编程
小咕聊编程18 小时前
基于Django的个人摄影博客网站设计与开发
后端·python·django
未秃头的程序猿19 小时前
@ConditionalOnMissingBean 把我配好的 RabbitMQ 手动 ack 吃掉了
后端·rabbitmq
回家路上绕了弯19 小时前
当 AI 成为队友:团队协作使用 AI 的实践与思考
后端
陈随易19 小时前
副业搞钱点子之独立开发
前端·后端·程序员
MetaLite19 小时前
Spring Boot 加了 @Valid,嵌套参数为什么还没校验?
java·spring boot·后端
霸道流氓气质19 小时前
Lingua 语言检测库:n-gram 统计模型、置信度阈值调优与 Spring Boot 分层检测管道的生产级实战
java·spring boot·后端
geovindu20 小时前
rust: Read-Write Lock Pattern
开发语言·后端·设计模式·rust·读写锁模式·同步型模式