现象:大Key导致Redis实例CPU 100%,系统阻塞。
追问:为什么一个Key会阻塞整个Redis?
本质:这是 Redis 单线程事件循环模型 + 大Key操作耗时巨大的必然结果。
一:Redis单线程模型与大Key阻塞
1,Redis是单线程的:核心处理(网络 I/O、命令解析、执行、数据序列化、响应发送)只有一个主线程。
2,大Key是耗时的:一个大Key如10MB的String或含10万元素的Hash)在执行HGETALL时,需要遍历所有元素并进行序列化,耗时可达数百毫秒甚至秒级。
3,阻塞效应:在这数百毫秒内,Redis主线程被这个命令完全占满。任何其他请求(哪怕是PING命令)都无法被处理,只能排队等待。
结论:一个大Key,阻塞整个Redis实例,所有请求到该实例的请求都会阻塞。所以redis大key的杀伤面积超级大,绝对禁止。
二:深入理解"耗时"的组成
耗时主要在三步:
1,内存遍历:遍历大Hash里的10万个field。这是内存访问,相对较快。
2,数据序列化:这是真正的CPU密集区。Redis需要把内存中散落的、私有的数据结构,转换成RESP这种客户端通用的网络传输格式。这包含大量整数转字符串、字符串拼接、内存分配与拷贝等操作。
3,系统调用与数据搬运:
write() 调用:主线程将序列化好的数据(在Redis进程的用户态内存),通过系统调用write,拷贝到内核的Socket发送缓冲区。这一步需要CPU参与,是阻塞的。
DMA 搬运:随后,DMA控制器会"接手",将数据从内核缓冲区搬运到网卡。这一步不占用CPU,主线程此时已可以处理新请求。
网络传输:网卡将数据拆分成最大1460字节的 MSS 包("数据卡车"),通过网络发送给客户端。这是最慢的一环。
三:CPU、内存、I/O 与锁的横向对比
1,速度层级 (纳秒到毫秒):
L1 缓存 ≈ 1 纳秒
内存 (RAM) ≈ 100 纳秒
本地 NVMe SSD ≈ 10 微秒 (10,000 纳秒)
同机房网络 ≈ 100 微秒 (100,000 纳秒)
机械硬盘 (HDD) ≈ 10 毫秒 (10,000,000 纳秒)
跨地域网络 ≈ 100+ 毫秒
2,I/O的本质:就是数据搬运。从内存搬到网卡是"输出",从网卡搬到内存是"输入"。所以叫 I/O (Input/Output)。
数据库为什么慢? 两个主要原因:
磁盘 I/O:为保证数据持久化,最终必须写入磁盘(即使是相对更快的 SSD)。
锁竞争:在高并发写的场景(如秒杀),多线程争夺行锁导致的等待,有时比磁盘 I/O 更致命。
Redis 为什么快?
纯内存:绕过了最慢的磁盘 I/O。
单线程 + 原子操作:从根本上避免了锁竞争。没有锁,就没有锁等待、死锁等问题。