面试官不会因为你会背“Redis是单线程”就满意也不会因为你报出“开slowlog”就点头。他真正想听的是你面对一个真实线上故障时脑子里有没有一套清晰的排查路径。这篇文章我就用“简历写了高并发、结果被追问Redis CPU飙升”这个场景把原理、排查链路、回答话术、简历写法一次讲透。1. 面试官问“Redis CPU 飙升”时到底想从你嘴里听到什么1.1 从“高并发”到“Redis CPU 高”一条经典的追问链先说个我面试时经常遇到的画面。候选人简历上赫然写着“支撑高并发系统”项目描述里堆了一串“Redis缓存、消息队列、分库分表”。于是我从最轻的问题开始你们这个系统QPS大概多少Redis在链路里承担什么角色有没有遇到过缓存导致的故障很多候选人到这里就开始含糊了尤其当我追问“线上Redis CPU飙到100%你怎么定位”的时候对面往往有两种反应。第一种是愣住因为他简历里的“高并发”是从项目文档里抄来的形容词没有对应任何真实场景。第二种是立刻开始背题嘴里蹦出“大key、热key、慢查询”这几个词但问他“你怎么通过命令确认是大key”“大key会从哪几个维度拖垮CPU”又答不上细节。面试官问这道题其实有个很明确的逻辑链简历说高并发 - 高并发系统离不开缓存 - 缓存扛不住的表现之一就是CPU飙升 - 面试官想确认你有没有真的在高流量下处理过问题。所以CPU飙升只是表象他真正想考察的是三件事你有没有处理过真实故障的经验你懂不懂Redis的底层执行模型以及你排查问题时是背命令还是有完整的方法论。1.2 背答案和真排障的区别几句话就能看出来背过面经的人回答CPU飙升通常会直接说“查大key、开慢日志、用scan替代keys”。这些说法没错但一听就是没踩过坑的人在背书。因为真实的排查顺序永远不是从“查大key”开始的而是从“确认现象范围”开始的。我举个例子。线上告警说某台Redis CPU高有经验的人开口第一句一定是描述边界是整机CPU高还是Redis进程高是单核打满还是多核都高从什么时候开始的持续时间多久当时在跑什么业务。因为这三个方向的排查重点是完全不同的一套工具链。单核打满大概率指向命令执行慢或热key多核都高更可能是连接风暴、子进程fork、或者MONITOR这类命令被开着如果是子进程CPU高那基本就是RDB或AOF rewrite引起的。这一句话的差别面试官立刻就能判断你是背题还是有实战。背题的人脑子里装的是“答案”排过障的人脑子里装的是“决策树”。所以这篇文章我不打算只教你“CPU飙升怎么查”而是把从现象到根因的整个判断链路拆给你看顺便聊聊怎么把这些经验收进简历里让“高并发”三个字经得起追问。2. 先补底层共识单线程模型和“Redis 不该吃 CPU”的认知偏差2.1 Redis 单线程为什么快以及它和 CPU 升高有什么关系要聊CPU飙升得先搞清楚Redis的执行模型。很多候选人知道Redis是单线程但会把“单线程”理解成“Redis不可能CPU高”这是一个很危险的认知偏差。Redis单线程指的是核心命令执行逻辑只有一个线程。它快的原因主要有三个第一绝大部分数据都存在内存里内存操作本身是纳秒级别的第二常用命令比如GET、SET都是O(1)或者接近O(1)的复杂度单线程顺序执行没有锁竞争开销第三它用IO多路复用Linux下是epoll管理成千上万个客户端连接而不是一个连接一个线程所以线程切换代价极小。但“单线程快”不意味着“单线程不会CPU高”。恰恰相反单线程模型意味着一个Redis实例最多只能把一个物理核跑满其他核大概率是闲着或者低负载的。所以你用top看到进程整体CPU占用只有20%不代表没有问题。你得按1看每核负载或者用pidstat -p redis_pid 1看线程级CPU占用。如果是某个线程长期在80%-100%那说明Redis的主线程已经接近瓶颈所有命令都在排队延迟会像坐过山车一样往上飙。换句话说CPU飙升这个问题在Redis身上有两种完全不同的表现形态机器层面看是多核打满还是单核打满线程层面看是主线程高还是子进程高。面试中主动把这个区分讲出来已经能刷掉一大批只会背八股的人。2.2 6.0 引入多线程后CPU 模型发生了哪些变化还有一个进阶知识点很多人没有意识到。Redis 6.0之前网络读写和命令执行全在单线程里完成所以压榨CPU的手段基本是“多开实例”或者“上集群”。6.0引入了IO多线程把socket的读、写、协议解析这些活儿从主线程拆出来交给你配置的IO线程池但命令的实际执行仍然在主线程。这就带来一个面试官很可能设陷阱的点你说“Redis是单线程所以CPU高跟我们没关系”这是错的你说“Redis已经支持多线程了所以CPU高很正常”这也是片面的。准确的说法是Redis 6.0以后CPU占用中有一部分来自IO线程但命令执行的瓶颈仍卡在主线程的CPU上。我在实际排障里见过有人一看到CPU高就去调io-threads结果调完CPU更高了。因为IO多线程不是默认开启的需要同时配置io-threads和io-threads-do-reads yes并且只有实例的吞吐量达到一定量级才有收益。对大多数业务盲开反而因为锁和内存同步增加CPU开销。所以面试时主动提一句“具体问题要结合实例规格和版本判断”比简单下结论要专业得多。3. 真实排障顺序从慢日志、命令统计到 bigkey 扫描的完整链路3.1 先确定现象范围单核高、整体高、还是子进程高我在生产环境排查过不少次Redis CPU高经验告诉我开始的15分钟决定排查效率。什么都没确认就开MONITOR或者跑--bigkeys等于在火上浇油。第一步永远是收集现象而且是低风险的信息收集。先上top -Hp redis_pid看线程状态。如果是redis-server主线程单核高重点查命令执行和热key如果是redis-server下面的fork子进程或者RDB/AOF子进程CPU高重点查持久化配置和内存量如果Redis进程本身CPU不高但sys占比很高重点查上下文切换、网络中断和连接数。这一步能非常快速地把问题从一大片可能性收敛到两三条主线。同时问自己三个问题这个实例平时CPU是多少现在飙到多少是持续还是抖动当时线上在做什么变更大促扩容、缓存预热脚本、新版本发布、某个新业务接入任何一种变更都可能解释CPU变化。排障不是玄学先基于变更猜根因再用工具验证这比我见过的“上来就乱试”要高效得多。3.2 从慢日志到命令统计定位命令级瓶颈的标准动作确认现象方向之后按照侵入性从低到高的顺序我一般这么走第一步看INFO commandstats。这个命令能输出每个命令的调用次数和总耗时我拿它算“某个命令的平均耗时/调用次数”能非常直观地看到哪些命令是CPU消耗大户。有一次我发现某个实例SMEMBERS每秒调用几百次每次平均耗时几十毫秒顺着代码一查是有人拿Redis当数据库存全量用户关系每次都全量拉取。第二步看SLOWLOG GET。默认慢日志阈值是10毫秒超过就算慢命令。但很多人忽略了一个问题默认阈值太宽那些“单条不慢但量巨大”的命令根本不会进慢日志。比如一个命令平常0.1毫秒QPS十万把CPU吃满了可slowlog一条都抓不到。所以遇到CPU高的时候我建议临时把阈值调低比如CONFIG SET slowlog-log-slower-than 1000单位微秒也就是1毫秒抓几分钟再调回来。这算是个线上排障的常用操作面试提到会很有说服力。第三步当怀疑大key或热key的时候用redis-cli --bigkeys和redis-cli --hotkeys做采样扫描。需要特别注意的是这两个命令会遍历整个keyspace对线上实例有性能影响我从来只选业务低峰期跑而且会加-i 0.1这样的休眠参数限速。--hotkeys还有一个前置条件内存淘汰策略必须是allkeys-lfu或volatile-lfu否则命令直接不工作。这个细节我在面试中提过一次面试官明显眼神亮了一下。3.3 高频根因对照表大 key、热 key、持久化、碎片、连接下面这张表是我在多个项目里验证过的根因对照拿出来可以直接参考。现象特征最可能根因核心定位命令/指标紧急处置思路主线程单核100%延迟飙升热key或复杂命令INFO commandstats、--hotkeys客户端本地缓存、热key副本、限流降级单个实例某分片CPU高热key在单分片上cluster info、--hotkeys热点key加后缀打散到多分片大key导致网络和序列化高大key读写或删除阻塞--bigkeys、DEBUG OBJECTvalue拆分、渐进删除UNLINK子进程CPU高、主线程卡顿RDB fork / AOF rewriteINFO persistence里的fork耗时错峰持久化、控制内存上限整体CPU高且sys占比大连接风暴、短连接多CLIENT LIST、sar -w强制连接池、调tcp参数CPU高伴随内存碎片率高activedefrag不断整理INFO memory的mem_fragmentation_ratio低峰重启或调碎片整理参数先说大key。一个包含几十万元素的hash执行一次HGETALL内存里要拷贝整份数据、序列化、塞进socket缓冲区这个动作本身消耗的CPU是普通GET的几十上百倍。更糟糕的是删除大key时2.x和3.x版本的DEL是同步阻塞的一个几MB的key删除过程可能阻塞主线程几百毫秒期间所有请求排队。所以我会把“大key”和“CPU高”同时讲而不是只当两个独立问题。再讲热key。Redis单实例单线程再快的命令也架不住单key流量过高。典型场景是秒杀品的库存key或者某条热点新闻的聚合缓存所有流量打到一个分片一个key上那个分片CPU立刻打满其他分片却闲着。加副本不一定有用因为读流量可以走副本但写流量和部分读场景还是压在主分片上。持久化这块容易被忽略。RDB做快照时fork()子进程fork瞬间要复制父进程的页表内存越大耗时越长一个10GB实例的fork可能让主线程停顿几百毫秒到一秒。而且fork出来的子进程做内存拷贝也要吃CPU你会在top里看到两个CPU很高的进程。AOF rewrite同理。检查INFO persistence里的rdb_last_fork_usec如果这个值非常大基本就是fork拖累CPU的实锤。内存碎片整理也是隐藏的CPU消耗点。Redis 4.0之后有activedefrag功能开启后它会定期搬运内存碎片这个搬运过程十分消耗CPU。我曾经在内存碎片率高的时候开了activedefrag结果CPU反而比不开时更高最后只能安排在低峰期重启实例来释放内存。连接层面很多团队没用连接池或者连接池设置得过大每次请求都新建连接。虽然Redis处理握手很快但高并发短连接会让操作系统陷入大量的上下文切换和中断处理CPU的sys占比显著升高。这类问题从Redis命令耗时上可能看不出来因为单条命令确实很快但整机CPU就是在涨。排查时看一眼CLIENT LIST里的连接数和info clients里的connected_clients再结合vmstat看上下文切换数基本就有答案。还有个容易翻车的点线上开着MONITOR。MONITOR的作用是把所有命令实时打印只要开着Redis的CPU使用率会大幅上涨很多时候是排查事故时被人开着忘记关结果CPU越查越高。我在面试里会主动提这个坑它能证明我确实在线上摔过跤。4. 回答话术拆解把一次 CPU 飙高讲成有头有尾的排查故事4.1 一个可以直接套用的回答框架面试和写代码一样先搭框架再填细节。我给候选人建议的框架是五段式确认现象 - 收敛范围 - 定位根因 - 处置方案 - 复盘改进。不要一上来就说“查大key”而是先让面试官知道你有全局视角。口头回答大概是这种感觉“我先确认现象边界是单核还是多核是Redis进程高还是机器整体高持续时间多久期间有什么变更。然后我会用最小侵入方式定位先看INFO里的命令统计和慢日志临时把慢日志阈值调低抓出那些量大但不算慢的命令再配合bigkeys和hotkeys扫描。确认根因之后分两步处理紧急措施保证业务先恢复比如临时限流、本地缓存、变更淘汰策略长期措施才是优化命令、拆分key、调整持久化配置。收尾我一定会做两件事一个是把处置动作和效果记录成文档另一个是补监控告警避免下次再被动发现。”这段话本身没有太高深的技术但它的结构是完整的。面试官听到的是“我知道先干嘛、再干嘛、为什么这么干”而不是“我背过一个命令清单”。4.2 被追问“你怎么证明是这个原因”时的应对面试官不会满足于答案他还会问“你为什么判定是大key而不是热key”“你怎么证明改了配置CPU就降下来了”。这种追问考验的是你的证据链意识。我建议你用“对比实验”来回应。比如判定是大key不是因为--bigkeys扫出来了就完事而是你会去业务代码里确认是哪个接口触发了对大key的读然后压测这个接口断开它再对比CPU或者把慢日志阈值调低后统计某类命令的耗时占比。判定是fork导致CPU高你会看fork耗时和内存峰值的对应关系比如内存从2G涨到8Gfork时间从30ms涨到200ms这种线性关系就是证据。判定是碎片整理导致CPU高最直接的办法就是CONFIG SET activedefrag no观察CPU是否回落但这属于线上变更得走审批和低峰期操作。记住一个原则不要抛结论抛“你是怎么确认这个结论是对的”。面试官要的不是你猜中了结果而是你验证结果的过程。4.3 几种常见追问的加分回答方式围绕Redis CPU飙升面试官有一组高频追问提前准备好能省不少尴尬。第一个追问“你们Redis CPU高的时候QPS是多少”加分回答不是报一个数字而是把数字串成上下文比如“当时集群32个分片单实例QPS大概3万命中率在95%左右已经接近单实例单线程的天花板CPU打满的接口是订单详情缓存单次读需要组装十几段字符串”。这样回答既说明你清楚容量边界也说明你知道为什么打满。第二个追问“redis是单线程你为什么不多加几台机器”加分回答是“如果瓶颈在单条命令执行慢或者热key集中在一个分片加机器也解决不了因为流量还是会打到同一个key上。要么把热key拆开要么做客户端本地缓存要么利用多副本读。单纯加机器只对整体容量扩容有意义对单key瓶颈没用”。第三个追问“CPU高为什么不直接重启”加分回答是“重启只能临时清掉CPU如果根因是慢命令或热key刚起来很快又会打满。而且重启大实例时如果配置了AOF恢复阶段本身就会造成CPU和磁盘双高如果是大key数据加载也会触发延迟。除非是内存碎片这类无法在线解决的问题我会选低峰期通过主从切换的方式重建实例而不是直接重启”。第四个追问“AOF rewrite不可能导致主线程CPU高吧”这时你可以解释rewrite是子进程在做但fork瞬间主线程要复制页表内存越大越卡而且重写期间如果有大量写请求父子进程之间会有内存共享和写时复制的开销整体CPU必然会涨。能讲到这一层已经超过大多数候选人了。5. 回到简历用 Redis CPU 这个案例反向审视“高并发”三个字5.1 “高并发”写进简历之前先准备好三个数字我必须说句得罪人的话简历里写“高并发”却讲不出数字等于简历造假。因为高并发是个相对概念一个只有十个用户的管理系统也可以自称高并发面试官只能通过量化指标来判断真实性。至少准备三组经得起追问的数字业务流量峰值多少Redis实例规模多大分片数、内存量、QPS出现CPU高问题时关键指标是怎么变化的。我见过一个不错的写法是“用户增长引擎日请求峰值5000万QPSRedis集群64分片单实例承载近5万QPS大促期间热key命中单分片导致CPU飙至95%通过热点key拆分和本地缓存将峰值CPU压到40%。”数字和方案都很具体面试官想不感兴趣都难。反面写法什么样呢只写“使用Redis提升系统并发能力解决高并发问题”没数字、没场景、没结果。这种描述在面试官眼里等于没写反而还会引来灵魂拷问“你们Redis怎么提升并发”。记住简历里每一个技术名词最好都能对应一个真实场景。5.2 把“Redis CPU 飙升”整理成一个 mini case 写进项目如果你真实遇到过CPU飙升问题我建议别把它琐碎地写在项目背景里而是单独提炼成项目描述中的一个“重点难点解决方案”条目。我自己整理过一个标准句式可以照着填“项目在某次促销活动中订单查询接口的Redis CPU飙升至90%以上接口整体RT从10ms涨到300ms。定位过程通过INFO命令统计发现HGETALL调用量异常增长配合bigkeys扫描确认存在百万级字段的大key。优化方案将大key按用户维度拆分为小key增加客户端多级缓存同时将DEL改为UNLINK渐进删除避免阻塞主线程。上线后单分片CPU峰值降至35%接口RT稳定在15ms以内。”这种写法的好处是面试官看到的不是一个形容词而是一套完整的故障闭环什么问题、怎么定位、怎么解决、量化效果。面试时被追问CPU飙升你完全可以把这个case原封不动地讲出来这就是你的真实素材。5.3 真没做过高并发怎么讲才不减分我知道有一部分读者确实没在真实高流量环境待过简历上的“高并发”是项目需要或者自己包装的。我的建议是不要造假因为面试官针对数字连续追问三轮以上你没有真实经历很容易穿帮。没做过生产环境的高并发不等于不能展示能力。你可以做一个“仿真演练”自己搭一套主从Redis用压测工具模拟热key和大key场景复现CPU飙高的报警然后把排查过程写成技术笔记。面试时说清楚“这是我搭建的实验环境做的故障演练但我完整地走了一遍从监控告警到定位再到处置的链路”这样的诚实表达反而加分。因为它证明你在没有生产压力的情况下主动去研究过这个问题这是很强的自驱力信号。另一种更好的方式是在你现有项目里找一个局部低配版的“并发问题”。比如虽然整体QPS不高但某个接口出现过Redis连接池耗尽、或者某条命令执行特别慢你就可以把这个小问题放大去讲排查思路同样能体现能力。面试官看的是你是否具备解决问题的思维而不一定是流量规模。最后分享一点我个人的经验每次带新人我让他们做的第一件事不是背Redis面试题而是开着慢日志和命令统计去盯一个真实实例的CPU曲线然后自己回答“如果CPU现在飙了我下一步该看什么”。这套思路练熟了比背二十个面经都管用。回到简历上的“高并发”三个字它从来不是荣誉而是一份承诺——承诺你配得上在那种流量下解决问题。Redis CPU飙升这道题就是这个承诺最好的试金石。
阅读完成 · 觉得有帮助?