ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

百度2019校招计算与存储系统笔试题深度解析:考点与备考指南

百度2019校招计算与存储系统笔试题深度解析:考点与备考指南 作为经历过那个时期校招的过来人看到“百度2019校招计算与存储系统研发工程师笔试题第二批”这个题目回忆一下子就上来了。计算与存储系统这个方向在当时的校招序列里属于典型的“硬核岗”不像前端、客户端那样考框架和API也不像算法岗那样死磕论文和模型它考察的是真正底层的计算机素养——从CPU怎么取指令到数据怎么落盘从单机内存管理到分布式集群的一致性每一道题都在筛选“真正懂系统的人”。这篇文章我就以这套笔试题为引子梳理一下我当时刷题、复盘和实际面试中总结出来的核心考点。不论你是正在准备校招的在校生还是工作几年想回头补基础的同学这篇内容都会对你有帮助。我会把题目背后的考查逻辑、典型的解题思路、容易踩的坑都拆开讲清楚也会附上一些具体的实操经验和备考建议。1. 这套笔试题到底在考什么1.1 计算系统与存储系统的考查边界百度计算与存储系统研发工程师这个岗位在2019年校招里的定位是偏向基础设施的。它包含但不限于分布式存储引擎、数据库内核、大规模计算框架、文件系统、KV存储、缓存系统等方向。第二批笔试题和第一批相比整体难度稳中有升尤其侧重对操作系统底层机制和存储引擎内部原理的考察。结合当年笔试的真题回忆和社区讨论这套题主要涵盖以下模块操作系统进程与线程、内存管理、文件系统、IO模型计算机体系结构CPU缓存、流水线、多核一致性、指令执行过程数据结构和算法海量数据处理、Top K问题、哈希一致性、B树分布式系统一致性协议、分布式事务、副本策略、负载均衡存储系统原理LSM-Tree、WAL、块存储/文件存储/对象存储的对比、RAID原理Linux基础IO多路复用、零拷贝、性能排查命令如果你只背了面经里的“八股文”没有真正跑过代码、没有在Linux下做过实验这套题想拿高分是有点难的。它不考你“知道什么”而是考你“遇到具体问题怎么分析和解决”。1.2 通过笔试的人有哪些共同特点我复盘了一下当年通过笔试、走到面试环节的同学发现大家身上有几个共同特质第一对操作系统的理解不是停留在概念层面。比如问到“虚拟内存的作用”大多数人能答出“隔离地址空间、扩大可用内存”但如果追问“缺页中断时CPU和OS各自做了什么”能完整答上来的人就明显变少。而百度这类公司恰恰喜欢在这种追问中筛人。第二有实际的项目经验哪怕只是课程设计或开源项目。笔试中有一道关于“如何设计一个支持高并发读的KV缓存系统”的题目有同学只答了“用Redis”有同学却能从线程模型、IO模型、内存分配、持久化策略、热点key处理等维度展开。后者显然更有竞争力。第三能用计算思维拆解问题。比如有一道关于磁盘IO优化的题目会做的人会先分析“读多还是写多”“随机还是顺序”“数据量多大”再给出对应的方案。这种“先把问题定义清楚再动手”的思维方式比堆砌知识点重要得多。2. 核心考点一操作系统与计算系统基础2.1 内存管理不只是“分页分段”四个字内存管理在校招笔试里几乎是必考中的必考。题目可能很直接比如“简述分页和分段的区别”也可能很隐晦比如给一个系统参数让你算页表开销、TLB命中率的影响。以“分页管理”为例完整回答应该包含下面几个层次逻辑地址到物理地址的映射过程逻辑地址 页号 页内偏移页号去页表查物理页框号再加上偏移量得到物理地址。页表的存放位置和多级页表结构为什么引入多级页表核心是解决连续页表占用大量内存的问题尤其64位系统里一级页表根本不可行。TLB快表的引入及其局部性原理依据TLB命中则一次访存未命中则可能需要两次甚至三次访存访问页表访问数据TLB的覆盖率和命中率直接影响系统性能。缺页中断的处理流程硬件保存现场OS查页表发现页不在内存决定淘汰哪个页页面置换算法、从磁盘哪个位置读入、更新页表和TLB、恢复进程执行。这里我想多说一句很多同学会背“LRU、FIFO、Clock”等页面置换算法但笔试中很少直接问“LRU是什么”更多是给出一个访问序列让你手动模拟。这种题没什么捷径就是老老实实按算法定义模拟注意Clock算法中的“使用位”和“修改位”联合判断的处理逻辑稍有不慎就答错。另外内存对齐也是高频考点。比如结构体大小计算要记住三条规则每个成员按自身对齐系数对齐结构体总大小必须是最大对齐系数的整数倍对齐系数等于成员大小与编译器默认对齐数常见为8的较小值。这类题送分也送命审题时一定要看清是32位还是64位环境。2.2 进程与线程从底层视角理解并发进程和线程的对比几乎是必考题但这道题的得分差距非常大。基础回答是“进程资源分配的基本单位线程调度的基本单位线程共享进程的地址空间”。但要拿高分建议从这几个角度展开创建开销fork写时拷贝机制线程创建只需要分配栈空间和TCB不需要复制完整地址空间。上下文切换开销进程切换需要切换页表导致TLB失效、切换寄存器、更新各种表项线程切换虽然也要切换寄存器和栈但不需要切页表所以更轻量。通信方式进程间通信有管道、消息队列、共享内存、信号量、Socket等线程间通信则依赖共享内存和同步原语。这里要能说清楚“共享内存为什么是最快的IPC方式”以及“为什么需要同步机制”。还容易考的是“多线程模型对比”一对一、多对一、多对多模型以及用户态线程协程和内核态线程的差异。结合到时候很多公司已经大规模使用协程比如百度的brpc框架这道题往往还隐含了对协程调度、栈管理、异步IO的理解。我实际做题时的一个心得是不要急着写下“线程比进程轻量”这种结论而是先思考“轻量到底轻在哪里、为什么轻”。把所有对比项落到具体的资源和操作开销上你的答案自然比其他人的更有深度。2.3 IO模型与IO多路复用大数据量下绕不开的坎这道题在第二批笔试里出现的概率很高尤其在问“如何设计高并发网络服务”或“介绍常见的IO模型”时。IO模型考察的范围比较明确阻塞IO进程发起read后陷入等待直到数据就绪才返回。非阻塞IOread立即返回通过返回值判断是否就绪通常配合轮询忙等CPU浪费明显。IO多路复用select/poll/epoll一个线程可以同时监听大量fd由内核帮忙检测就绪事件。信号驱动IO进程注册SIGIO信号处理函数数据就绪后内核发信号通知但实际读取数据还是要自己来。异步IOaio_read这类接口内核负责把数据拷贝到用户缓冲区后通知进程全程无需用户进程阻塞或干预。关键在于要能清楚区分“同步/异步”和“阻塞/非阻塞”这两组概念之间的关系同步IO意味着内核把数据从内核空间拷到用户空间时用户进程需要主动等待无论是阻塞等还是轮询等真正的异步IO连拷贝过程都由内核完成完成后才通知用户进程。IO多路复用里epoll为什么比select/poll高效这是必须答透的点select有FD_SETSIZE限制通常1024每次调用都需要把整个fd集合从用户态拷贝到内核态。poll用链表组织fd突破数量限制但每次也是全量拷贝、全量遍历。epoll通过epoll_ctl注册感兴趣的事件内核用红黑树维护通过回调机制把就绪的fd放入就绪链表用户通过epoll_wait只获取就绪事件不需要遍历所有fd也不需要每次重新拷贝全部fd集合。再往前推进一点如果题目让你“用epoll实现一个高并发echo服务器”你就得知道ET边缘触发和LT水平触发的区别以及为什么ET模式下必须使用非阻塞IO并循环读直到EAGAIN。这些细节我在实际编码中踩过坑——使用LT反而更省心但高并发高性能场景ET是标配。3. 核心考点二存储系统原理深度拆解3.1 从机械硬盘到SSD存储介质的演进逻辑存储系统考题里存储介质相关的知识往往是基础题。复习时需要掌握的最核心内容如下维度HDD机械硬盘SSD固态硬盘介质磁性盘片 机械臂NAND Flash颗粒读写单位扇区512B/4KB页常见4KB~16KB擦除以块为单位常见几MB随机读写性能很差寻道旋转延迟远优于HDD但仍有写放大寿命基本不受写次数限制存在P/E擦写次数限制适合场景大容量冷数据热数据、高IOPS场景这里容易考到的专业概念有写放大Write AmplificationSSD不能覆盖写必须先擦除后写入且擦除以块为单位如果块里还有其他有效页就要先把它们搬走导致实际写入物理介质的量大于上层请求的量。计算公式写放大系数 实际物理写入量 / 逻辑写入量。磨损均衡Wear Leveling为了延长SSD寿命控制器需要让每个块的擦写次数尽量均匀。动态磨损均衡只考虑释放的空闲块静态磨损均衡还会把长期不动的冷数据搬走腾出空间让频繁写的块轮换。FTLFlash Translation Layer负责把逻辑地址映射到物理页并处理垃圾回收、磨损均衡、坏块管理等。FTL策略的好坏直接决定SSD的性能和寿命。我当时复习的时候在纸上画了一下写放大产生过程的流程图帮我把整条链路理得特别清楚。用通俗的比喻说就是想象你有一个笔记本想改其中一页的一行字但这一页不能单独改必须把整页撕下来重写如果这一页上还记着别的重要信息你就得先把那些信息抄到新页上再撕掉旧页——多出来的“抄写”工作就是写放大。3.2 RAID原理与级别选择不只是“01拼一起”RAID独立磁盘冗余阵列也是存储岗笔试题里的老朋友。你需要掌握每种级别的数据组织方式和容错能力还要能根据应用场景选型。我把常见级别整理如下RAID 0条带化数据分散写入多块盘无冗余。性能最好但任何一块盘坏掉数据全毁。RAID 1镜像数据写两份到两块盘空间利用率50%读性能提升容错1块盘。RAID 5条带加分布式校验校验信息均匀分布在各块盘上空间利用率N-1/N容错1块盘。RAID 6双重校验PQ可容错2块盘但写性能因为两次校验计算而下降。RAID 10先镜像再条带兼顾性能和容错至少需要4块盘空间利用率50%。它是很多数据库场景的首选。笔试中常见的问题是“一个RAID 5阵列由5块1TB磁盘组成实际可用容量是多少最多坏几块盘还能正常工作”答案是4TB、1块。这些基础题不能丢分。更进阶一些还会考“RAID 5在随机写场景下的读改写流程”由于要更新一个条带中的数据块需要读取旧数据和旧校验值计算新校验值再写入新数据和校验值所以一次逻辑写往往对应两次读两次写。这个“读改写”过程是很多人忽略的考点。RAID实现方式也要知道硬件RAID依赖专用RAID卡有独立缓存和电池保护性能好但成本高软件RAID用CPU计算和系统内存成本低但会占用系统资源分布式存储中常用多副本或纠删码Erasure Coding如RS-3-2取代传统RAID以应对跨节点容错。3.3 分布式存储的三驾马车CAP、一致性哈希与副本协议如果你投递的是存储系统研发岗分布式部分就是拉开分差的关键。第二批笔试里这块的比重明显较大而且往往以开放式设计题出现。CAP定理是必须张口就来的在分布式系统中一致性Consistency、可用性Availability、分区容错性Partition tolerance三者不可兼得。实际系统面对网络分区是必须容忍的P是必选项所以真正的设计取舍发生在一致性和可用性之间。一致性哈希是高频考点重点要理解这几件事为什么不用简单哈希取模因为节点增减时大量key需要迁移导致缓存雪崩或大量回源。一致性哈希怎么做把节点和key都映射到一个0~2^32-1的哈希环上key顺时针找到第一个节点存储。节点增减时只影响环上相邻范围的数据。哈希环偏斜问题怎么解决引入虚拟节点每个物理节点对应环上多个位置保证数据分布的均匀性和故障时负载的平滑转移。再来是副本协议。需要知道几种典型的副本同步方式同步复制主副本写成功并同步到从副本后才向客户端返回成功。数据安全性高但延迟大。异步复制主副本写成功就返回后台异步同步到从副本。延迟低但故障时可能丢数据。强同步如MySQL半同步至少一个从副本确认后返回兼顾安全和延迟。Raft协议采用日志复制日志先写入Leader的本地日志再复制到多数派节点落盘后Leader才能提交并返回。这里面涉及选举机制、日志匹配、安全保证等细节。我当时复习Raft时用一个小Demo模拟了Leader选举和日志复制的过程真正上手跑一遍之后再回答笔试中“为什么Raft要求日志必须连续复制”这类问题时明显更有底气。纸上谈兵和实操的差别在答题深度上体现得非常明显。3.4 LSM-Tree与BTree存储引擎的两条技术路线存储引擎的底层数据结构是存储系统笔试的重头戏。BTree和LSM-Tree的对比是这个模块最核心的考点。BTree的特点所有数据都存在叶子节点非叶子节点只存索引键因此单次查询的IO次数固定为树高。叶子节点用链表串联天然支持范围扫描。节点分裂和合并保证树的平衡。适合读多写少、要求稳定读延迟的场景典型代表是MySQL InnoDB。LSM-Tree的特点写入时只追加内存中的MemTable有序结构达到阈值后冻结并落盘为SSTable后台异步合并。写入不涉及随机IO顺序写性能极佳。读性能相对较差一次读可能需要查多个SSTable需要布隆过滤器Bloom Filter加速判断某个key是否存在减少无效磁盘IO。后台Compaction会带来写放大和读放大需要精心调优。适合写多读少、写入吞吐优先的场景典型代表是LevelDB、RocksDB、HBase。这里有个常见的考题“为什么LSM-Tree比BTree写入快”答案的核心在于BTree的写入可能触发随机IO和节点分裂而LSM-Tree把随机写转化为顺序写把磁盘最怕的随机小IO变成了擅长的大块顺序IO。反过来也会问“LSM-Tree的读放大和写放大如何权衡”回答时可以提到RocksDB中二级Compaction策略的配置、Bloom Filter的作用、以及Level层数和每层大小比例的设置。还有一个隐藏考点是WALWrite-Ahead Logging预写日志。无论BTree还是LSM-Tree为了保证数据持久性和崩溃可恢复都需要WAL机制先写日志再更新内存中的数据。MySQL的Redo Log、RocksDB的WAL都是这个思路。要能解释清楚为什么“先写日志”反而是更快的方式——因为日志是纯顺序写而数据文件的更新往往是随机写。4. 经典题目实战复盘从题意到解题思路4.1 设计题“海量Key-Value数据的高并发读取系统”第二批笔试中有一道典型的系统设计题没有标准答案但阅卷人可以明显看出考生的系统设计功底。我当时把这道题完整拆解了下来这里和大家分享我的思路框架。第一步澄清需求。实际上笔试中题目不会写“读多写少”或“写多读少”但你需要主动分析。如果题目说“高并发读取”默认是读多写少读写比假设在10:1到50:1之间。数据规模假设在亿级别以上单个value大小假设1KB以内。第二步设计整体架构。基于对题目的常规理解一个可用的方案如下接入层使用NginxLua或自研网关做负载均衡和请求路由根据key做一致性哈希把请求分发到对应的缓存节点。缓存层使用Redis Cluster每个分片部署一主一从主节点写从节点分担读流量。热点key可以在本地加一层LRU缓存。存储层底层用RocksDB或RocksDB分布式文件系统保证数据不丢同时支持定期把冷数据下沉。第三步细化关键技术点缓存穿透查询的key在缓存和底层存储中都不存在时请求会直接打到数据库。解决思路有布隆过滤器拦截、缓存空值。缓存击穿某个热点key过期瞬间大量请求打到数据库。解决思路是互斥锁重建缓存、逻辑过期。缓存雪崩大量key同时过期导致数据库压力激增。解决思路是过期时间加随机数、多级缓存。热点key某个key的访问量特别大单个分片扛不住。解决思路是本地缓存如缓存到JVM/C进程内存中、把key复制成多份分散到不同分片。第四步谈一致性和最终一致。缓存和数据库之间的数据一致性推荐使用延迟双删或者基于Binlog的异步更新。这个点说出来阅卷人就知道你了解生产环境中的真实做法而不是只会写伪代码。回答设计题时切忌只丢出一个Redis就说“可以了”。面试官和阅卷人想看的是你把一个HTTP请求从入口到存储的全链路都想清楚并且针对关键风险点有预案。4.2 计算题“多线程环境下统计十亿整数的Top 100”这道题在第二批笔试中也很经典考了两个维度一是海量数据的处理思路二是多线程编程模型的掌握。常规思路是分治堆把十亿个整数切分成适合单机处理的分片数据。每个分片在单线程内维护一个大小为100的小顶堆当新数大于堆顶时替换并调整堆。多线程并行处理各分片每个线程得到该分片的局部Top 100。最后把多个局部Top 100合并再次用小顶堆选出全局Top 100。如果题目允许使用多机则用MapReduce思想Map阶段输出分片内的Top 100Reduce阶段合并得到全局结果。重点是要能写出处理复杂度遍历每个数一次O(N)堆操作O(log100)趋近于常数所以整体时间复杂度约等于O(N)。这里容易忽略的是“如果数是分布式的如何避免数据倾斜”以及“如果内存足够大是否可以直接用计数数组/排序”。这类题目没有唯一答案但你要学会根据约束条件选择方案。建议平时多练习几种海量数据题型的解法比如位图法求不重复数、布隆过滤器判存在、外排序处理大文件等。另外多线程代码实现上要小心并发安全。每个分片用独立的堆最后合并时再对合并堆加锁尽量避免全局锁带来的竞争开销。回答中如果能提到“用原子操作代替互斥锁”或者“分片无共享设计”会让阅卷人眼前一亮的概率更大。4.3 细节题“一个进程访问了不存在的内存地址会发生什么”这题有意思它看起来是概念题实际上考的是整个缺页/段错误处理链条。完整的回答应该是CPU访问虚拟地址TLB未命中后查页表。页表项中有效位Present bit为0CPU触发缺页异常/页面错误。OS捕获异常检查地址是否在当前进程的虚拟地址空间内。如果地址非法比如空指针、野指针、越界访问未映射区域OS向进程发送SIGSEGV信号进程默认终止。这就是“Segmentation Fault”的来源。如果地址合法但页面未在内存中则分配物理页框从磁盘换入数据更新页表和TLB恢复进程执行。很多人答到第二步“触发缺页异常”就停了丢失了后半段“非法地址会怎么处理”的内容。实际上后半段才是区分“背过”和“理解”的关键。笔试的考点往往藏在这种细节里平时写C/C代码时多想想“为什么这里会core dump”自然而然就理顺了。5. 备考策略与实操建议5.1 如何在两个月内高效准备系统方向笔试题不管你是科班出身还是半路转行准备计算与存储系统方向的笔试我都建议按照下面的节奏来安排第一阶段前两周打基础回归教材和经典课程。重点复习《深入理解计算机系统》CSAPP和《操作系统概念》里的内存管理、进程线程、文件系统章节《数据密集型应用系统设计》DDIA里的事务、复制、分区、存储引擎章节后者对于分布式存储题尤其重要。第二阶段中间三周刷题与源码阅读并行。推荐在LeetCode上刷一些设计题和并发题同时把RocksDB或LevelDB的源码挑核心部分读一遍重点是MemTable、SSTable、Compaction这三块逻辑。如果你时间紧张至少要把它们的README和架构文档看明白。这里我想分享一个自己的做法把每道题目的答案整理成“一句话结论 三点论据 一个例子”的结构。这样在笔试限时作答时你不需要现场组织语言直接按框架输出既节省时间又能保证条理清晰。第三阶段最后两周模拟笔试复盘错题。按照真实笔试的时间限制通常2小时做几套模拟题练习时间分配。我当年吃过亏在一道设计题上花了太多时间导致后面的选择题草草作答。建议拿到试卷先花2分钟浏览全卷确定每道题的预估用时先做有把握的难题放最后。5.2 复习时最容易踩的坑结合我和身边同学的经历以下四个坑非常常见写出来给大家避雷第一忽视基础知识。有些同学一上来就研究Raft论文、读GFS论文结果连“页表放在内存哪里”都说不清。请记住笔试里基础题占比通常超过一半先把基础分拿稳再谈拔高。第二只会背概念不会动手算。比如“Cache命中率对平均访问时间的影响”这种题如果平时不推公式、不代入数值考场上一紧张就容易出错。建议把CSAPP课本中所有带数字的例题都自己算一遍。第三死记硬背源码不理解设计动机。RocksDB为什么默认用LSM-Tree而不是BTree这不是源码能告诉你的而是要从读写比例、磁盘特性、Compaction策略等多方面理解。答题时如果只是“源码里就是这么写的”给分不会高。第四忽略语言表达。笔试的简答题不比编程题阅卷人看的是你的逻辑组织能力。有些同学知识点都知道但表达杂乱无章想到哪写到哪。建议平时练习用“总-分-总”的结构作答先给结论再分条验证带上具体的数字或例子佐证。5.3 实操练习题推荐这里给出一份适合用来备考的实操清单你把这几项动手做完笔试时对很多题目的理解会明显不一样用C语言实现一个简单的线程池观察线程数量与任务吞吐量的关系思考为什么不是线程越多越快。用mmap或read/write分别读取一个大文件并计时对比系统调用和内存映射在IO路径上的差异。在Linux下使用strace跟踪一个Redis命令的执行过程观察它调用了哪些系统调用理解epoll的工作方式。用RocksDB的Java或C接口写一个小例子设置不同的write_buffer_size和max_write_buffer_number比较写入性能和Compaction触发频率的变化。自己模拟一致性哈希的实现加入/删除节点对比普通哈希取模和一致性哈希在key迁移数量上的差异。你会发现当你在电脑上实际跑过一遍之后笔试里那些“概念题”就不再是死记硬背了而是变成了“噢这不就是我之前调参时看到的那个现象嘛”的自然反应。6. 常见笔试问题速查表6.1 内存与进程线程高频考点速查下面这个表格是我备考时自己整理的考前过一遍非常有用问题核心回答要点分页和分段的区别分页是系统行为固定大小无逻辑意义分段是用户行为按逻辑模块划分大小不固定虚拟内存的作用内存隔离、地址空间扩展、按需加载、共享内存基础进程和线程切换开销差异是否需要切换页表TLB失效、地址空间、资源表死锁的四个必要条件互斥、持有并等待、不可剥夺、循环等待进程间通信方式管道、FIFO、消息队列、信号量、共享内存、Socket线程同步方式互斥锁、读写锁、条件变量、信号量、自旋锁协程和线程的区别协程用户态调度、栈可动态扩容、切换不需要内核参与6.2 存储与分布式高频考点速查问题核心回答要点RAID 0/1/5/6/10区别条带、镜像、分布式校验、双重校验、先镜像后条带HDD和SSD关键差异寻道时间、随机读写能力、擦写寿命、写放大CAP定理C/A/P三者取舍P必选多数场景C与A之间权衡一致性哈希如何解决扩缩容哈希环、虚拟节点、只影响相邻节点数据Raft的日志复制过程Leader选主、日志追加、多数派确认、提交、状态机应用缓存穿透/击穿/雪崩方案布隆过滤器/空值缓存、互斥锁/逻辑过期、过期时间随机化/多级缓存LSM-Tree读放大优化Bloom Filter、层级压缩策略、SSTable元数据索引备考时把这些考点逐一展开每个考点都要达到能说5分钟以上的程度。如果发现哪个考点你只能说出两三句话不要犹豫立刻回到教材或源码里把那块补全。作为过来人我强烈建议你在准备这套题时不要以“通过百度笔试”为目标而是以“成为一名合格的计算与存储系统工程师”为目标。笔试只是一道门槛但门槛里的知识会在你入职后每天都在用。当时我在刷题时啃下的RocksDB源码、Raft论文和CSAPP习题后来真正参与分布式存储开发时依然在持续发挥着作用。这套题之所以值得认真对待是因为它帮你把整个知识体系梳理了一遍。最后分享一个小技巧复习时用XMind或手写笔记做一张自己专属的知识地图题做完以后把错题涉及的知识点标记出来你会发现高频考点就那么几个——内存管理、IO模型、缓存一致性、分布式一致性、存储引擎数据结构。把这些核心模块各个击破笔试这关基本就稳了。
返回列表