
“奇安信2019春招服务端开发试题”我看到这个标题的第一反应是又是一份让无数人栽在“基础题”上的卷子。这几年我帮不少学弟学妹做过春招复盘也反复跟人强调过一句话——服务端开发的笔试筛的不是谁刷题多而是谁的基础知识体系是完整的。奇安信作为国内网络安全领域的企业它的服务端岗位笔试题在业界一直以“范围广、基础深、工程感强”著称。当年那一套卷子做下来很多人最大的感受是算法题没多难反而是那些看似简单的网络和系统题处处是坑。这篇文章不是要给你背答案而是想把那份试卷背后的考点逻辑拆开讲清楚服务端开发笔试到底在考什么、为什么这样考、以及用什么样的复习节奏能在有限时间内把分数拿满。无论你是正在准备春招的应届生还是想转岗服务端开发的工程师这篇复盘都值得你静下心看一遍。尤其是那些觉得自己“LeetCode刷了三百题就能横着走”的同学我建议你先看完第二章再下结论。1. 奇安信服务端笔试题的考点地图一份试卷想筛选什么样的人先给没参加过这类笔试的同学还原一下现场。奇安信2019春招服务端开发的笔试题型大致分三块选择题包括单选和多选、简答题、编程题。总时长一般在90到120分钟题量不小选择题大概有20到30道简答题3到5道编程题2到3道。这个结构是当年很多网络安全和互联网公司的通用配置但它考查的重心非常明确不追求你把某一道难题做出来而是看你在一堆中等难度的题目里能不能保持稳定的正确率。我当时拿到卷子后快速扫了一遍印象最深的是选择题部分几乎覆盖了服务端开发的全部基础领域计算机网络、操作系统、Linux、数据库、编程语言基础中间还穿插了几道和安全相关的常识题毕竟是安全公司。这种出题方式背后的逻辑很清晰——服务端开发是一个对“短板”极其敏感的岗位。你可以不精通某一项但你绝对不能完全不懂某一项。因为真实的服务端系统是网络、操作系统、数据库、存储、缓存、中间件共同协作的产物任何一个环节出现基础盲区线上出问题的时候你连排查的方向都不知道。我把这份试卷以及同类型公司服务端笔试题的考点分布整理成了一个表格方便你对照自己的复习情况考点模块常见出题形式大概占比难度感受计算机网络选择题、简答题20%-25%中等但概念容易混淆操作系统选择题、简答题15%-20%中等重点集中数据库选择题、简答题、SQL手写15%-20%中等SQL题容易细节翻车Linux与Shell选择题、简答题10%-15%偏简单但覆盖面广编程语言基础选择题10%-15%看你主语言熟不熟算法与数据结构编程题20%-25%难度不大边界条件多注意看这个表算法题只占四分之一左右剩下的全是基础知识的考察。这和很多同学的复习策略是完全相反的——大家花了80%的时间刷算法题剩下20%的时间草草过一遍基础结果选择题一错错一片。这不是个别现象我接触到的笔试复盘里至少一半的人挂在选择题上而这恰恰是笔试中最容易通过短期背诵拿分的部分。再说说这份试卷的“安全基因”。奇安信毕竟是网络安全起家的公司它的服务端笔试题里偶尔会出现和Web安全、加密、认证相关的题目比如SQL注入的原理与防范、HTTPS的握手过程、对称加密与非对称加密的区别。这类题目不需要你有多深的安全攻防经验但基本的安全常识必须要有。我在复习时把这部分和计算机网络合并在一起看效果不错后面会详细展开。所以这份卷子到底想筛选什么样的人我的结论是它要的不是“算法竞赛选手”而是“基础扎实、工程思维正常、遇到问题知道从哪个方向排查的人”。这个筛选标准放在今天的服务端招聘中依然适用甚至比2019年更加强调。你提前想明白了这一点就不会再傻乎乎地只刷题不看书了。2. 网络与系统服务端笔试的“隐形护城河”服务端开发的笔试里计算机网络和操作系统是最能拉开差距的两个模块。算法题大家都会准备但网络和系统的细节很多人是似懂非懂的。偏偏这两个模块又是服务端开发日常工作中用到最多的知识——你的服务要处理请求就得懂TCP和HTTP你的服务要跑在服务器上就得懂进程、线程和内存。2.1 TCP与HTTP高频考点背后的真实场景先回忆几道我当时遇到的典型题目TCP建立连接为什么需要三次握手两次行不行大量TIME_WAIT状态连接出现在什么场景如何优化HTTP的GET和POST有什么区别底层传输上有本质差异吗HTTPS的握手过程大致是什么样的为什么需要证书这些题单拎出来每一个你都能在网上找到标准答案。但笔试的难处在于它喜欢把两个相似概念放在一起让你辨析。比如“TCP三次握手和HTTP的连接复用有什么关系”“HTTP/1.1的Keep-Alive和TCP的Keep-Alive是不是一个东西”。这种组合型题目只背答案是很难对付的。先说三次握手。我推荐的答题思路是这样的三次握手的核心目标是让通信双方确认彼此的收发能力都正常。第一次握手客户端发送SYN服务端收到后知道自己接收能力没问题、客户端的发送能力没问题。第二次握手服务端回复SYNACK客户端收到后知道自己发送能力没问题、服务端的接收和发送能力也没问题。但此时服务端还不知道自己的发送能力是否正常所以还需要第三次握手客户端回一个ACK服务端收到后确认自己的发送能力没问题。两次握手的缺陷在于服务端无法确认自己的发送链路是否通畅而且无法处理客户端由于网络延迟产生的失效连接请求。再说TIME_WAIT。这个考点几乎年年出现因为它的产生场景太典型了——高并发短连接服务。主动关闭连接的一方在收到对端FIN并回复ACK后会进入TIME_WAIT状态持续2MSL。在Linux默认配置下这个时间大约是60秒。如果你的服务端每秒处理几千上万个短连接请求就会出现大量TIME_WAIT连接堆积占用端口和内存导致新连接无法建立。优化手段有几类一是调整内核参数比如net.ipv4.tcp_tw_reuse和net.ipv4.tcp_timestamps配合使用二是改造应用层尽量使用长连接三是在架构层引入连接池。但注意网上很多人说直接开tcp_tw_recycle这个参数在NAT环境下有严重的副作用容易导致连接被丢弃新版内核已经移除了它。答题时如果能写出这层思考说明你真的理解而不是背答案。关于HTTPS握手我当时用了一个比喻来帮助记忆HTTPS握手就像是两个人要在一间透明的房间里对话他们先在门口互相验明正身证书验证然后商量出一把只有他俩能用的钥匙会话密钥协商最后才关上门用钥匙加密通话加密传输。证书的作用是防止中间人伪装成服务器对称加密用来保证传输效率非对称加密只用在密钥协商阶段。答题时把这三层逻辑讲清楚分数不会低。2.2 操作系统死锁、并发与内存管理的“送分”陷阱操作系统的题目在笔试题里属于“你背过就会没背过就蒙”的类型。考点非常集中进程与线程的区别、死锁产生的四个条件及处理策略、进程间通信方式、虚拟内存和页面置换、线程池参数设置。这些知识在面试中也会被反复追问笔试阶段更像是帮你划重点。进程和线程的区别我建议从三个维度回答资源拥有者、调度单位、并发粒度。进程是资源分配的基本单位拥有独立的地址空间和系统资源线程是CPU调度的基本单位共享所属进程的地址空间和资源。所以多进程编程的隔离性更强、更稳定但创建和切换的开销更大多线程编程更轻量、通信更方便但需要自己处理共享资源的同步问题。答题时如果能顺手写上“线程崩溃可能导致整个进程退出而进程崩溃不会直接拖垮其他进程”会让面试官觉得你有真实工程经验。死锁的四个必要条件——互斥、占有并等待、不可剥夺、循环等待——这个没什么好说的必须烂熟于心。但笔试更爱考的是“如何避免死锁”这就需要你理解每种策略的本质。破坏互斥条件不现实因为资源本身就有互斥特性破坏占有并等待可以要求进程一次性申请所有资源破坏不可剥夺可以在资源无法满足时释放已占资源破坏循环等待可以给资源编号并强制按序申请。另外银行家算法这类经典的避免死锁算法也要能说个大概它背后的思想是“系统在分配资源前先判断是否处于安全状态”。内存管理这块我遇到过一道印象很深的题给定一个页面访问序列分别用FIFO和LRU算法计算缺页次数。这种题没有技巧就是一步一步画表算。但很多人会栽在细节上——比如初始时内存为空前几次访问都算缺页比如LRU要更新最近使用时间而FIFO只看出场顺序。建议你在复习时把OPT最优置换、FIFO、LRU三种算法放在一起对比着练顺便记住LRU的硬件实现方式计数器或栈因为有些选择题会从实现角度出题。还有一个容易被忽略的考点是并发工具。比如Java里的synchronized和ReentrantLock的区别、volatile的可见性和有序性、线程池的核心参数核心线程数、最大线程数、阻塞队列、拒绝策略。这些知识点不光是笔试要考后面的技术面试必定会深入追问。我的建议是笔试复习阶段就把它们当面试题来准备一举两得。3. 数据库与Linux从送分题到翻车现场的距离数据库和Linux是服务端笔试里的“性价比之王”。这两个模块的考点非常固定不需要太高深的数学或算法基础只要系统复习过基本都能拿分。但恰恰因为简单很多人掉以轻心在SQL语法和命令细节上翻车。3.1 索引、事务与SQL数据库题的三种考法数据库的笔试题目几乎逃不出这三类索引原理、事务特性、手写SQL。每类都有一些经典陷阱。索引原理题核心是B树。你要能回答清楚几个问题为什么InnoDB用B树而不是B树、红黑树或哈希表B树的非叶子节点不存数据只存索引所以同样大小的页能容纳更多索引项树的高度更低磁盘IO次数更少B树的叶子节点用链表串联范围查询时只需要遍历链表效率远高于B树的多次回溯访问B树的叶子节点存储所有数据查询性能稳定。而哈希索引适合等值查询但不适合范围查询所以InnoDB的默认索引结构是B树。聚簇索引和非聚簇索引的区别也经常考。聚簇索引的叶子节点就是数据行本身一张表只能有一个聚簇索引通常是主键非聚簇索引的叶子节点存储的是索引列的值和主键值查询时需要回表。如果查询的列都包含在索引里就可以实现覆盖索引避免回表。这些都是服务端开发写SQL时优化慢查询的基础。事务这块ACID四个特性是送分题但事务隔离级别才是真正的考点。四个隔离级别——读未提交、读已提交、可重复读、串行化——分别解决脏读、不可重复读、幻读的问题。MySQL的默认隔离级别是可重复读但InnoDB通过间隙锁可以在可重复读级别下一定程度避免幻读。这个细节值得多写两句因为它体现了数据库引擎对SQL标准的扩展答题时能体现你的深入理解。手写SQL题是我见过翻车率最高的题型原因不是不会写而是审题不仔细。我给你还原一道典型的题目有两张表学生表sid, sname, sage和选课表sc, sid, cid, score要求查询“平均成绩大于80分的学生姓名及其平均成绩按平均成绩降序排列”。很多人一上来就写SELECT s.sname, AVG(sc.score) AS avg_score FROM student s JOIN sc ON s.sid sc.sid GROUP BY s.sname HAVING AVG(sc.score) 80 ORDER BY avg_score DESC;这个写法看似没问题但如果学生表里有同名同姓的人GROUP BY s.sname就会把两个不同学生算到一起结果出错。正确的做法是按学生ID分组SELECT s.sid, s.sname, AVG(sc.score) AS avg_score FROM student s JOIN sc ON s.sid sc.sid GROUP BY s.sid, s.sname HAVING AVG(sc.score) 80 ORDER BY avg_score DESC;再说一种常考的题型——分组取每组TopN。比如“查询每门课程成绩最高的前两名学生的姓名和成绩”。这类题在MySQL 8.0里可以用窗口函数SELECT cid, sid, score FROM ( SELECT cid, sid, score, ROW_NUMBER() OVER (PARTITION BY cid ORDER BY score DESC) AS rn FROM sc ) t WHERE rn 2;如果笔试环境是MySQL 5.7没有窗口函数就需要用变量或自连接来实现写法复杂不少。所以我建议你复习时把窗口函数和传统写法都准备一下以防万一。3.2 Linux命令与排查思路考的是“肌肉记忆”Linux相关的题目在笔试里不算难但覆盖范围很广。常见的考察方式有给定一个场景让你写出对应的命令或排查思路。场景一服务负载突然升高如何排查。我的标准答案是四步走第一步用top或htop看CPU和内存占用找到CPU占用最高的进程第二步用ps -ef或ps aux确认这个进程是什么是不是我们自己的业务进程第三步如果确认是业务进程用top -Hp pid查看线程级别的CPU占用或者用jstackJava应用导出线程栈分析是GC频繁、锁竞争还是死循环第四步如果CPU高但应用线程正常再看是不是有频繁的Full GC用jstat查看GC情况。这个答题思路不仅适用于笔试你入职后去排查线上问题也是这个流程。场景二如何查看某个端口是否被监听。答案是netstat -tlnp | grep 端口号或者ss -tlnp | grep 端口号。顺便说一句ss命令比netstat更高效因为netstat在连接数多的时候会慢得让人想砸电脑。如果你想看网络连接的状态分布可以用netstat -an | awk {print $6} | sort | uniq -c这个组合命令在分析TIME_WAIT数量时非常有用。场景三如何从日志文件中筛选出指定时间段内错误次数最多的IP。这需要用awk和sort组合awk $4 08:00:00 $4 09:00:00 $9 ~ /500|502|503/ access.log | awk {print $1} | sort | uniq -c | sort -rn | head -10场景四编写一个Shell脚本实现定期清理3天前的日志文件。这道题考察的是crontab和find命令的组合find /var/log/myapp -type f -name *.log -mtime 3 -exec rm -f {} \;然后写入crontab0 3 * * * /opt/scripts/clean_log.sh在Linux这块我的复习建议是不要死记硬背命令参数而是把命令放到具体场景里去记。你只要真正动手配置过一台服务器这些命令就是肌肉记忆根本不用背。4. 算法与编程笔试能编译不等于能拿分奇安信2019春招服务端笔试题里的编程题整体难度放在今天的眼光来看并不高基本是LeetCode中等偏下水平。但正是这种“不难”的题反而把很多人筛掉了——因为他们写代码时不注意边界条件、不处理输入输出的细节、不关注时间复杂度结果就是用例过了一半。4.1 语言基础选择题里藏着C和Java的爱恨情仇编程语言的选择题往往决定了你是稳拿基础分还是丢冤枉分。我当时选的Java所以对Java的考点更熟悉一些HashMap的底层实现数组链表/红黑树、ConcurrentHashMap的分段锁和CAS机制、ArrayList和LinkedList的区别、String为什么不可变、例外机制受检异常和非受检异常等等。HashMap是笔试选择题的常青树。你要知道JDK 1.8之后的HashMap底层结构是“数组链表红黑树”当链表长度超过8且数组长度大于等于64时链表会转化为红黑树。put的大致流程是先计算key的哈希并对数组长度取模找到桶的位置如果桶为空直接放入如果桶不为空遍历链表找是否有相同key有则覆盖没有则尾插链表长度达到阈值就树化。另外还要知道HashMap不是线程安全的多线程put可能导致死循环JDK 1.7的bug或数据覆盖。ConcurrentHashMap则是用CAS和synchronized锁住桶头节点来实现线程安全。如果主语言是C那考点主要集中在内存管理new和malloc的区别、智能指针unique_ptr/shared_ptr/weak_ptr的使用场景、虚函数和虚函数表、深拷贝和浅拷贝。尤其智能指针笔试选择题特别喜欢考“下面哪个智能指针可以解决循环引用”答案是weak_ptr它是为了解决shared_ptr互相引用导致内存无法释放的问题而设计的。我的建议是不管是C还是Java你都要把语言基础过一遍“面试高频50题”。笔试选择题的难度不会超过面试但考察的知识点几乎一致用面试的标准去准备笔试完全是降维打击。4.2 编程题常见的三种题型和应对思路编程题部分我根据经验把常见题型分成了三类字符串处理、数据结构模拟、基础算法思想。下面给出一道和当年考题风格非常像的题目以及我的完整思考过程。题目给定一个字符串请你找出其中不含有重复字符的最长子串的长度。例如输入abcabcbb输出3。这道题是LeetCode原题第3题难度中等但笔试时很多人写不对。最直观的思路是暴力枚举所有子串并检查是否有重复字符时间复杂度O(n^3)在数据量大时直接超时。正确的解法是滑动窗口用两个指针维护一个不含重复字符的窗口用HashSet记录窗口内的字符。右指针每向右移动一位就检查新字符是否在集合中如果在就移动左指针并删除对应字符直到集合中没有该字符然后更新最大长度。我这里给一个Java实现public int lengthOfLongestSubstring(String s) { SetCharacter set new HashSet(); int left 0, right 0, maxLen 0; while (right s.length()) { char c s.charAt(right); while (set.contains(c)) { set.remove(s.charAt(left)); left; } set.add(c); maxLen Math.max(maxLen, right - left 1); right; } return maxLen; }这道题的关键点有两个一是窗口的维护逻辑内层while循环保证每次加入新字符后窗口内没有重复元素二是左指针移动时要从集合中移除对应字符很多人漏掉这一步导致结果错误。笔试OJ对代码的判定很严格边界条件比如空串、全重复字符都要考虑到。除了这种窗口类题目服务端笔试还喜欢考链表、二叉树、栈、队列这些基础数据结构的操作题。比如反转链表、用两个栈实现队列、判断二叉树是否对称、实现一个LRU缓存。这些题目没有太多技巧就是看你基本功扎不扎实。我建议你把LeetCode上“字节跳动”标签下的简单和中等题刷一遍覆盖度基本就够用了。还有一个编程题的隐蔽考点是输入输出。有些平台要求你自己处理标准输入输出比如连续读入多组测试用例。很多同学平时在LeetCode上写惯了函数题到了要写main函数和Scanner/BufferedReader的地方就卡壳。笔试前一定要去牛客网刷几道输入输出练习把字符串分割split、整数转换、多行读取这些操作练熟否则你会死得很冤。5. 笔试实战策略90分钟如何把卷面分最大化最后一个部分我想聊聊比知识更重要的东西——考场上的策略。很多同学笔试没过不是不会做题而是不会“考试”。奇安信这类公司的笔试有一个特点题量大时间紧选择题、简答题、编程题混杂在一起如果你的做题顺序不对很容易陷在某一道题里出不来最后编程题根本没时间写。我的做题顺序建议是先花3到5分钟把整张卷子快速浏览一遍了解题型分布和每一部分的难度。然后按照“先易后难、先客观后主观”的顺序答题。具体来说先做选择题中自己有把握的题遇到不确定的不要死磕标记一下先跳过。选择题全部过一遍后做简答题中背过的、熟悉的知识点再跳过来想那些需要深入思考的题。最后留出至少40分钟给编程题。编程题的时间分配也有讲究。如果编程题有两到三道先做最简单那道确保AC再做中等难度的。宁可只AC一道题也不要三道题都写了一半。笔试的评分系统通常按通过的测试用例数给分一道题你写对了80%的用例能拿80%的分数但三道题都只写对50%的用例总分会很难看。简答题的答题技巧是“分点作答、先结论后解释”。比如问“死锁的四个必要条件是什么”先列出四个条件的小标题再逐一展开一句说明。面试官批卷时看的是关键词你分点写清楚了他一眼就能找到给分点。相反如果你写一大段话让他自己找即使意思全对分数也可能打折扣。另外一个容易被忽略的点是笔试和面试的联动。很多同学考完就忘了自己写了什么结果面试时被问到“你笔试最后那道题是怎么优化的”直接哑口无言。我建议你在笔试结束后尽快把自己没做出来的题和犹豫过的选择题重新查一遍资料理清思路。别小看这一步奇安信这类公司面试时面试官手边就放着你笔试的答卷和判分结果他们很可能从中挑题目追问。你如果能在面试时把自己当时的思路和复盘后的答案讲一遍会大大加分。还有一点关于复习节奏的建议。如果距离笔试还有一到两周我推荐的时间分配是这样的40%的时间看计算机网络和操作系统30%的时间看数据库和Linux20%的时间刷算法题10%的时间背语言基础。这个分配比例也许和你平时的复习习惯不同但它和笔试的考点占比是匹配的。别再用“我算法题还没刷完”来给自己拖延的借口了把选择题的分数拿到手你就已经赢了一半。最后再说一个我在辅导学弟学妹时反复提到的心得春招的笔试是一个“快速反馈”的环节你不需要等到所有知识都复习完才去投简历。大胆投多投几家把每一次笔试都当作一次查漏补缺的机会。我认识一个同学秋招前两个月每天都在刷LeetCode结果第一次笔试选择题错了一半他后来花了三天把网络和操作系统过了一遍第二次笔试就通过了。笔试就是这样你准备的方向对了通过就是水到渠成的事。