小米二面: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 快起来的,是下面几类能力共同作用的结果:
-
内存存储,避开磁盘随机 IO;
-
高效的数据结构设计;
-
单线程命令执行,减少锁竞争;
-
IO 多路复用,高效处理大量连接;
-
Pipeline、批量操作、合理编码等工程优化;
-
Redis 6.0 之后引入多线程 IO,进一步提升网络读写效率。
下面我们逐个来看。
二、第一点:数据主要在内存中,天然具备高访问速度
Redis 最直观的优势,就是数据主要存放在内存里。
和磁盘相比,内存访问速度快了好几个数量级。
大致可以这样理解:
如果一个请求需要频繁访问磁盘,即使有索引,也可能存在页读取、磁盘寻址、缓冲池命中率等问题。
而 Redis 大部分情况下直接在内存中完成数据读取和修改,所以访问路径非常短。
举个简单例子:
如果要根据用户 ID 查询用户信息。
在 MySQL 中,哪怕走索引,也可能涉及:
-
B+ 树索引查找;
-
回表;
-
缓冲池命中或磁盘读取;
-
SQL 解析和执行计划;
-
结果集返回。
而 Redis 中,如果用 String 或 Hash 存储用户信息,大致就是:
-
根据 key 计算 hash;
-
在内存哈希表中定位;
-
返回 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,简单动态字符串。
它大致包含几个核心信息:
structsdshdr{
intlen; // 当前字符串已使用长度
intfree; // 剩余可用空间
charbuf[]; // 真正存储字符串内容的数组
};
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)