小米二面: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[]; // 真正存储字符串内容的数组
};
相关推荐
Moment1 小时前
刷 Reddit 1 小时没结果?我用这个方法 10 秒挖出真实需求
前端·javascript·后端
学不思则罔1 小时前
SpringBoot启动失败排查指南
spring boot·后端·部署
喵个咪1 小时前
Kratos KCP 传输中间件:游戏开发低延迟网络通信实战指南
后端·微服务·游戏开发
喵个咪1 小时前
Kratos 生态双定时器中间件:高精度 hptimer 与标准 cron 选型与实践
后端·微服务·go
夕除2 小时前
spring boot 5
数据库·spring boot·后端
星栈2 小时前
每次改订单,我都存了快照
后端·rust·开源
传说之后2 小时前
Go Context 完全指南:树状级联、超时控制、值传递与最佳实践
后端·go
一个骇客2 小时前
还在写 Python 脚本?试试用 Unix 命令分析莎士比亚
后端
XovH2 小时前
Django 实战:从零开发一个完整的博客系统(附带文章、分类、标签)
后端