看到“哔哩哔哩2019秋招技术岗(系统工程师)笔试题”这个题目,我第一反应不是去回忆当年的选择题考了什么,而是想聊聊这套题背后真正想筛选的人。系统工程师这个岗位,在视频网站这类业务形态下,说白了就是既要懂Linux、网络、数据库,又要懂中间件、监控、自动化,还得扛得住突发流量和故障。笔试题里那些看似零散的知识点,最后都指向同一个核心能力:给你一批机器,你能不能从零把一个生产系统搭起来,并且长期稳定地维护下去。
这恰好对应了最近很热的那个话题——“作为一个运维工程师,如何在生产环境从零搭建一个系统并做好后续维护”。我做了这么多年系统工程师,参加过校招也当过面试官,可以负责任地说,这题就是那套笔试题的“隐藏大题”。这篇文章我就借这个机会,把这道大题从头到尾拆一遍,覆盖容量规划、基础环境初始化、中间件部署、监控告警、日常维护和故障排查,希望能给准备面试的朋友,以及刚入行的运维新人一些真正能落地的参考。
1. 这道笔试题的真考点:不是背知识点,而是考察系统化工程能力
1.1 表面题面与真实能力模型的差距
很多人备考系统工程师笔试时,习惯去刷Linux命令题、网络协议题、数据库SQL题,觉得把知识点背熟就能过。但如果你真看过BAT、B站这类互联网公司的系统工程师笔试题,会发现题目虽然以选择题、简答题的形式出现,但考察的从来不是孤立的知识点记忆,而是你能不能把这些知识串成一条完整的链路。
举几个典型的例子。笔试里考“Linux系统中如何查看系统负载”,表面答案是uptime或top,但考官真正想看到的是:你知道load average的数值和CPU核数之间的关系吗?你能区分CPU密集型负载和I/O等待导致的负载升高吗?当生产环境出现负载飙高时,你的排查思路是什么?再比如考“MySQL主从复制的原理”,表面答案是多线程回放binlog,但真正的问题可能是:主从延迟了怎么办?binlog格式选row还是statement?从库误删数据怎么恢复?
所以,系统工程师这个岗位的笔试题,本质上是在有限的时间里,通过少量题目来考察你对系统整体架构的认知深度。它要求你脑子里不是一个个零散的知识点,而是一张完整的系统运行拓扑图:流量从用户端进来,经过DNS、负载均衡、接入层、应用层、缓存、消息队列,最后落到数据库和存储上,每一层都有对应的组件、监控指标、常见故障和维护手段。你有没有真正从零搭过一套系统,从你的回答里是藏不住的。
1.2 从岗位JD反推知识结构
我们再看一下系统工程师岗位的常见JD:负责公司业务的日常运维、保障业务连续性、参与系统架构评审、推进自动化运维建设、处理突发故障。这些要求全部指向同一个核心能力:交付一个可运行、可维护、可扩展的生产系统。
我把系统工程师完整的知识结构拆成了六个方面,这基本就是那套笔试题的覆盖范围:
| 知识域 | 核心内容 | 对应的生产场景 |
|---|---|---|
| Linux基础 | 文件系统、进程管理、权限、systemd、内核参数 | 系统安装配置、故障排查、性能调优 |
| 网络基础 | TCP/IP、HTTP/DNS、负载均衡、防火墙 | 接入层架构、网络问题定位、安全策略 |
| 数据存储 | MySQL、Redis、对象存储 | 数据持久化、缓存加速、备份恢复 |
| 中间件 | Nginx、Kafka/RabbitMQ、ZooKeeper | 流量接入、异步解耦、分布式协调 |
| 自动化运维 | Shell/Python、Ansible、CI/CD、监控平台 | 批量部署、变更发布、告警处理 |
| 稳定性治理 | 容量规划、高可用、灾备、故障演练 | 大促保障、限流降级、应急预案 |
这套知识结构不是凭空想的,而是从“从零搭建一个生产系统并维护好它”这个完整流程里倒推出来的。你每掌握一个模块,就能回答出这套系统里的一块拼图,当你拼完所有模块,你不仅知道笔试题的答案,更知道这些答案在生产环境里到底意味着什么。
2. 生产环境从零搭建:主机与基础环境到底怎么落地
2.1 容量规划与机器选型:先算清楚再动手
很多新手拿到“从零搭建系统”这个任务,第一反应是安装操作系统、配环境,这其实是本末倒置。真正有经验的系统工程师,拿到需求后会先做容量规划。为什么?因为机器买多了浪费成本,买少了上线就宕机,这个度把握不好,后面全是坑。
容量规划核心就三件事:算QPS、算存储、算带宽。假设你要上线一个日活10万用户的视频类应用,先估算核心接口的QPS。日活10万,假设每个用户每天发起200次请求,总共2000万次请求,按8小时业务高峰折算,平均QPS约700,考虑到高峰是平均的3到5倍,核心接口的峰值QPS大概在2000到3500之间。一台4核8G的云主机,经过优化后扛500到1000 QPS问题不大,那你至少要准备4到6台应用服务器。存储方面,10万用户每天产生约100GB的日志和上传数据,保留30天就得3TB原始容量,按三副本冗余算,就是9TB左右,这还没算数据库。带宽就更直观了,视频类业务按平均码率2Mbps算,高峰期同时在线5000人,需要约10Gbps出口带宽。
做完这些估算,你才能回答笔试题里最常见的那个问题:给你一个业务需求,你怎么设计系统架构?当你把容量账算清楚,架构自然就出来了:前端挂Nginx做接入和静态资源分发,中间挂应用集群,底层用MySQL存核心数据、Redis做缓存、消息队列削峰,存储用对象存储扛大文件。每一步都有数据支撑,这才是系统工程师的思考方式,而不是凭感觉选组件。
2.2 操作系统安装与初始化清单:标准化是第一原则
容量规划做完之后,才进入真正的搭建环节。关于操作系统,这里必须强调一个原则:标准化。生产环境的每一台机器,从操作系统版本、分区方案到内核参数,都应该保持一致。我自己踩过的坑是,不同机器内核版本不一致,结果在排查一个网络问题的时候,同一套sysctl参数在两台机器上表现完全不同,那叫一个痛苦。
初始化清单我一般是这样做的。系统层面,统一使用CentOS 7.9或Ubuntu 20.04 LTS这类稳定版本,分区单独划出/data给业务数据,避免系统盘被日志写满。安装完系统后,第一批必调的内核参数包括:vm.swappiness调低到10以下,避免swap频繁交换影响性能;fs.file-max调大到655360以上,防止高并发下文件句柄耗尽;net.core.somaxconn和net.ipv4.tcp_max_syn_backlog适当调大,应对突发连接。然后是基础服务,配置公司内部的NTP时间同步服务器,服务器时间漂移会导致日志排查错乱、分布式系统数据不一致,这是很多人会忽略的问题;配置公司内部的DNS解析,避免每次域名解析都走公网,延迟高还不安全;配置统一的Yum或APT源,保证所有机器安装的软件版本一致。
SSH加固也必须在这个阶段做。生产环境绝不能开放密码登录,全部改用密钥认证,禁用root直接登录,SSH端口建议改掉,虽然不能说这样就绝对安全,但能挡住绝大部分扫描攻击。做完这些,我还会把每台机器的hostname、IP、用途、负责人信息都登记到资产表里,后续的监控、告警、自动化操作都依赖这份资产信息。基础环境搞标准化了,后面几十台、几百台机器的管理才有基础,不然天天给每台机器“擦屁股”就够你忙的。
2.3 基础环境初始化的常见坑:时间、句柄、分区
基础环境搭建过程看似简单,实际上暗坑不少,这里分享几个我真实遇到过的,也特别像笔试题里的“事故分析题”。
第一个坑是分区规划不合理。我见过一台业务机器,根分区只给了20G,MySQL的datadir放在默认路径/var/lib/mysql,结果跑了一个月磁盘直接满了,数据库只读,业务全线挂掉。后来排查才发现,binlog和慢查询日志全写在系统盘上。合理的做法是:数据盘单独挂载,日志、临时文件、核心数据都放到容量充足的数据分区,并且提前做好磁盘空间监控告警。
第二个坑是文件句柄限制。很多应用(比如Nginx、Java应用)在高并发下会报“Too many open files”。这不是系统bug,而是ulimit默认值太低。CentOS 7默认的ulimit -n是1024,对生产环境来说远远不够。需要在/etc/security/limits.conf里给进程用户设置nofile为65535或更高,同时确认systemd服务文件里的LimitNOFILE也同步修改了,否则不生效。
第三个坑是时间不同步导致的连锁反应。有一次线上一个基于时间戳的分布式ID生成服务突然出现重复ID,排查了半天,最后发现是几台新加的机器没有配置NTP,系统时间比标准时间慢了将近一分钟。所以我在初始化检查里专门加了一条:配置完NTP后,必须用ntpdate -q 时间服务器地址确认时间偏差在100ms以内才算通过。
3. 核心组件部署:数据库、缓存、队列与接入层的选型落地
3.1 数据库初始化:MySQL参数不是默认就能用
系统里最不能出问题的组件就是数据库,所以数据库的初始化也是笔试题必定会覆盖的重头戏。面试官问你“MySQL如何优化”,如果只回答“加索引、开慢查询日志”,分数一定不高,因为生产环境的MySQL,从安装那一刻起就要为性能和稳定做规划。
我习惯用二进制方式部署MySQL,不用系统自带的包管理器,原因很简单:版本可控、目录可控、参数可控。部署完成后,第一件事是调整my.cnf参数。innodb_buffer_pool_size一般设置为物理内存的70%左右,这是InnoDB的缓存池,直接影响读写性能;innodb_log_file_size建议设置为512M到1G,太小会导致频繁刷盘、性能抖动;binlog_format必须设置为row模式,虽然会产生更大的binlog,但对数据一致性和误操作恢复有极大帮助。慢查询日志必须打开,long_query_time设为1秒,这是排查SQL性能问题最重要的数据来源。
数据库的高可用一定不能省。主从复制是标配,从库至少一个,既做读写分离又做备份源。主从搭建完,必须验证复制是否正常:在从库执行SHOW SLAVE STATUS\G确认Slave_IO_Running和Slave_SQL_Running都是Yes,然后写一条测试数据看看从库能不能同步到。这一步做不好,后面主库挂了切从库,发现从库数据落后几万条,那就真的是事故了。
备份策略更要在初始化阶段定好。每天凌晨用mysqldump做全量备份,配合binlog做增量恢复,备份文件必须异地存储,绝不能和数据库在同一台机器上。备份策略好不好,不是看备份过程顺不顺利,而是看恢复演练能不能过关。我的标准是:每季度至少做一次从空库开始的全量恢复+binlog增量恢复到任意时间点的演练,没做过恢复演练的备份等于没有备份。
3.2 缓存与消息队列:Redis、Kafka选型与核心参数
视频网站这类业务,数据库下面一定要有缓存层和消息队列层,它们决定了系统能不能扛住突发流量。这些中间件的部署参数,也是系统工程师笔试的重点考察方向。
Redis部署看似简单,但有几个关键点极易踩坑。第一,maxmemory必须设置,否则Redis会把机器内存吃满触发OOM,我建议设置成物理内存的70%到80%,给操作系统和fork子进程留足余量。第二,maxmemory-policy要按业务场景选,缓存场景用allkeys-lru,需要精确控制的场景用volatile-lru。第三,开启AOF持久化并设置appendfsync everysec,兼顾数据安全和性能。Redis主从结构要为从节点配置replica-read-only yes,防止误写入导致主从数据不一致。
Kafka这里要重点说,因为很多新手会忽略它的一个特点,就是部署前必须先想好主题分区数。分区的数量需要跟消费端的并发度匹配,同时也要考虑分区过多带来的文件句柄占用和rebalance时间变长。一般情况下,一个主题的分区数建议是消费组消费者数量的整数倍,比如4个消费者就配8个或12个分区,这样负载相对均衡。Kafka的log.retention.hours按日志保留需求设置,比如168小时(7天),log.segment.bytes用默认的1G就行。队列监控方面,生产环境一定要监控消费延迟,如果消费端挂了一个小时,积压了几百万条消息,等发现的时候可能已经影响到业务数据的实时性了。
3.3 接入层与高可用:Nginx、负载均衡和健康检查
用户流量进入系统的第一个入口是接入层,这一层的高可用直接决定了系统能不能对外服务。部署Nginx时,除了常规配置,我后来才意识到还有一个非常关键的细节:启用了upstream后,必须配置合理的健康检查参数。max_fails和fail_timeout要调成适合业务的值,比如连续3次失败、30秒内标记为不可用。如果不配,Nginx默认将失败的请求转发给挂掉的后端,用户就会间歇性看到502。
接入层的高可用方案,传统的做法是Keepalived + Nginx主备模式。Keepalived通过VRRP协议提供一个虚拟IP,主节点挂了,备节点自动接管,整个过程对用户透明。这个方案配置不复杂,但要注意:主备之间必须开启组播或单播通信,而且建议在Keepalived的脚本里加一个对Nginx进程的检测,不要只检测Keepalived本身存活。为什么?因为如果Nginx进程挂掉了但Keepalived还活着,虚拟IP不会漂移,用户请求照样是502,等于高可用失效了。
现在云上环境更推荐直接用云负载均衡,由云平台负责健康检查和流量切换,省心很多。但不管是自建还是云上,核心的检查项都是:后端服务器的端口存活检测、HTTP状态码检测、以及后端挂掉时的自动摘除与恢复。这一层配好了,业务架构的地基才算稳固。
4. 自动化、监控与发布:从“能跑”到“可持续维护”的关键
4.1 从人工到自动化:配置管理与CMDB建设
系统搭起来只是第一步,更难的是后续维护。如果所有操作都靠人肉SSH到机器上执行,几十台机器还能勉强应付,到了上百台机器,效率低下不说,还容易出错。这也是为什么系统工程师面试里,自动化运维几乎是必考题。
自动化运维的第一步是搭建配置管理工具。以Ansible为例,它的优势是无Agent、基于SSH、学习曲线平缓。我会把前面说的操作系统初始化清单写成Ansible Playbook,新机器交付后直接执行一遍,所有初始化动作自动完成。Playbook里不仅包含内核参数调整、NTP配置、DNS配置、SSH加固,还包含基础监控Agent的安装。这样一来,新机器从交付到纳入监控体系,时间从过去的人工操作半小时压缩到几分钟,而且保证了每台机器的状态完全一致。
自动化运维的第二步是建设CMDB(配置管理数据库)。以我的经验,CMDB不一定要用多复杂的平台,核心是把资产关系理清楚:这台机器属于哪个业务线、运行什么应用、依赖哪些数据库、负责人是谁、告警通知谁。只有把这些信息结构化,后面的监控告警、故障排查、容量管理才有数据基础。很多团队在业务量小的时候觉得CMDB是负担,等出了事故找机器、找人、找依赖关系找半天的时候,才知道CMDB的价值。
4.2 监控告警体系搭建:四类监控信号缺一不可
系统上线之后,监控就是你的眼睛。一个系统工程师如果只能回答出“用prometheus监控CPU和内存”,那离合格还有很大距离。一套完整的监控体系,至少包含四个维度:基础监控、日志监控、链路追踪和拨测监控。
基础监控用Prometheus + Grafana是当前的主流方案。需要采集的指标不止是CPU、内存、磁盘、网络,还包括每个组件的核心指标:MySQL的QPS、连接数、慢查询数、主从延迟;Redis的命中率、内存使用率、阻塞客户端数;Nginx的QPS、5xx状态码比例、平均响应时间;Kafka的消费延迟、分区leader分布。每个指标都要设置合理的告警阈值,告警分级要清晰:P0是影响业务的故障(比如数据库挂了、服务大面积5xx),电话通知+立即响应;P1是潜在风险(比如磁盘使用率超80%、Redis内存告警),邮件/钉钉通知;P2是日常提醒,按周汇总。
日志监控也必不可少。建议搭建ELK或轻量化的Loki方案,把所有机器上的应用日志统一收集、集中检索。日志的价值不仅在于排障,更在于发现潜在问题,比如通过分析Nginx访问日志中的5xx状态码趋势,可以提前发现某个接口的稳定性隐患。链路追踪(比如SkyWalking、Jaeger)在微服务架构下尤其重要,没有它,一个请求经过三四个服务的耗时分布你就完全看不清楚。拨测监控则是从用户视角模拟访问,能发现机房网络问题、域名解析异常等内部监控发现不了的问题,建议至少5分钟一次。
4.3 发布与变更管理:最容易被忽视的稳定性杀手
排查了很多次生产故障之后,我得出了一个很扎心的结论:大多数故障不是硬件问题,而是变更引发的。变更包括代码发布、配置修改、数据库变更、服务器扩容缩容,等等。做好变更管理,能避免70%以上的线上事故。
具体的落地方式,是建立一套完整的发布流程。代码发布必须走CI/CD流水线,经过编译、单元测试、镜像构建,然后部署到测试环境验证,最后才发布到生产环境。生产发布一定要支持灰度发布:先发布一台机器,观察监控指标正常后,再逐步扩展到整个集群。一旦发现异常,能够一键回滚到上一个版本。这一点上,Kubernetes等容器化平台的滚动更新和回滚机制非常有用,如果公司还没容器化,也要通过脚本做好版本管理和回滚预案。
配置变更同样需要规范。我见过很多次线上事故,是有人在生产机器上临时改了一个配置项,改完没有同步给其他机器,结果流量一上来各机器行为不一致,引发了雪崩。我的办法是:所有配置变更必须走配置中心或版本控制,禁止在机器上临时改配置,改完必须通过自动化工具下发到所有机器,并在变更记录里留下人和时间。数据库变更更要注意,比如加索引这类操作,如果表很大,MySQL 5.6以下版本会锁表,必须在业务低峰期执行,并且先在从库执行验证后再切换。
5. 后续维护的核心工作:巡检、备份、扩容与故障排查
5.1 日常巡检与备份恢复演练:维护工作不能靠“等故障”
系统交付之后,每天的维护工作更考验耐心和专业性。日常巡检不是随便看看监控面板就完事,而是要有一套固定的检查节奏和检查项。
我的巡检清单包含四个层面。第一,系统层:确认CPU负载趋势、内存使用率、磁盘空间、inode使用率、系统日志有没有异常报错。第二,应用层:确认Nginx的QPS和5xx比例是否正常、MySQL的连接数和慢查询有没有异常增长、Redis的命中率和内存使用是否健康、消息队列的消费延迟有没有在正常范围。第三,安全层:检查登录日志有没有异常IP尝试登录、关键文件有没有被篡改、安全补丁是否需要更新。第四,容量层:根据近期的增长趋势,推算磁盘、内存、带宽还能支撑多久,提前安排扩容计划。
备份检查要纳入巡检项,不能只依赖备份脚本。每天的备份任务执行后,要检查备份文件是否存在、大小是否正常(突然变小可能意味着备份失败或数据丢失)。在此基础上,我还坚持一个原则:每季度至少做一次恢复演练。恢复演练不是走过场,而是真正把备份文件恢复到一台临时机器上,启动数据库,验证数据完整性,再模拟一个“误删一张表”的场景,尝试从备份和binlog恢复到误删前的状态。只有经过这种演练,你才能确定真出事时你是有把握的。
5.2 核心故障排查思路:从现象到根因的五步定位法
故障排查能力是系统工程师最核心的竞争力,也是笔试题里最难的场景题。我在带新人时,会反复强调一套排查方法,普通人容易像无头苍蝇一样乱试,但老手都是按套路出牌的。
第一步,确认影响范围。先搞清楚是单台机器的问题,还是整个集群的问题;是某个接口变慢,还是全站不可用;是只影响部分用户,还是所有用户都受影响。这一步能快速缩小排查方向。第二步,看监控回顾。查看故障开始前后,机器负载、网络流量、业务指标有没有突变,监控面板通常能直接告诉你问题出在哪个环节。第三步,看日志定位。登录到可疑机器,先看系统日志/var/log/messages,再看应用日志,搜索当时时间点的错误关键字,比如“OutOfMemory”“Connection refused”“deadlock”。第四步,做现场验证。用命令验证你的猜测:top看进程CPU、free -h看内存、iostat -x 1看磁盘I/O、ss -anp看连接数、ping和traceroute看网络。第五步,临时止血+根因修复。先通过重启、切换流量、降级等手段恢复业务,再深入分析根因,做永久修复。
举一个我实际遇到的案例。某天线上告警,服务A的接口耗时翻倍,用户开始投诉。我先确认影响范围:只有服务A受影响,其他服务正常。然后看监控:服务A所在机器的CPU使用率99%,但应用本身的QPS并没有明显增长。看日志发现大量“GC overhead limit exceeded”,基本可以判断是JVM内存问题。用jstat查看GC情况,发现Full GC非常频繁,老年代持续增长。用jmap导出堆转储,分析后发现一个缓存类对象持有大量数据导致内存泄漏。定位到根因后,先通过重启快速恢复业务,然后开发修复代码,走发布流程修复。事后复盘,这类问题如果在监控里加上JVM的GC指标和堆内存使用率告警,其实可以更早发现,根本不用等用户投诉。
5.3 系统维护常见问题速查表
我把生产环境里最常遇到的几个问题整理成了一张速查表,建议收藏备用。这些场景也可以当成面试场景题来准备,想清楚每行的排查思路。
| 问题现象 | 可能原因 | 快速定位命令 | 处理建议 |
|---|---|---|---|
| 服务响应变慢,CPU高 | 应用死循环、SQL全表扫描、GC频繁 | top、jstack、show processlist | 抓线程栈/慢SQL,定位热点后优化或扩容 |
| 磁盘写入失败 | 磁盘满或inode耗尽 | df -h、df -i | 清理日志、扩容数据盘 |
| 大量TIME_WAIT连接 | 短连接过多、负载均衡配置不合理 | ss -s、netstat -anp | 开启连接复用、调大端口范围、长连接改造 |
| 数据库主从延迟 | 大事务、从库磁盘慢、DDL锁表 | SHOW SLAVE STATUS\G | 优化大事务、升级从库硬件、错峰执行DDL |
| 内存持续增长 | 内存泄漏、缓存配置过大 | free -h、top、jstat | 分析堆转储、限制缓存内存、及时重启验证 |
| Redis出现阻塞 | 大key操作、fork耗时、AOF重写 | redis-cli slowlog get | 拆分大key、错峰AOF重写、关闭耗时命令 |
排查故障时有一个心态建议:越是紧急的时刻,越要冷静按步骤来。我见过太多人在故障发生时胡乱重启、随手改参数,结果把现场破坏了,最后连根因都找不到。正确的做法是先定位再操作,每做一步都记录时间点和结果,方便事后复盘。这套方法不仅能帮你解决笔试里的“故障分析题”,更是日常工作中保护自己的基本功。
做了这么多年系统工程师,我最大的体会是:这套笔试题目背后的真实问题,不是“你会不会做这道题”,而是“你敢不敢把一个系统从零交付到线上,并且为它长期负责”。从容量规划、基础环境初始化,到数据库、缓存、中间件部署,再到监控告警、自动化运维和故障排查,每一个环节都是经验的积累,也都是笔试和面试真正的分水岭。希望这篇拆解,能帮你把脑子里零散的知识点串成一张完整的系统工程师能力地图。如果你也在准备类似岗位的面试,我的建议是别只刷题,去真正找几台机器,从零搭一套环境出来,你亲自踩过的每一个坑,都比背下来的答案值钱得多。