当时参加搜狐畅游2020校招运维开发工程师笔试的时候,我其实心里是有点没底的。原因倒不是怕题难,而是这个岗位的名字本身就带有迷惑性——“运维”两个字让人以为考的是 Shell 命令和 Linux 操作,但真正坐在电脑前打开试卷,才发现它考的是“开发工程师”该有的东西:Python 编程、网络协议、数据库原理、系统设计,甚至还有一些游戏业务背景下的场景题。整场笔试更像是一次技术体检,把你在学校里的底子、在实验室里踩过的坑、在开源项目里读过的源码,全都翻出来晒了一遍。
这篇文章想把当时笔试的完整复盘写下来,包括考点分布、题目类型、答题思路、备考资料,以及我在笔试里吃亏的一些细节。如果你是准备投运维开发方向校招的同学,或者对游戏公司的运维技术栈好奇,这份复盘应该能帮你少走不少弯路。尤其是那些“考试时觉得会,对答案发现自己想简单了”的题,我会专门拿出来说透。
1. 游戏行业的运维开发,到底在招什么样的人
1.1 从搜狐畅游看游戏公司的技术栈
先说一个容易被忽略的背景:搜狐畅游不是那种普通的互联网公司,它有大量的端游、手游业务,代表作像《天龙八部》系列这种大型 MMO,服务器的架构和调度逻辑比一般 Web 业务要复杂得多。游戏业务的运维工程师,日常面对的不是简单的“服务挂了重启一下”这种活,而是开服、合服、跨服战、大版本更新、活动流量峰值、封测压力测试,这一整套围绕游戏生命周期的运维工作。
在这些业务背后,运维开发工程师的核心职责就是两件事:第一,把重复的运维操作变成自动化平台,比如发版工具、配置分发系统、日志采集平台、监控告警系统;第二,在故障发生时,能快速定位问题,并且用代码去修复或规避问题。所以笔试的时候,你会发现它在用考题反复确认一件事:你到底有没有用工程的思路去解决运维问题。
我当时判断,这个岗位的笔试本质上是在筛选两类人。一类是 Linux 基础和网络基础扎实的候选人,因为游戏服务器的运行环境大多是多地多机房部署,网络问题、系统性能问题都是日常;另一类是代码能力过关的候选人,因为运维开发的核心产出是工具和平台,不是单纯的“敲命令”。笔试的卷子也确实是这么设计的,大约一半的分数给了编程和脚本题,另一半给了系统、网络、数据库这类基础题,纯粹死记硬背的题目反而很少。
1.2 笔试考察的四层能力模型
把 2020 年那次笔试的题目做一次复盘,我倾向于把它的考察点拆成四个层次。第一层是基础理论,也就是操作系统、计算机网络、数据库这些计算机核心课,占比最大,也是刷人最狠的部分;第二层是工具实战,比如 Linux 命令、Shell 脚本、Git 操作,这部分考的是你真的有没有在用这些东西;第三层是工程思维,比如监控告警的设计、日志分析、故障排查的思路,这部分通常以简答题或场景设计题出现;第四层是代码落地能力,就是给一个实际问题,用 Python 或 Shell 写出可运行的解决方案。
这四个层次是递进的。基础理论不行,后面的题基本无从下手;工具用过但不懂原理,遇到变通的题就容易翻车;有工程思维但代码写不出来,那也只能干瞪眼。我印象很深的是有一道场景题,大意是说游戏新版本上线后,玩家反馈登录超时,让你写出排查思路。这道题没有标准答案,但阅卷人能从你的步骤里看出你有没有真实处理过生产环境故障:是直接从“重启服务器”开始写,还是会先看监控、查日志、确认网络链路、再逐步缩小范围。
| 能力层次 | 考察内容 | 典型题型 | 大约占比 |
|---|---|---|---|
| 基础理论 | 操作系统、网络、数据库 | 选择题、填空题 | 35% |
| 工具实战 | Linux、Shell、Git | 选择题、操作题 | 20% |
| 工程思维 | 故障排查、监控设计 | 简答题、场景设计题 | 25% |
| 代码落地 | Python/Shell 编程 | 编程题 | 20% |
2. 笔试核心知识点全景拆解
2.1 操作系统与 Linux:笔试里最重的一座山
无论是选择题还是后面的排查题,操作系统和 Linux 几乎无处不在。我记得卷子里有一道题问的是top命令输出里,load average后面的三个数字分别代表什么。很多同学能背出“1分钟、5分钟、15分钟平均负载”,但它紧接着问:如果服务器是 4 核 CPU,load average 是 4.5,说明什么?这就不是背概念能答出来的了。正确理解应该是:4 核 CPU 的机器,load 持续超过 4.0 说明运行队列已经饱和,结合%us、%wa的数值才能判断是 CPU 计算密集还是 I/O 等待导致。
Linux 命令的考察也不只是“这个命令是干嘛的”这种程度,而是给你一个具体的排查场景,让你选择合适的命令组合。比如:
- 查看端口监听情况:
netstat -tlnp或ss -tlnp - 查看进程的线程数和 CPU 占用:
top -Hp <pid> - 查看磁盘空间和 inode 使用:
df -h、df -i - 查找大文件:
du -sh * | sort -hr | head -20 - 实时跟踪日志并过滤关键字:
tail -f app.log | grep "ERROR"
这些命令我平时都用过,但笔试里被问到的不是“会不会敲”,而是能不能说出每个命令的关键参数,以及为什么用这个参数。比如netstat里的状态统计,ss -s可以直接看 socket 统计,在排查大量TIME_WAIT连接时就非常有用。
还有文件系统基础,笔试里出了一道关于软链接和硬链接的题。它问:创建一个硬链接后,ls -l看到的 inode 号码是否相同?删除源文件后,硬链接还能不能访问?这道题考察的是硬链接的本质——多个目录项指向同一个 inode。软链接则是一个独立的文件,里面存的是目标路径,所以源文件被删掉后软链接就失效了,而硬链接依然可以正常访问。这种题只要在 Linux 里亲手敲过一遍 mkdir、ln、ls -i,基本不会丢分。
2.2 网络与协议:从 HTTP 到 TCP 的常考细节
网络部分的考察非常经典,但问法上很有游戏公司的特色。它不会直接让你默写 TCP 三次握手,而是问“游戏客户端在登录时,为什么 TCP 连接建立需要三次握手而不是两次”。这道题的核心是解决“客户端发出的连接请求超时重传后,服务端无法区分旧请求和新请求”的问题。如果只有两次握手,服务端收到一个迟到的旧请求,会直接建立连接并分配资源,造成资源浪费。三次握手里,客户端收到服务端的 SYN+ACK 后,如果确认自己是迟到重传的,就不会再回 ACK,服务端也就不会建立连接。
HTTP 协议部分考了一道比较典型的题:从浏览器输入 URL 到页面显示,中间经历了哪些过程。这道题看起来简单,但它考察的是完整的网络链路:DNS 解析、TCP 连接、TLS 握手(如果走 HTTPS)、HTTP 请求发送、服务端处理、响应返回、浏览器渲染。每一个环节都可能扩展出追问,比如 DNS 用的是 UDP 还是 TCP,为什么区域传送用 TCP,普通查询用 UDP。这类题我建议在备考时自己画一遍完整链路,把每一层涉及到的协议和可能出问题的地方写下来,比单纯背书有用得多。
还有一道关于 HTTP 状态码的题,给了几个场景让你选对应的状态码:请求的资源不存在,应该返回什么?服务器内部错误,应该返回什么?重定向呢?这类题本身不难,但它考到了 301 和 302 的区别。301 是永久重定向,浏览器会缓存,后续请求直接跳转;302 是临时重定向,每次都需要先访问原地址再跳转。游戏里做活动页面跳转时,如果错误地用了 301,可能会导致玩家永远访问不到更新后的内容,所以这个细节在真实业务里也是有意义的。
2.3 数据库与缓存:写不出慢 SQL 是最低要求
数据库部分在运维开发笔试里从来不是单纯的“写 SQL”测试,而是考你对索引和查询计划的理解。我记得有一道题:有一张用户订单表,字段包括 user_id、order_id、create_time,查询条件是WHERE user_id = 12345 AND create_time > '2020-01-01',问应该怎么建索引。这里有一个很关键的细节,就是联合索引的列顺序。因为create_time是范围条件,联合索引应该把等值条件user_id放在前面,范围条件放在后面。如果反过来建,create_time的范围条件会让后面的user_id索引失效,查询效率会差很多。
事务隔离级别也是必考的。MySQL 默认的隔离级别是 REPEATABLE READ,这个知识点大多数人都知道,但换个问法就有人懵了:在 REPEATABLE READ 隔离级别下,A 事务读取了一行数据,B 事务删除了这行并提交,A 事务再次读取这行,能不能读到?其实在 InnoDB 的 MVCC 机制下,A 事务第一次读取时创建一个 ReadView,后续读取都基于这个 ReadView,所以 B 事务提交后的删除对 A 是不可见的,A 依然能读到这行数据,这叫快照读。如果把查询改成SELECT ... FOR UPDATE这种当前读,那结果就不同了。
缓存方面,Redis 的考察集中在那几个高频问题上:缓存穿透、缓存击穿、缓存雪崩。我记得题目是让考生分析这三种情况分别是什么,以及如何解决。三者的本质区别要理清:穿透是查询一个必然不存在的数据,导致请求直接打到数据库;击穿是某个热点 key 过期,大量请求一瞬间打到数据库;雪崩是大量 key 同时过期,导致数据库压力暴增。对应的解决方案也不一样,穿透可以用布隆过滤器,击穿可以用互斥锁或逻辑过期,雪崩可以在过期时间上加随机值、做多级缓存。游戏场景里还有一个特殊的缓存问题,就是排行榜数据,既要求实时性又要求性能,后来我在项目里用的是 Redis ZSET 存储,这个点如果能在笔试里主动提一句,会显得你有游戏业务的场景意识。
2.4 脚本能力与自动化:Python 和 Shell 都要会
编程题是笔试里最拉分的一块。我当时拿到的编程题大概是:有一个 Nginx 访问日志文件,每行记录包含 IP、访问时间、请求路径、状态码,要求统计出访问次数最多的 Top 5 IP,并输出到另一个文件。这道题用 Shell 一行可以搞定:
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -5 > top5_ip.txt但如果只用 Shell,遇到更复杂的逻辑、需要写正则提取特定字段、或者需要维护状态的时候,Shell 就会很吃力。所以笔试还给了 Python 的替代方案,考察你用 Python 处理文本的能力。我当时用的是collections.Counter,大概长这样:
from collections import Counter ip_list = [] with open('access.log', 'r') as f: for line in f: ip_list.append(line.split()[0]) top5 = Counter(ip_list).most_common(5) with open('top5_ip.txt', 'w') as f: for ip, count in top5: f.write(f"{ip} {count}\n")这道题我虽然很快写出来了,但后来复盘时发现有个细节没处理好:如果日志文件很大,把所有 IP 全读进内存再统计,内存占用会很高。更稳妥的做法是边读边用字典计数,或者用defaultdict(int),对每行做实时累加。笔试阅卷人未必会真的运行你的代码,但他在看代码时能不能发现你有这种“生产环境意识”,会直接影响这道题的评分档位。
Shell 部分还考了一个常见需求:查找日志文件中最后 10 分钟内的错误记录。这个题考察的是时间处理和文本过滤的组合,可以用date计算时间戳,再用awk做比较判断。不过手写这个逻辑在考场上容易卡住,我的建议是备考时把“日志按时间过滤”“统计 TOP N”“多文件批量处理”这三类脚本题各写三遍,基本就能覆盖笔试里 80% 的脚本场景。
3. 题目类型还原与答题思路
3.1 选择题:不是考记忆,是考排查链路
选择题属于看着不难,但错误率很高的板块。它的难不在于概念偏,而在于选项设计得非常接近。比如有一道题问的是ps -ef | grep java这个命令,下面哪个说法是正确的。A 选项说是查看 java 进程的 CPU 使用率,B 选项说是查看 java 进程的 PID 和父进程 PID,C 选项说是查看 java 进程监听的端口,D 选项说是查看 java 进程的内存使用。正确答案是 B,但很多同学选了 A,因为平时习惯了用ps看进程,却忘了ps -ef输出的是 UID、PID、PPID、C、STIME、TTY、TIME、CMD 这些信息,并不能直接看到 CPU 使用率和内存。
这类题给我最大的启发是:笔试选择题实际上在模拟“你登录到服务器上,第一件事会敲什么命令”这个真实场景。它考的不是孤立的知识点,而是你有没有在大脑里存一条“故障排查链路”。比如服务响应变慢了,正常的链路是top看负载和 CPU,再用free看内存,再用iostat看磁盘,然后vmstat看上下文切换和运行队列,最后结合日志定位。如果你的知识是片段式的,选择题很容易被迷惑选项带跑。
3.2 简答题与场景设计题:先给结论再说依据
场景设计题是这份卷子里最有区分度的一部分。它不会直接告诉你标准答案,而是要看你的思路。我记得有一道题是:某个游戏大区在晚上 8 点开放新活动,预计玩家流量是平时的 5 倍,作为运维开发工程师,你需要提前做哪些准备。这道题如果只写“加服务器”“扩容带宽”,基本就告别晋级了。合理的思路是按时间轴拆解:
- 活动前一周:压测模拟峰值流量,确认瓶颈在 CPU、内存还是数据库连接数;检查 CDN 是否回源正常;确认监控大盘覆盖关键指标,比如在线人数、请求 QPS、错误率、平均响应时延
- 活动前 1 小时:发布变更单,扩容游戏服和数据库只读节点;预热缓存;检查日志采集链路是否正常,确保活动数据能实时分析
- 活动进行中:盯告警,尤其是慢查询和错误日志;准备应急预案,比如限流策略、降级开关、回滚方案
- 活动结束后:输出峰值数据报告,复盘是否有容量预估偏差
这种题的关键是逻辑完整、节奏清晰。一个建议是做题时不要上来就写细节,先用一句话给出结论,比如“我会从容量评估、监控告警、应急预案三个维度来做准备”,然后每一条下面写两到三句支撑细节。这种“总—分”结构的答案,阅卷人扫一眼就能看到你的思路,分数不容易低。
还有一道简答题是我之前提到过的:玩家反馈登录超时,排查思路是什么。这道题考察的是网络和系统知识的综合运用。我当时写的思路是:先看监控确认是单区还是全服问题,再查 DNS 解析和网络层,确认客户端到登录服的网络链路;然后看登录服的 CPU、内存、TCP 连接数和日志,确认是否有连接耗尽或慢查询;最后看数据库和 Redis 的负载,确认是否被活动流量打满。每一步都对应一类常见的故障原因,面试官看到这种思路会认为你有实际排查经验。
3.3 编程题:用最小闭环表达工程思维
编程题除了考语法,更考察你有没有“输入—处理—输出—容错”的完整闭环。有一道题我记得很清楚:写一个脚本,监控指定进程的 CPU 使用率,如果连续 3 次超过 80%,就打印告警信息并退出。这道题看似简单,但里面埋了几个隐藏考点:
- 进程可能不存在,脚本需要做判断
- 连续 3 次,意味着脚本要循环采样,而不是只取一次快照
- “超过 80%”的判定,需要考虑是单核还是多核,如果进程是多线程,
ps里的 %CPU 语义是什么 - 告警输出后要考虑是否要退出,还是继续监控
我当时用 Python 写的方案,核心部分是循环采样,每次通过/proc/<pid>/stat读取进程的 CPU 时间,计算两次采样之间的差值,从而得到实时 CPU 使用率。这种做法比直接用ps的 %CPU 更准确,因为ps显示的是进程生命周期内的平均值。代码大概长这样:
import os import time import sys pid = int(sys.argv[1]) threshold = 80 count = 0 def get_cpu_time(pid): with open(f"/proc/{pid}/stat", "r") as f: data = f.read().split() utime = int(data[13]) stime = int(data[14]) return utime + stime def get_total_cpu_time(): with open("/proc/stat", "r") as f: data = f.read().split() return sum(int(x) for x in data[1:]) t1 = get_cpu_time(pid) total1 = get_total_cpu_time() time.sleep(1) t2 = get_cpu_time(pid) total2 = get_total_cpu_time() cpu_percent = (t2 - t1) / (total2 - total1) * 100这道题我的得分应该还不错,因为我在函数边界上做了处理:进程不存在时捕获FileNotFoundError并提示用户。如果你能在笔试编程题里写出这种对异常情况的判断,哪怕主体逻辑简单,也能让阅卷人感受到你写代码的习惯是严谨的。
4. 备考策略与踩坑实录
4.1 时间分配:不同起点的备考打法
如果你还有一个月左右的准备时间,我的建议是不要把时间平均分给所有知识点,而是按“产出价值”来排优先级。第一优先是 Linux 命令和 Shell 脚本,这部分性价比最高,学两天就能应付一大半选择题,而且几乎每份笔试都会大量出现;第二优先是 Python 基础和常用模块,重点练文件读取、字符串处理、正则表达式,这些都是编程题的常客;第三优先是网络基础,尤其是 TCP、HTTP、DNS 这三个高频主题;第四才是数据库原理,因为 MySQL 的索引和事务理解需要一些积累,短期冲刺效果有限。
如果基础比较薄弱,我的建议是先把自己定位成“能用工具解决问题的工程师”而不是“能把原理倒背如流的学生”。什么意思呢?就是你要会写脚本统计日志、会用top和vmstat定位负载问题、会给一张表设计索引。这些能力一旦建立,面对笔试会有一种“肌肉记忆”式的从容。相反,如果一上来就啃《深入理解计算机系统》,时间不够容易挫败,而且很多内容笔试未必考得到。
我自己的时间线安排是:前两周集中刷 Linux 和网络,每天晚上保证 2 小时实操;第三周开始刷 Python 编程题和数据库索引、事务;最后一周用两三天做整套模拟卷,按真实笔试的时间限制来卡自己。模拟卷的选择上,找牛客网和企业往年校招帖子就足够了,重点是练“限时答题”的感觉,因为笔试时每道题能分配的时间可能只有两三分钟。
4.2 我在笔试中踩过的三个坑
第一个坑是轻视选择题。我当时觉得选择题不值钱,结果错了四五道,后来对答案才发现丢分非常多。尤其是一些带命令输出的题,如果在 Linux 里实际操作过,三秒钟就能选出来;但如果只靠看书,很容易在“看起来都对”的选项里纠结。所以备考阶段一定要手敲命令,不能只看不练。
第二个坑是编程题不处理异常输入。我那场笔试的编程题,我第一版代码没有考虑文件不存在、日志格式不规范的情况,后来在模拟自测时才发现,如果某一行字段数不对,line.split()[0]会直接越界崩溃。笔试环节虽然不会真运行,但线上笔试系统有时候会跑测试用例,一旦踩到边界就直接零分。所以编程题写完一定要预留异常处理的逻辑。
第三个坑是简答题只写结论不写链路。比如题目问“如何排查服务器负载过高”,我一开始只写了“看 top、看 CPU、看 load”,这种答案拿不了高分。正确做法是把每一步的输入和判断条件写明白,比如“先用uptime看 load average,如果 1 分钟负载明显高于 15 分钟负载,说明是近期突增;再看top里 %us 和 %wa 的占比,如果 %wa 高说明 I/O 瓶颈,结合iostat看待处理器是哪个设备”。这种表达展示的是完整的排查思维,而不只是会几个命令。
4.3 笔试后的加试考点:聊深一轮才见真章
笔试通过后,往往还有一轮电话面试或技术面,这时候考察的深度会明显提升。面试官会围绕笔试里的场景题继续追问,比如“你刚才说用 Redis 缓存排行榜,如果 Redis 挂了怎么办”,或者“你写脚本监控进程 CPU,为什么不用ps而要读/proc”。这些追问是在验证你是真的理解原理,还是只是背了答案。
在准备技术面时,我建议把笔试里每道题的关键选择都准备一个“为什么”。比如:
- 为什么
TIME_WAIT要保留 2MSL 而不是 1MSL? - 为什么 MySQL 索引用 B+ 树而不是红黑树?
- 为什么抖动要做成批处理而不是逐条处理?
- 为什么监控系统要分成采集、存储、告警三层?
这些问题没有标准答案,但你要能把背后 trade-off 讲清楚。面试官不一定期待你给出最优解,而是想看你有没有能力在约束条件下做技术决策。
为了在面试阶段有东西可聊,建议在校期间尽量积累一两个贴近生产环境的项目,比如自己搭一套个人网站监控告警系统,用 Prometheus 采集指标,用 Grafana 展示面板,再用 Python 写一个告警推送机器人。哪怕功能简单,只要你能把采集指标的含义、告警阈值的设定逻辑、故障演练的过程讲清楚,在面试官眼里也比“我学过 Linux”要有说服力得多。
5. 笔试不只是考试,更是查漏补缺的机会
那次笔试最终的结果我记不太清了,但有一个感受很清晰:笔试前我以为自己最弱的是编程,考完才发现,真正让我丢分的反而是那些我以为闭眼都能答对的基础题。Linux 命令的细节、TCP 的状态变化、MySQL 索引的列顺序,这些知识点平时都能用,但一旦被从“使用场景”里拎出来单独提问,就特别容易暴露理解上的空洞。
这里插一个我用过的笨办法,但效率很高:把笔试里遇到的每一道错题,不管多简单,都重新在本地环境里复现一遍,并写一篇 200 字左右的笔记,解释“为什么当时选错了”。比如我发现自己在TIME_WAIT出现原因上理解偏了,就本地起了一个高并发的测试服务,用ss -s观察大量TIME_WAIT连接,再顺藤摸瓜去查主动关闭连接的是谁,最后彻底搞懂了。这种带着问题去操作的复习方式,效果比二刷参考书好十倍。
如果你现在正在准备运维开发方向的校招,我的建议是别太把笔试当成一道“门”。它更像是一次免费的体检,把你在操作系统、网络、数据库、脚本语言上的薄弱环节清清楚楚地标出来。认真复盘一次笔试,比闷头刷十套题收获更大。而且运维开发这个岗位的成长路径很宽,笔试只是第一步,后面还有压测、故障演练、容器化改造、监控系统建设这些真正硬核的事等着你。趁还在校招阶段,把底子打扎实,后面会轻松很多。