
百度2018校招核心系统工程师笔试题提前批一场裸考失败后我复盘出的备考清单先说个背景。我是2018届的当年投的百度核心系统工程师岗位走的是提前批。提前批和正式批最不一样的地方在于——它没有给你太多“找感觉”的机会。我印象很深当时临近开考才意识到自己完全没准备这个岗位的专项内容硬着头皮裸考了一把结果自然不太好看。不过考完之后我把能记住的题目和考察点全量复盘了一遍对照自己后续补课的内容和实际工作中遇到的知识点整理了一篇完整的备考笔记。这篇复盘现在回头看它的价值反而不在于“押题”——毕竟每一年的笔试题型都会微调考查方向也会跟着业务变化——而在于它帮我梳理出了“核心系统工程师”这个岗位到底在考什么、为什么考这些、以及怎么准备才不会跑偏。所以这篇博文我打算从考题本身出发把题目背后的知识点掰开揉碎讲清楚再附上我踩过的坑和总结出来的复习路径。无论你是准备投百度还是打算投其他大厂的基础架构、系统研发、SRE方向这篇复盘都应该能给你一个相对完整的参考框架。1. 先看考试全貌这套题在测什么能力提前批的笔试时间一般是90分钟到120分钟题量不小核心系统工程师的卷子整体风格偏底层、偏系统、偏实战和普通的后端开发工程师笔试有明显区别。普通后端岗可能以算法题、数据库题、业务场景题为主而核心系统工程师会更关注你对操作系统、网络、存储、Linux内核、高并发架构这些底层模块的理解深度。我根据自己的回忆把当年的考点归了几大类基本可以用下面这个表概括考试模块考察重点典型题目方向占比预估计算机基础操作系统、内存管理、进程线程、锁死锁条件、虚拟内存、上下文切换开销30%网络与分布式TCP/IP、HTTP、负载均衡、一致性TCP握手细节、分布式缓存一致性25%Linux与系统编程Shell、系统调用、性能调优、容器线上故障排查命令、CPU飙高排查25%算法与代码数据结构、手写代码TopK、字符串处理、LRU20%这个比例不是官方数据是我自己做题时的体感。但它的分布说明了一个核心逻辑核心系统工程师本质上是在“靠近基础设施”的岗位上工作你必须对一个请求从进入到返回的每一条链路都有清晰的认知还必须能动手处理真实环境里的故障。所以笔试不是在考你会不会写业务接口而是在考你有没有“往底层钻”的潜力。这里多说一句提前批的难度通常高于正式批因为提前批的目标是筛选“头部候选人”所以题目会更偏原理性、思考性而死记硬背的内容相对少。如果你提前批没过不代表你不行只说明你和这个岗位的匹配还需要再打磨。这是很现实的。2. 操作系统题看起来在考概念实际上考“你有没有真用过”操作系统是重头戏。当年卷子里操作系统相关的题多到让我一度怀疑自己在考系统程序员而不是校招生。这里我把印象最深的几个考点列出来每个我都会补充“为什么考”和“怎么答才不踩坑”。2.1 虚拟内存与页面置换别只背LRU要理解开销从哪里来有一道题问的是“虚拟内存的作用是什么页面置换算法有哪些LRU的缺点是什么”。前两问属于送分题背过书的人都能答上。但第三问“缺点是什么”通常是拉开差距的地方。很多人的回答是“LRU需要维护访问顺序开销大。”这话没错但不够。如果我是面试官我更希望听到这样的表述LRU在理论上是最接近最优置换算法OPT的实用策略因为它利用了局部性原理。但在实际实现中它面临两个核心问题一是需要为每个页面记录最近访问时间这本身需要额外的硬件支持和数据结构维护开销比如用链表或栈实现时每次访问都可能触发节点移动二是在多核CPU环境下LRU的状态维护需要处理并发访问这会引入锁竞争和缓存一致性开销。我当时在卷面上补充了一个点现代操作系统里很多时候用的是近似LRU的算法比如Clock算法二次机会算法它用一个引用位来代表“最近是否被访问过”用循环扫描的方式来近似LRU的效果牺牲一定的命中率换来更低的实现开销。这个补充在我的复盘里被认为是加分的因为它体现出“我知道理论和工程实现之间有差距”。再延展一点页面置换算法的选择本质上是“命中率”和“开销”之间的权衡。TLB缺失、缺页中断、磁盘I/O这些的代价从纳秒到毫秒不等跨度极大。笔试时如果能把这个量级差异写出来会显得你理解非常到位。2.2 进程与线程问到“为什么线程切换比进程切换快”时警惕陷阱有一道题是“进程和线程的区别为什么线程上下文切换比进程上下文切换开销小”。这道题经典到不能再经典但经典题恰恰容易出问题。很多人第一反应是“因为线程不拥有独立地址空间共享进程的地址空间所以切换时不涉及地址空间的切换”。这句话是对的但不完整。完整的答案应该覆盖两个层面第一地址空间切换确实是主要开销来源之一。进程切换需要切换页表基址CR3寄存器、刷新TLB而TLB刷新后会导致后续内存访问出现大量miss这是进程切换中最大的性能惩罚之一。线程切换不涉及这一步同进程内自然开销小。第二进程和线程在内核里的调度实体不同。现代Linux中线程和进程都统一为task_struct线程本质上是“轻量级进程LWP”但进程切换与线程切换在内核态的流程差别其实不大——它们都要保存寄存器上下文、栈指针、程序计数器等。所以严格来说线程切换快的原因主要是“不需要刷新地址空间相关状态”而不是“免去了内核态切换”。我当年答题时画了一个对比表格把进程切换和线程切换的具体开销来源列清楚。这个方法后来我把经验分享给了不少学弟学妹遇到比较类题目先列维度再填答案结构清晰阅卷人也容易找到你的得分点。2.3 死锁四个必要条件 实际工程中的处理思路死锁这道题是标准考点。考法通常是“死锁产生的条件是什么举例说明如何避免”。四个必要条件——互斥、持有并等待、不可剥夺、循环等待——这是必背内容。但真正的加分项在于你能否说明“实际工程中如何破坏这些条件”。举几个例子破坏“持有并等待”一次性申请所有资源一次性分配但这种方法在资源种类多、占用时间长的场景下会导致资源利用率急剧下降。破坏“不可剥夺”当进程无法获取新资源时主动释放已持有的资源。这在数据库事务里很常见比如死锁检测后强制回滚某个事务。破坏“循环等待”对资源类型进行线性排序所有进程必须按编号递增的顺序申请资源。这在很多底层锁设计里都有变体应用。我当年笔试时还在答案里加了一个和业务场景结合的例子多线程并发更新不同表记录时如果两个事务各自持有一把锁并等待对方的锁就很容易形成循环等待从而触发数据库死锁。常见的解法是约定所有事务按同一张表的顺序加锁或者设置锁超时时间。这样答的好处是把“会背概念”提升到“能落地解决问题”的层面而这正是核心系统工程师岗位需要的能力。2.4 并发与锁从自旋锁到读写锁的选型逻辑有一道题问的是“多线程并发访问共享变量时有哪些同步手段简述各种锁的适用场景”。这类题如果只是罗列“互斥锁、自旋锁、读写锁、乐观锁、悲观锁”那只能拿基础分。要拿高分必须体现出“选型逻辑”。我给一个框架也是我后来复习时反复使用的思路互斥锁Mutex适合临界区操作耗时较长的场景线程在拿不到锁时让出CPU避免忙等浪费。自旋锁Spinlock适合临界区极短的场景比如内核中某些数据结构保护。因为线程拿不到锁时会原地自旋等待时间短时开销远小于线程切换。读写锁RWLock适合读多写少的场景比如配置表、路由表的读取。但写锁饥饿问题需要关注可以通过“写优先”策略避免。乐观锁CAS适合冲突很少的场景比如计数器累加。CAS是CPU指令级别的原子操作不需要进入内核态效率高但在高冲突下会导致大量自旋重试。悲观锁数据库行锁适合数据冲突概率高的场景比如电商库存扣减。我当时在卷子上写了一个特别典型的例子在C中实现一个线程安全的计数器用std::atomicint和CAS循环来实现比用std::mutex快得多。这种“我会用我知道为什么”的答案比纯理论堆砌要有说服力得多。这里补充一个我的体感校招笔试并不期望你写出多么精妙的并发代码但你需要证明自己理解锁的本质——锁的本质是把并发问题串行化任何锁都有代价工程上要尽量缩小临界区、减少锁粒度而不是无脑加锁。3. 网络与分布式系统题每道题都像是从线上故障报告里抽出来的第二大类让我印象深刻的是网络与分布式方向的题。百度这种体量的公司核心系统一定面临海量请求、跨机房部署、数据一致性这些现实问题。笔试题目看起来在考网络协议实际上在考你有没有“系统排查过线上问题”的意识。3.1 TCP三次握手与四次挥手必考题但细节能拉开差距TCP连接管理几乎是所有校招笔试的保留节目。核心系统工程师的卷子里它不只是问“三次握手是什么”还会深入问“为什么TIME_WAIT状态需要等待2MSL”这个问题很经典。2MSLMaximum Segment Lifetime是为了保证最后一个ACK如果丢失对端会重发FIN而本端必须还在监听状态才能重新发送ACK同时防止旧连接上的延迟报文段干扰新连接。2MSL是“报文段最大生存时间”的两倍确保一个方向上的报文段在网络中完全消失。这里有个实际应用场景我在笔试前刚遇到过大量短连接服务在关闭时会出现大量TIME_WAIT状态的socket这会导致本地端口耗尽或内存占用过高。排查线上问题时会用ss -s或netstat -s看TIME_WAIT数量如果数量异常通常会考虑调整tcp_tw_reuse、tcp_fin_timeout等参数。但要注意tcp_tw_reuse只在客户端场景下安全在服务端场景下需要谨慎因为它可能导致旧连接数据串扰到新连接上。这种题目如果你只是把书上的图解画出来只能证明你背过。但如果你能进一步解释“为什么主动关闭方要进入TIME_WAIT而不是直接CLOSED”再结合线上调优经验那说明你真的能解决实际问题。3.2 HTTP与RPC协议选择的底层逻辑还考了HTTP/1.1和HTTP/2的差异、RPC框架的基本原理。这部分的考察重点不是让你背RFC而是看你能否理解协议设计背后的性能和可靠性考量。我记得有一道题是“HTTP/2相比HTTP/1.1有哪些改进为什么这些改进对性能有帮助”标准答案是多路复用解决了队头阻塞、头部压缩HPACK、二进制分帧减少了解析开销、服务端推送。但这里有一个容易被忽视的细节HTTP/2的多路复用是在同一个TCP连接上并发处理多个流但如果TCP层发生丢包因为TCP的全局重传机制所有流都会被阻塞——这就是HTTP/2的队头阻塞问题仍然存在的根本原因。这也是后来HTTP/3选择基于UDP的QUIC协议的核心动机之一。我在答这道题时提到了HTTP/3/QUIC并简单解释了它如何通过独立流乱序交付来解决TCP层的队头阻塞问题。虽然2018年的时候HTTP/3还在早期阶段但这种“向前看”的知识储备会给面试官留下“这个候选人对技术有好奇心”的印象。3.3 负载均衡与一致性和业务强相关的场景题有一道题是“设计一个高可用的负载均衡系统需要考虑哪些因素”。这道题很开放但也很能暴露一个人的工程视野。我的回答框架是接入层通过DNS轮询/智能DNS把流量分发到多个机房四层LB如LVS/F5基于IP端口转发性能高不解析应用层协议负责漂移和故障摘除。七层LB如Nginx/HAProxy基于HTTP/HTTPS内容进行路由支持路径、Header、Cookie等更细粒度的分发策略还可以做SSL卸载、gzip压缩等。健康检查不能只做“端口通不通”的检测还需要做应用层健康检查比如探测某个HTTP接口的返回值。否则可能出现“后端进程还在但已经无法处理请求”的假活状态。一致性哈希在处理缓存类请求时需要把相同key的请求固定转发到同一台后端否则缓存命中率会暴跌。这可以通过一致性哈希环实现它能在节点增减时尽量减少需要迁移的key数量。这类开放题没有标准答案但考察的是你的系统设计思路是否完整。我当时答题时还补充了一个细节负载均衡器本身要避免成为单点所以通常采用主备模式或集群模式并使用keepalived实现VIP漂移。如果连“负载均衡器自己挂了怎么办”都没考虑到那这道题基本拿不到高分。3.4 分布式一致性从CAP到Raft分布式系统的一致性题在核心系统工程师的笔试中非常喜欢考。比如“CAP理论中CAP三者为什么不能同时满足请举例说明。”还有“Raft和Paxos的核心思想是什么”CAP解释起来不难——网络分区P发生时如果选择可用性A那不同分区的节点可能在同一时间对同一请求返回不同数据这就无法保证一致性C如果选择一致性C则必须停止服务等待分区恢复这就牺牲了可用性A。真正的难点在于理解实际系统如何在CAP之间做取舍。比如ZooKeeper它其实是一个CP系统在leader选举期间会短暂不可用而Eureka则是一个AP系统它允许各个节点在分区期间继续服务但可能返回过期数据。Redis集群在某些配置下也偏向AP因为主从切换时可能丢失少量写数据。我当时还写了Raft的几个关键设计leader选举、日志复制、安全性只允许leader追加日志、多数派投票。对比Paxos来说Raft最大的优势是可理解性——它把一致性问题分解成了相对独立的子问题。这个特点在工程界特别重要因为分布式系统的bug通常出在“人理解错了协议”而不是“协议本身错了”。现在我在实际工作中review分布式相关代码时仍然会用这个框架去思考这个系统在分区的时候是选择C还是A日志复制的多数派是怎么保证的节点故障后如何恢复这些问题在校招笔试里就是一道题但在工作里就是每一次线上事故的根源。4. Linux与系统编程题纸上谈兵和真正上手一眼就能看出来核心系统工程师和普通后端不一样的地方在Linux与系统编程这部分体现得淋漓尽致。普通后端可能只会考“说几个Linux常用命令”而核心系统工程师会直接给你一个线上故障场景问你怎么排查、怎么处理。4.1 线上故障排查从“CPU飙高”到“找出元凶”有一道场景题我印象非常深大意是“一台线上服务器CPU使用率突然飙高到100%可能是什么原因你如何排查”这道题考察的就是你是否有真实的线上运维经验。我的标准排查链路是先用top定位是哪个进程或哪个线程在消耗CPU如果是JVM进程用jstack或jstat看线程栈定位是GC线程还是业务线程的问题如果是C/C进程用perf top看热点函数或者用gdb attach看卡在哪个调用栈用vmstat看上下文切换cs列和用户态/内核态CPU占比判断是用户态计算密集还是内核态锁竞争严重如果是锁竞争导致的内核态CPU飙升可以用pidstat -w看线程切换频率再用strace -p跟踪系统调用。这道题拿高分的诀窍是展现“分层排查”的思路——从上到下、从现象到根因而不是一上来就猜。我在卷子上写的是“先看load average的变化趋势再看CPU在user/nice/system/iowait/steal各状态下的分布”然后再往下逐层定位。这个思路后来在工作中帮我解决了不少真实故障可以说笔试复习的收获远不止“应付考试”。4.2 进程与内存free、ps、/proc 的误用陷阱还有一道题问的是“如何查看系统内存使用情况如何判断系统是否内存不足”。很多人第一反应是free -m然后看available列。但这里面有个容易被忽略的点Linux的free输出中used列很大并不代表内存告急因为那包含了page cache文件缓存而这部分内存在内存紧张时会自动回收。真正需要看的是available可用内存——它考虑了可回收的缓存后才是真实的可分配给新进程的内存。更进阶的排查方式是看/proc/meminfo中的关键字段MemAvailable、MemFree、Buffers、Cached、SwapCached。特别是MemAvailable这个字段它是一个估算值比简单用free -m里的free列判断要准确得多。此外如果服务器内存不足系统会启动OOM Killer。这时你可以在/var/log/messages或dmesg里看到内核的OOM日志。OOM Killer的评分逻辑基于oom_score它会优先杀掉占用内存大、进程优先级低的进程。这个机制听起来简单但在真实环境中如果你的数据库进程被OOM Killer干掉了你就知道什么叫“欲哭无泪”。所以我在答题时补充了一句生产环境通常设置vm.overcommit_memory2来禁止内核过度分配内存或者为关键进程设置oom_score_adj来降低被误杀的概率。这些细节是区分“背过命令”和“真的运维过”的试金石。4.3 容器与虚拟化核心系统工程师绕不开的主题2018年的时候容器化已经在国内大厂大规模落地了所以笔试试卷里也出现了和容器相关的题目比如“容器和虚拟机的区别”“Docker的namespace和cgroup有什么作用”。这道题的核心考点在于容器不是“轻量级虚拟机”它是一种“基于内核能力实现的进程隔离技术”。Docker通过namespace实现资源隔离PID、Network、Mount、UTS、IPC通过cgroup实现资源限制CPU、内存、磁盘I/O、网络带宽。我在答题时做了一个对比虚拟机的隔离依赖hypervisor每个VM有完整的客户机操作系统隔离性强但资源开销大容器共享宿主机内核启动快、资源占用低但隔离性弱于VM——同一个内核的漏洞可能影响所有容器。这个“得与失”的对比思路是面试官非常欣赏的。现在回头看这个考点在校招笔试里出现的频率越来越高因为云原生已经是基础设施团队的标配能力。如果你在笔试前还没用过Docker或Kubernetes强烈建议自己搭一套环境实际跑一跑docker run、docker exec这些命令再手动创建一个cgroup来限制一下CPU使用率。纸上得来终觉浅这句话在系统工程师这里特别适用。4.4 系统调用与I/O模型NIO为什么快有一道题是“select、poll、epoll的区别为什么epoll在高并发场景下表现更好”。这道题是Linux网络编程的高频考点核心系统工程师几乎必考。标准答案selectfd数量有限制默认1024每次调用都要把fd集合从用户态拷贝到内核态内核需要线性扫描所有fd判断是否就绪效率低下poll解决了fd数量限制但同样存在用户态到内核态的拷贝、线性扫描的问题epoll通过epoll_ctl注册fd只在注册时拷贝一次通过回调机制内核在fd就绪时主动回调不需要线性扫描epoll_wait只返回就绪的fd效率大幅提升。但这道题如果你只答到这里还是不够。面试官更想听的是“epoll的底层实现机制”——它的核心数据结构是红黑树用于管理注册的fd 就绪链表用于存放触发事件的fd以及它的两种触发模式水平触发LT和边缘触发ET。边缘触发模式必须配合非阻塞I/O使用否则很容易因为漏读数据导致事件不再触发。我当年在笔试时甚至还写了一段伪代码来说明epoll的用法包括epoll_create、epoll_ctl和epoll_wait三个系统调用的配合方式。这种把“概念”和“代码”结合起来的答题习惯在考场上非常加分因为它让阅卷人相信你是真的写过网络编程而不仅仅是背了八股。5. 算法代码题不只是刷LeetCode还要扣住“系统”语境核心系统工程师笔试的最后一部分通常是算法题。说实话这部分题量不算特别大但难度并不低。它考的算法未必有多高深但往往和“系统设计”有关联。5.1 从TopK到LRU系统场景下的经典算法有一道题是“海量数据中找出Top K大的数”这是面试必刷题。但这道题在核心系统工程师的笔试里会多一个背景“有10亿个整数内存只有几百MB如何找出其中最大的100个数”。标准解法是维护一个大小为K的最小堆遍历数据时如果当前数据比堆顶大就替换堆顶并调整堆结构。这样时间复杂度是O(N log K)空间复杂度只有O(K)。如果内存依然不够就需要用分治法把数据切分成多份分别求出每份的TopK再合并。本质上这就是MapReduce的思想——Map阶段局部TopKReduce阶段全局TopK。这种“把大规模问题拆小”的思路后来我在实际处理海量日志时也经常用到。另一道高频题是“实现一个LRU缓存”。这道题之所以高频是因为它在系统设计中非常常见——缓存、页面置换、连接池、限流器都会用到类似数据结构。实现思路是用哈希表双向链表哈希表保证O(1)的查找双向链表保证O(1)的插入和删除。每次访问一个节点时如果命中就把它移到链表头部缓存满了之后淘汰链表尾部的节点。我当时在笔试时用Java手写了LRU并且用LinkedHashMap的accessOrder参数实现了一次。但我也写了一个纯手写的双向链表版本因为面试官问过“你为什么不用LinkedHashMap?”——用集合类方便是方便但如果你不了解底层原理很容易在深挖时露馅。所以我的建议是笔试时可以用语言自带的数据结构提高速度但心里一定要有底层的实现图景。5.2 手写线程安全的单例模式简单题里也有坑有一道题是“手写一个线程安全的单例模式”。这题看起来简单但能完美写对的人比例不高。最简单的写法是双重检查锁DCL加 volatilepublic class Singleton { private static volatile Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance null) { synchronized (Singleton.class) { if (instance null) { instance new Singleton(); } } } return instance; } }这里最重要的是volatile关键字。如果不加volatile由于指令重排instance new Singleton()的“分配内存、初始化对象、引用赋值”三步可能被重排为“分配内存、引用赋值、初始化对象”。如果线程A执行到“引用赋值”但还没“初始化对象”时线程B看到instance不为null直接返回一个未初始化完成的对象就会出问题。volatile禁止了这种重排。经典的枚举单例实现public enum Singleton { INSTANCE; }这种方式既线程安全又防序列化破坏是《Effective Java》里推荐的做法。但如果在笔试里直接写这个有些面试官会觉得过于取巧所以最好两种写法都掌握并根据题目语境选择。这类题考察的本质是并发编程基本功和你写的业务代码质量直接相关。核心系统工程师的日常就是和各种并发、各种状态打交道如果连单例都写不严谨很难让人放心把基础组件交给你维护。5.3 字符串处理不要轻视简单题笔试还考了一道字符串题大概要求是“给定一个字符串找出最长的不含重复字符的子串长度”。这道题是LeetCode第三题的经典变种很多刷过题的人一眼就能认出。我的解法是滑动窗口哈希集合def lengthOfLongestSubstring(s: str) - int: char_set set() left 0 max_len 0 for right in range(len(s)): while s[right] in char_set: char_set.remove(s[left]) left 1 char_set.add(s[right]) max_len max(max_len, right - left 1) return max_len滑动窗口的时间复杂度是O(N)空间复杂度是O(字符集大小)。只要理解了“左指针右移”的逻辑这道题基本不会做错。这类字符串题目本身不难但它在笔试里的意义是测试你的代码基本功边界条件处理空字符串、全重复字符、循环不变式、复杂度的分析能力。很多人在刷题时追求难题却忽略了简单题的“一眼看出正确解”和“写出无bug代码”的能力。而真正的笔试尤其是时间紧张的提前批笔试比的往往是你能否在有限时间内把简单题做得又快又对。6. 备考路线复盘从裸考失败到形成系统化知识体系笔试结束后我复盘了整套卷子意识到自己最核心的问题不是“知识储备不够”而是“没有形成一个系统化的知识网络”。散点式的知识点我多少都见过但在考场的高压环境下它们无法被快速检索和组装。后来我花了很长时间重新搭建了一套完整的备考体系这里分享给后来人。6.1 以“一个请求的生命周期”为线索串联知识点这是一条特别高效的复习主线。想象你在浏览器里输入一个网址到网页完全展示中间涉及了多少核心系统知识DNS解析网络协议、DNS缓存、智能DNS调度TCP连接建立三次握手、TLS握手、连接复用HTTP请求发送HTTP协议、HTTP/2多路复用、代理负载均衡转发四层LB、七层LB、健康检查、一致性哈希Web服务器处理Nginx/Tomcat线程模型、I/O多路复用业务逻辑处理并发编程、锁、缓存、连接池数据存储MySQL索引、Redis持久化、分布式一致性日志与监控日志采集、指标监控、链路追踪连接关闭四次挥手、TIME_WAIT、端口复用。这条线串起来之后你会发现每个知识点都不是孤立的而是整条链路中的一个环节。笔试不管考哪个点你都能从链路上找到它的位置理解它的上下文。这比死记硬背的效率高得多也更能应对综合题和场景题。6.2 建立“原理命令场景”三位一体的笔记法我备考时建立了一个表格笔记法针对每个核心知识点记录三列内容知识点原理命令/工具排查场景CPU负载CFS调度、运行队列top, vmstat, pidstatCPU飙高、load高但CPU低内存管理虚拟内存、page cachefree, /proc/meminfo, dmesgOOM、swap爆满磁盘I/O调度算法、块层iostat, iotop, fioI/O等待高、磁盘慢查询网络连接TCP状态机、TIME_WAITss, netstat, tcpdump连接耗尽、端口耗尽这个表格帮我建立了“从知识到工具、从工具到场景”的思考习惯。笔试的时候看到任何一道题我都会不自觉地在脑海里过一遍这三列答题的深度和准确度都会有显著提升。6.3 动手实践没有真实系统也要自己造真实场景很多人复习系统知识时会陷入“只看书、不动手”的误区。但实际上核心系统工程师是一个极其看重动手能力的岗位你读一百遍epoll的原理不如亲自写一个echo server来感受它的行为差异。我当时给自己设计了一组实验这组实验后来也推荐给了很多学弟学妹实验1写一个简单的HTTP服务器分别用单线程阻塞I/O和多线程/select/epoll实现用abApache Bench压测对比QPS和延迟实验2在Linux里创建两个进程一个持续读写文件另一个做CPU密集型计算用iostat和top观察系统资源的分配实验3用Docker启动一个容器手动限制它的CPU和内存配额然后在容器里跑一个stress程序观察cgroup的限制是否生效实验4模拟一次TCP连接耗尽用脚本大量创建短连接然后用ss查看TIME_WAIT状态数量再通过调整内核参数观察变化。这些实验的成本很低一个Linux虚拟机即可但收益极大——一旦你亲手做过这些操作笔试里的场景题就不再是“猜答案”而是“回忆亲历”。6.4 题目收集与错题复盘少即是多刷题是必要的但我不推荐盲目刷。核心系统工程师笔试的风格和算法岗刷LeetCode完全是两码事更重要的是“真题复盘”——每一道遇到的题都要追问三个问题这道题考的是哪个知识模块我为什么做错了/没做出来下次遇到同类题我的解题框架是什么我当时专门建了一个错题本记录每道题的考察点和我的答案然后重新整理出标准的答题框架。比如“TCP连接管理”这类题我会整理出一个“三次握手 四次挥手 TIME_WAIT 常见异常排查”的完整回答模板。这样即使考场上遇到没见过的场景题我也能从模板中抽取相关信息进行组合而不是现场大脑空白。7. 写在最后笔试只是起点核心系统工程师的修炼永无止境回看这场2018年百度提前批的笔试它对我的帮助远不止“一次考试经历”。它像一面镜子照出了我当时知识体系的薄弱环节也让我第一次认真思考想做核心系统方向到底需要具备哪些能力。笔试中那些操作系统、网络协议、并发编程、系统设计的问题到现在依然是我日常工作中每天都要面对的主题。每当我用perf定位到一个CPU热点函数或者用tcpdump抓到一个诡异的重传包时都会想起当年在考卷上写那些答案时的青涩。理论和实践的差距只有真正走到系统深处的人才能体会。最后分享一个我个人的经验如果你准备投核心系统工程师这类偏底层的岗位不要把全部精力放在刷算法题上。花三分之一的时间刷题三分之二的时间去理解操作系统、网络和分布式系统的底层原理并且尽可能多地动手做实验。笔试考察的从来不是“你知道多少”而是“你能用你知道的东西解决什么问题”。想明白这一点你的备考方向就不会跑偏。祝每一个看到这里的你都能在笔试中稳住心态发挥出真正的实力。