ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

系统工程师校招笔试复盘:从Linux排查到分布式架构的考察逻辑

系统工程师校招笔试复盘:从Linux排查到分布式架构的考察逻辑 复盘了一场游戏大厂的系统工程师校招笔试聊聊这场考试背后真正想筛什么。拿到这套搜狐畅游2019系统工程师校招笔试题的时候我正在宿舍准备秋招。当时搜了很多面经发现游戏公司系统工程师岗的笔试资料特别少能参考的只有零星几篇讨论帖。考完之后我把整套题复盘了一遍结合后来在运维岗踩过的坑发现这套题的价值其实远超“应付一场面试”——它基本把一名系统工程师从底层原理到生产落地要用的核心技能都过了一遍。如果你也在准备系统工程师、运维开发、SRE这类岗位的校招或者刚入行想系统补一下基础这篇文章应该能给你一份比较完整的参考。我不打算逐题报答案而是按“题型背后考什么、应该怎么答、实际工作中怎么用”这个思路来拆。1. 岗位认知与目标拆解1.1 系统工程师笔试到底在考什么很多人一看到“系统工程师”这个岗位名下意识觉得这是修电脑、装系统的。但放在游戏公司里这个岗位通常属于技术运营体系负责的是游戏服务器集群的搭建、监控、容量规划、故障恢复、版本发布等一摊子事。搜狐畅游做端游起家后来又铺了手游对服务器的稳定性、玩家同时在线时的抗压能力要求很高所以笔试出题方向非常明确Linux操作系统、网络基础、数据库、Shell脚本、分布式系统基本概念。整套卷子做下来的感觉是不考偏题怪题但考察面很宽。它不像算法岗上来就手撕二叉树也不像开发岗让你写一个完整的业务模块而是用选择题、简答题、场景设计题混合的方式看你对一个“生产环境”有没有系统的认识。一个很典型的例子卷子里有一道关于系统负载的题问的是系统load average偏高时如何判断是CPU瓶颈还是IO瓶颈。这种题没有标准操作但你如果只在教科书上学过top和uptime不知道怎么用iostat、vmstat、pidstat组合排查就很容易答得模棱两可。它本质上是想确认你有没有真实处理过“线上系统变慢”这类问题。1.2 我理解的岗位底层要求把整套题归类之后我提炼出三个反复出现的底层能力要求。第一是“懂原理”。不管是IP地址计算、TCP三次握手还是MySQL索引失效题目都默认你理解这些技术“为什么这样设计”而不是只背结论。第二是“会排查”。很多题给了一个故障现象比如磁盘满了、连接数过高、PHP进程频繁崩溃让你给出排查思路。这类题在笔试里占比不低考察的是面对未知问题时的分析路径。第三是“能落地”。有几道场景题不是问你某个命令怎么用而是给你一个业务需求比如“游戏开新服前需要准备什么”让你以一个工程师的身份给出一套可执行的方案。这里没有唯一答案但你的方案里是否包含容量评估、环境初始化、监控部署、数据备份、回滚预案直接反映了你有没有参与过真实项目的上线流程。理解完这三点再回头看这套题你会发现它真正筛选的不是“知识储备最多的人”而是“具备生产环境直觉的人”。这个直觉恰恰是校招生最稀缺、又最需要通过刻意练习去补的东西。2. Linux操作系统与性能排查题复盘2.1 进程、内存和文件系统的经典考点Linux相关题目在整套卷子里占比最高大概在百分之四十左右。选择题里反复出现了进程状态、内存管理、文件权限、软硬链接这几个方向都是基础中的基础但越基础越容易丢分。比如有一题问ps aux输出中 STAT 列的D状态表示什么。很多人知道R是运行、S是睡眠、Z是僵尸但D这个不可中断睡眠状态经常被忽略。这个状态在实际生产里非常关键——进程处于D状态通常意味着它正在等待IO完成如果大量进程卡在D状态大概率是存储系统出了严重问题比如NFS挂载超时或者磁盘硬件故障。还有一道关于软链接和硬链接的题问删除源文件后硬链接还能不能访问。答案是能因为硬链接和源文件指向同一个inode只要链接数不为0数据就不会被回收。而软链接是指向文件路径的源文件删了软链接就成了“悬空链接”。这个知识点笔试时只是选个答案但工作中做日志轮转、二进制版本切换时选错链接类型是真的会出事故的。内存方面考了free命令的输出解读特别是buff/cache那一列要不要算进“已用内存”。很多人刚接触Linux时会把很高的buff/cache当成内存泄漏实际上这是内核把空闲内存用来做页缓存属于正常行为。真正要关注的是available列它估算的是“在不触发swap的情况下还能分配给新进程的内存”。2.2 负载升高时的排查思路分享简答题里有一道很典型的性能排查题服务器load average飙升但CPU使用率不高让你分析可能原因并给出排查命令。这道题我印象很深因为它没有任何提示全靠平时的排查经验积累。我把这类问题从两个方向拆解。第一是看CPU到底在忙什么——用top或htop查看用户态、内核态、io wait的占比如果us高说明是计算密集或跑了一些死循环如果sy高可能是频繁系统调用或者锁竞争。再看进程列表里的具体进程用pidstat -p PID 1观察单进程的CPU和上下文切换情况。第二是看是不是IO或内存导致的“伪负载”。vmstat 1可以看r运行队列、b阻塞进程、si/soswap换入换出iostat -x 1可以看 %util 和 await如果 %util 接近100%但await不高可能是 SSD 这类设备在处理并发IO时本身就表现出高利用率。磁盘或者网络IO卡顿的时候会出现 CPU 占用不高但 load 高的情况因为负载统计的是正在运行和不可中断的进程总数D 状态进程多了自然负载就上去了。这里插一句我踩过的坑。有一年线上服务偶发变慢load从2跳到15但CPU、磁盘看起来都正常。查了一天最后发现是另一个团队在同一台机器上跑了一个数据导出任务疯狂读磁盘把IO带宽打满了。top里看CPU空闲是因为任务在等IO而不是真的闲。所以排查load问题一定要带着“负载是CPU、IO、内存三者综合结果”的认知去看不能只盯着一项。3. 网络与故障排查综合题复盘3.1 TCP状态机、连接数问题与TIME_WAIT网络部分的题占总分的两到三成重心在TCP。有一道选择题考察TCP连接状态列出ESTABLISHED、TIME_WAIT、CLOSE_WAIT、FIN_WAIT_2这几个状态让选哪个状态说明被动关闭方没有正常关闭连接。答案是CLOSE_WAIT。这个知识在游戏服务器运维里非常实用。游戏客户端经常出现断线重连、异常退出如果服务端代码没有正确回收连接CLOSE_WAIT会越积越多。正常情况下CLOSE_WAIT只是TCP关闭流程里的一个中间状态但如果程序一直没有调用close()这个状态就会一直挂着。线上遇到大量CLOSE_WAIT基本可以断定是业务代码的bug而不是内核参数的问题。排查方式很简单用ss -ant | awk {print $1} | sort | uniq -c统计各状态连接数如果CLOSE_WAIT数量异常升高直接抓服务端对应端口的线程堆栈看阻塞在哪里。TIME_WAIT 问题则是另一类常客。高并发的短连接服务比如PHP-FPM、Nginx代理很容易出现大量TIME_WAIT。有些同学一看到这个问题就想去调内核参数干掉TIME_WAIT比如把net.ipv4.tcp_tw_reuse或tcp_tw_recycle打开。实际工作中我强烈不建议动tcp_tw_recycle这个参数在NAT环境下会引发非常诡异的问题——因为同一NAT出口后面的机器时间戳可能不一致导致部分连接被内核直接丢弃。相比之下调整应用层复用连接、开启长连接比粗暴调内核参数健康得多。3.2 从Linux零搭建一套Web服务的完整流程综合题里有一道特别贴近生产场景给你一台全新的CentOS服务器没有任何环境要求你从零搭建一套Web服务并说明后续维护方案。这个题放在2024年来看依然很经典它考察的不是你会不会用某一种工具而是有没有一套标准化的“初始化动作”。我当时的答题思路分为六层。第一层是基础初始化设置主机名、配置yum源、同步时间、创建普通用户并配置sudo权限。第二层是安全加固修改SSH端口、禁止root远程登录、配置防火墙只放行业务端口。第三层是应用部署安装Nginx、配置站点目录和日志格式、安装PHP或Tomcat等运行时。第四层是监控接入部署Agent上报CPU、内存、磁盘、网络、进程存活等指标配置进程挂掉自动告警。第五层是日志处理将访问日志和错误日志做按天切割配置日志同步到统一收集平台。第六层是备份策略至少对配置文件和数据库做定期备份并明确恢复演练的周期。后来我真实负责服务器初始化时发现这套思路基本够用但还要补充两块一是初始化流程必须代码化用脚本或配置管理工具统一执行避免每台机器“手工装出来配置漂移”二是部署完成后要做一次“自检”比如检查端口是否监听、进程是否开机自启、防火墙规则是否持久化。笔试时写出这六层已经能超过大多数人但实际生产环境要再加一层“验收”才算闭环。4. 数据库、缓存与日志的实战考察4.1 MySQL索引失效场景与主从同步延迟数据库部分主要考MySQL。有一道题列出几个SQL语句让判断哪些语句用到了索引哪些会导致索引失效。常见失效场景基本都涉及了在索引列上做函数运算、隐式类型转换、LIKE前面带通配符、联合索引不满足最左前缀原则。我把这类题总结成一句话索引失效的本质是“B树无法按顺序继续走”。比如WHERE DATE(create_time) 2024-01-01这种写法对create_time列做了函数处理破坏了他原本的有序性优化器只能放弃索引扫描。解决方式是把条件改写成范围查询WHERE create_time 2024-01-01 AND create_time 2024-01-02这样就能走上索引了。主从同步延迟也出了题。游戏业务里玩家数据一般比普通网站更敏感主库写完从库还没同步完时如果读请求打到了从库很可能读到旧数据。最基本的缓解手段是让核心读操作走主库或强制走从库时校验延迟更通用的是减少从库压力、升级硬件、把大事务拆小。另外还有一个非常容易忽略的点主从延迟在业务低峰期也不一定为零需要监控Seconds_Behind_Master超过阈值就告警而不是等到用户投诉才感知到。4.2 缓存穿透、缓存击穿与缓存雪崩缓存相关的题也出现了主要围绕Redis。三个“缓存杀手”——穿透、击穿、雪崩在笔试里往往以“如何设计缓存方案保护数据库”的形式出现。缓存穿透指的是查询一个不存在的数据缓存和数据库里都没有请求直接打到数据库。解决方案可以简单归纳为两种一是把空结果也缓存起来设置较短的过期时间二是用布隆过滤器在缓存之前判断数据是否存在从源头拦截无效请求。这里有一个要注意的细节布隆过滤器存在误判率它只能告诉你“这个数据一定不在”不能完全替代数据库查询。缓存击穿指的是某个热点key过期瞬间大量并发请求同时穿透到数据库。常见解法是互斥锁或逻辑过期。互斥锁就是只放一个请求去重建缓存其他请求等待或直接返回旧值要注意的是必须设置锁的超时时间防止线程挂了锁一直不释放。逻辑过期则是给缓存里的value设置一个内部的过期时间程序读到过期数据时由后台异步刷新实现更丝滑但实现复杂度更高。缓存雪崩则是大量key同时过期或者Redis整个实例不可用导致流量直接打到数据库。应对思路包括过期时间加随机扰动、Redis集群高可用、接口层做限流降级。笔试答题时如果能提到“先用本地锁或信号量扛住第一波再让后台任务去恢复缓存”通常能拿到不错的分数。4.3 日志采集方案从文件到平台日志相关的题虽然没有单独一道大题但在场景题里经常要求“说一下这台服务器的日志怎么管理”。很多人第一反应是tail -f但生产环境下日志的收集、传输、存储和分析是一个完整的链路。我在工作中用过的比较典型方案是应用日志按天写入本地文件Filebeat监听文件变化并发送到KafkaLogstash或Flink做解析和清洗最后写入Elasticsearch用Kibana做查询和可视化。整个链路里最容易出问题的是两个环节一是多个实例的日志如果没有带上实例标识排查问题时没法区分请求来自哪台机器二是日志格式变更时序不一致解析规则很容易挂。如果你笔试时没有那么多经验可以写可以退一步答至少要做日志切割防止单个文件无限增长占满磁盘核心业务日志要采集到统一平台便于跨多台服务器检索日志保留周期也要明确比如原始日志保留30天归档日志保留半年。这套思路虽然朴素但足以证明你理解日志管理在生产中的重要性。5. 分布式基础与系统设计题的解题框架5.1 负载均衡的选型与分层架构分布式部分的题不算多但分值高基本都是简答或设计。有一道题问的是负载均衡的几种实现方式和选型依据这几乎是系统工程师的必考题。我给出的对比框架是四层负载均衡工作在传输层基于IP和端口做转发性能高但要关注LVS的keepalived主备切换七层负载均衡工作在应用层可以根据URL、Header、Cookie做更细粒度的分发典型代表是Nginx和HAProxy。实际生产里两层经常配合用LVS做入口流量分发Nginx做HTTP层的反向代理和路由规则。这样分层的好处是LVS扛大流量Nginx做业务层面的灵活控制两者各自做高可用任何一个出问题都不至于全站挂掉。扩展一下游戏场景里负载均衡还会涉及“分区”的概念。玩家登录时会把玩家分配到不同的游戏服或分区这本质上是一种业务层的负载均衡。到了有状态的长连接场景负载均衡器还需要支持会话保持或者一致性哈希保证玩家连接断开重连时还能回到原来的服务器。笔试如果只答到“用Nginx做反向代理”这个层面其实是偏浅的。5.2 生产环境从零搭建系统并维护的答题框架从今年开始网上关于“如何在生产环境从零搭建一个系统并做好后续维护”的讨论热度很高。这个问题和搜狐畅游这套卷子里那道综合题几乎是同一个问题我当时是按照“设计—部署—验收—运维—迭代”五个阶段来答的这里我把它展开说一下。设计阶段要明确部署架构。单机还是集群要不要负载均衡数据库和Web服务放在一起还是分开存储怎么选这个阶段不能拍脑袋要结合业务量、成本、团队维护能力做权衡。一个刚起步的游戏项目没必要一开始就上微服务和Kubernetes单机加一套虚拟化可能更快。部署阶段除了前面说的“六步初始化”核心是配置管理和自动化。我现在的习惯是服务器全部用Packer打镜像变更只改代码仓库里的配置模板通过GitLab CI或Jenkins构建、发布。这样做的核心价值是可重复——任何一台新机器都能在十分钟内变成和现有机器一致的状态彻底消除“上次那台机器是怎么装的来着”这种尴尬。验收阶段是很多新人容易忽略的。部署完成后至少要检查端口是否正常监听、进程是否设置了守护和开机自启、基础监控是否上报、日志是否接入采集、备份任务是否执行成功、安全组和防火墙是否只放开必要端口。这些检查可以写成脚本一键执行也可以做成上线检查清单每一条都打勾后才算部署完成。运维阶段的核心是监控和告警而不是“等用户说挂了再登录服务器”。我至少会保证三类监控基础设施监控包括CPU、内存、磁盘、网络、温度应用层监控包括进程存活、接口响应时间、错误率、队列堆积量业务层监控包括登录成功率、付费成功率等。告警要分级邮件、短信、电话分别对应不同严重级别同时要写一份紧急事故处理文档把“什么时候重启、什么时候扩机器、什么时候回滚”都提前约定好。迭代阶段则要建立变更管理机制。任何变更都走审批灰度回滚方案。我遇到过最惨的一次事故就是因为直接在生产环境改了一个MySQL参数没走审批结果业务高峰时连接数被耗尽服务大面积超时。后来所有变更都必须提交变更单包含变更目的、影响范围、回滚步骤再小的变更也得走这个流程。5.3 从一道容量估算题聊资源规划逻辑容量估算在游戏笔试里很容易出现但不少人一看到让算服务器数量就懵。其实它考察的不是数学而是“有没有拆解问题的意识”。我把自己常用的思路整理成三步。第一步算“单机能扛多少”以Web服务为例假设单台Nginx或PHP-FPM能处理500并发每请求平均耗时100ms那单机QPS大概是5000左右500并发除以0.1秒。这个数字不用精确关键是数量级要对。第二步算业务需要多少游戏同时在线10万人每个玩家平均每5秒产生一次请求QPS就要2万左右除以单机5000的QPS至少需要4台Web服务器。第三步算冗余和缓冲为了应对突发流量和单机故障至少再乘1.5到2倍也就是6到8台再加两台备用。数据库的容量估算会复杂一点核心看IOPS和连接数。写多读少的业务主库连接数一般控制在200以内比较稳超过这个数要考虑读写分离。存储空间按“日增数据量乘以保留周期再加索引开销”估算磁盘不能只算当前用量要给未来至少半年的增长留出余地。这类题不用答出精确数字但必须在有限条件下做合理假设并给出清晰的计算过程。这恰恰是系统和运维人员日常做资源规划时的真实状态——信息和约束都不完全但必须做出一个可执行的决策。6. 常见问题与易错点汇总6.1 笔试答题时的三个扣分习惯复盘完这套题我发现自己和身边同学在笔试中最常犯的错有三个。第一是“答了但没答到点子上”。比如问排查load高只答“用top看”而不说怎么分析top里的数据、CPU和IO如何区分。系统工程师岗位很注重分析过程所以答题时要把排查路径写完整看什么命令、每个指标代表什么、什么情况会得出什么结论。第二是“只写方案不写理由”。如果你说“修改内核参数开启tcp_tw_reuse”最好补一句“因为短连接关闭后产生大量TIME_WAIT开启后可以复用连接”这样面试官才能看出你是理解了原因而不是背了一个优化项。第三是“忽略备份、监控、回滚这类非功能性设计”。做系统设计题时很多人一门心思想把架构画得多完备却漏了监控和备份。但生产环境最重要的往往就是监控、告警、备份、容灾这些“不出彩但救命”的部分。答题时我习惯最后检查一遍这台服务器如果今天挂了有没有人能第一时间感知到数据和配置能不能快速恢复6.2 时间分配与复习方向的个人建议这份卷子题量中等偏大大概120分钟。我当时的策略是选择题控制在40分钟以内拿不准的标记跳过不纠结简答题每道控制在10分钟左右最后留至少30分钟给设计题因为设计题写起来最费时间。复习方向上如果时间有限我会按优先级排序Linux基础命令和性能排查第一网络TCP基础第二数据库索引和缓存设计第三Shell脚本第四。Shell在大厂笔试题里经常以“写一个脚本查找日志里的错误并统计数量”的形式出现虽然不难但平时不练很容易在细节上翻车。推荐至少能独立写出包含循环、条件判断、文件读取、正则匹配的脚本并了解grep、awk、sed的基本用法。入职之后再看这套卷子我最大的感受是笔试画了一条线线上是知识线下是经验。知识可以通过刷题和看书快速补齐但经验只能在真实的生产环境里一点点攒。如果你还在准备校招不妨自己在虚拟机或云服务器上完整走一遍“从零搭系统”的流程装一次Linux、部署一个Web应用、写几个排查脚本。这套流程做完再回来看搜狐畅游这套题你会发现自己看的不是“题目”而是一张张已经做过的活儿。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进