Skip to content

Redis 为什么这么快? ​

  • 标签:后端、Redis

🏛 业务架构师 ​

Redis 快的原因可以归纳为四层,我配上业务含义:

  • 纯内存操作:数据在内存,读写是纳秒级内存访问,对比磁盘的毫秒级是三个数量级的差距——这是它承接热点读的资本;
  • 单线程命令执行 + IO 多路复用(epoll):单线程没有锁竞争、没有上下文切换开销,一条线程监听成千上万个连接;单线程换来了无锁的简单性,业务含义是:不会有死锁、时序确定、排查简单;
  • 高效数据结构:SDS 字符串(O(1) 长度)、跳表(ZSet O(logN))、ziplist/listpack(小数据紧凑存储)、intset——为不同数据形态选了不同的物理结构,省内存又省 CPU;
  • 单线程也促成了极简的线程模型:不存在并发修改, pipelines/mget 这类批量操作顺序执行即可。

业务上的"快"值多少钱:商品详情页 QPS 10 万,若每次读 DB 5ms,需要上百台 DB;前面挡一层 Redis(0.2ms),DB 只承受缓存未命中流量——用 10 台 Redis 省掉 90 台 DB,这就是缓存架构的商业逻辑。

但快有前提,我常提的三条红线:单线程怕慢命令(keys *、smembers 大集合会阻塞所有请求);怕 bigkey(删除与序列化耗时);怕 keyspace 过大导致 fork 停顿。Redis 的快是"保持简单动作"的快,把它当数据库用复杂查询,就是把保时捷开成拖拉机。

🏗 系统架构师 ​

Redis 快是全链路设计的结果,我归纳六个因素:

  1. 纯内存操作:数据全在内存,读写在百纳秒到微秒级,比磁盘数据库快 2~3 个量级——这是根本;
  2. 单线程命令执行:无锁、无线程上下文切换,无竞争开销,也避免多线程 cache miss;
  3. IO 多路复用:epoll + 事件驱动(自带 ae 事件库),单线程也能支撑几万到十万级 QPS;
  4. 高效数据结构:SDS(O(1) 取长度、二进制安全、预分配)、跳表、ziplist/listpack、intset,按数据规模自适应编码,小对象紧凑存储省内存;
  5. 单线程内的简单模型:每个命令 O(1) 或 O(logN),无慢路径;
  6. 自己实现 VM 替代系统调用路径优化(历史)、6.0 的多线程 IO 仅用于读写 socket 与协议解析,命令执行仍单线程,保序同时把网络 IO 并行化。

性能量级:单节点 10 万 QPS 常态,pipeline/批量可到百万级 ops。

架构提醒:单线程意味着一个慢命令(keys *、大 key 的 del、复杂 Lua)会阻塞全部请求,这是我做 Redis 治理的第一红线——禁用阻塞命令、大 key 拆分、删除用 unlink 异步化。

💻 全栈开发专家 ​

快的原因是一组组合拳,每一项都可对应到架构决策:

  1. 纯内存操作:读写在内存完成,比磁盘 DB 快 2~3 个数量级,这是根基。
  2. 单线程命令执行:没有锁竞争、没有线程上下文切换,实现简单还规避了并发bug。之所以敢单线程,是因为瓶颈在内存和网络带宽而不在 CPU。
  3. IO 多路复用(epoll):单线程监听几万个连接,事件驱动非阻塞,和 Nginx 同一思路。
  4. 高效数据结构:SDS(O(1) 取长度、预分配)、ziplist/listpack(小集合省内存紧凑存储)、skiplist(有序集合 O(logN) 且范围查询友好)、intset 小整数集合——按数据特征自适应编码,内存和速度双优。
  5. 6.0 多线程 IO:网络读写、协议解析卸载到 IO 线程池,命令执行仍单线程——解决高 QPS 大 value 场景网卡软中断打满单核的问题。io-threads: 4 开启,CPU 密集的命令(大 key 操作)无收益。

实践佐证:单节点简单命令 10w+ QPS 轻松达到;我压测 pipeline 后到百万级——这也说明RTT 才是常被忽略的瓶颈,能批量就批量。反过来,慢查询(keys *、大 key 操作)会卡住唯一执行线程,这是 Redis 稳定性第一军规。