第5章 笔试 重生10:我在企鹅做推手
九点五十八分,打开瀏览器,输入腾讯笔试系统的网址。
九点五十九分,登录——帐號密码他早就背熟了。
十点整,笔试页面准时刷新。
第一部分,计算机基础,30道选择题。
林深扫了一眼题目,嘴角扯了扯。大部分都是死记硬背的东西:osi七层模型每层的功能、进程和线程的区別、死锁的四个必要条件……对他来说,这些知识点就像呼吸一样自然。
二十二分钟后,第一部分完成。
系统自动跳转到第二部分:逻辑推理,20题。
图形推理、数字序列、语言逻辑……林深遇到第三题时卡住了——那是一道复杂的立方体展开图旋转题。他盯著屏幕看了半分钟,直接点了“標记,稍后回答”。
跳过去。
他做得很从容,甚至有点……享受。每解出一道题,他就在心里对自己说:看,这就是不用加班、不用改“按钮向左移2像素”的bug、不用听老吴吼叫的生活。纯粹的逻辑,乾净的思维,多好。
四十五分钟时,前两部分全部完成。
系统跳转到编程题环节。
第一道:给定一个字符串,找出其中最长的回文子串。
经典题。林深几乎不用思考,手指就在键盘上飞起来。他写了一个中心扩展算法,时间复杂度o(n2),空间o(1)。写完后,他想了想,又在注释里加了一段:
“如果字符串长度超过10^6,建议使用manacher算法,时间复杂度可降至o(n)。但考虑到本题明確说明输入规模较小,且manacher算法实现较复杂、可读性差,故採用更易於理解和维护的中心扩展法。”
这既展示了知识面,又体现了工程权衡。
第二道:两数之和的变种,找出数组中所有不重复的和为目標值的元素对。
又是昨晚重点复习过的题型。林深先排序,再用双指针,同时小心处理重复元素。代码写完,他特意测试了几个边界用例:空数组、所有元素相同、目標值比所有元素都小……
十一点零五分,两道编程题提交。
系统最后一次跳转。
最后一道题:系统设计。
题目描述简洁得让人心悸:“设计一个简易的即时通讯系统,支持一对一文本消息发送。请从客户端、伺服器、协议、存储等角度简要阐述你的设计思路,並重点说明如何保证消息的可靠投递。”
林深盯著这行字,沉默了很久。
机房的嗡鸣声在耳边持续。
他有答案。他太有答案了——前世在微信团队七年,参与过消息系统从简单到复杂、从单机到分布式的整个演进过程。他知道每一个坑在哪里,每一种权衡背后的代价,每一次架构升级的痛苦。
但他不能写。
现在是2010年。iphone 4刚刚发布,android 2.2还叫froyo,行动网路主要是2g和初生的3g,智慧型手机普及率还很低。他不能把2018年的微信架构直接搬过来。
他需要写一个“2010年的聪明人会想出来的方案”。
一个符合当时技术现实、却又隱约透出一点前瞻性的方案。
一个既扎实、又有点“小聪明”的方案。
林深开始敲字。
他写得很快,但很克制:
客户端:基於tcp长连接,心跳保活(30秒一次),断线自动重连(指数退避)。
伺服器:简单的连接管理(用字典存userid->socket映射),消息路由(查字典转发),消息先存內存队列,再异步刷到磁碟文件。
协议:自定义二进位协议,包头包含消息类型、长度、序列號、发送者、接收者、时间戳。
可靠投递:发送方等待伺服器ack,伺服器存储成功后回ack,接收方收到后回送达回执。每个环节都有超时重传,最多三次。
写到这里,他停下来。
他看著屏幕上自己写的东西,眉头慢慢皱起来。
太普通了。
这就像一份教科书式的標准答案,每个学过网络编程的大学生都能写出来。挑不出错,但也绝不会让人记住。
他需要一点……不一样的东西。
林深看了眼时间:十一点二十分。还剩四十分钟。
他看了眼系统界面:
【摸鱼幣余额:1.02】
【可用技能:子弹时间·初级(1幣/次)】
用。
【是否使用子弹时间·初级?消耗1摸鱼幣,持续5分钟。】
【是】
一瞬间,世界变了。
不是时间停止,而是……思维的速度被强行拔高了一个维度。
耳边伺服器群的嗡鸣声陡然退远,变得像隔著厚厚的水层,模糊而缓慢。眼前屏幕上的文字却异常清晰,每一个像素都锐利得刺眼,光標每秒一次的闪烁慢得像在呼吸。
但他的思维在狂奔。
前世那些记忆碎片——技术討论会的爭吵、架构文档的版本变迁、线上事故的復盘报告——此刻不再是零散的画面,而是被某种无形之力串联、编织,形成一张立体的知识网。
他想到了几个关键点:
移动特性。现在是2010年,智慧型手机正在崛起。设计不能只考虑稳定的wi-fi环境,还要考虑蜂窝网络的不稳定、高延迟、频繁切换。可以在协议头里加一个“网络类型標记”(wi-fi/3g/2g),客户端根据这个標记决定一些行为——比如在2g下,不发大的图片预览;在电量低於20%时,主动告诉伺服器“进入节电模式”,让伺服器延迟非紧急消息的推送。
状態同步的简化。当时的im系统,比如手机qq,喜欢搞复杂的用户状態:在线、离开、忙碌、隱身、q我吧……其实大部分都没用。他可以提出一个极简理念:只区分两种状態——“可送达”和“不可送达”。在线、离开但可接收消息?都是“可送达”。离线、隱身?都是“不可送达”。乾净,省资源,减少同步开销。
存储的演进路径。不要一上来就设计一个复杂的、能支撑亿级用户的存储架构。那太假,面试官反而会觉得你不踏实。他应该写一个“演进式设计”:初期用户少,直接用文件存储+內存缓存;用户上十万了,迁移到mysql单表;上百万了,mysql分库分表;上千万了,引入nosql做冷热数据分离,热数据存redis,冷数据存hbase。这叫务实的前瞻性——我知道未来会怎么样,但我从最简单、最靠谱的开始做。
一个小创新点。可以在消息头里加一个“內容特徵標记”——比如这条消息是纯文本、是图片、是语音、是文件。客户端根据当前网络状况和电量,决定是否预载非文本內容。比如在wi-fi下,自动预载小图预览;在3g下,只载文本,图片要用户点开才下载。这在2010年还是个很新的概念。
思路如溃堤的洪水,汹涌而出。
林深的手指在键盘上疯狂敲击。不是写代码,而是写设计思路。他摒弃了冗长的段落描述,採用清晰的条目式结构。
他写得飞快,手指几乎在键盘上留下残影。
五分钟,三百秒。
在思维加速150%的状態下,这相当於七分半钟的高质量输出时间。
当【子弹时间】效果结束的提示浮现时,林深已经写满了整整两屏的答题区。
他停下手,快速滚动瀏览自己写的內容。
逻辑清晰,层次分明。基础部分扎实得无懈可击,创新部分又恰到好处地亮眼——既不过分超前到脱离2010年的技术现实,又隱约指向了移动网际网路未来的发展方向。
完美。
他长长呼出一口气,感觉太阳穴在突突地跳。高强度思维加速的后遗症开始显现,有点晕,有点反胃。
但他没时间休息。
十一点二十五分,还剩三十五分钟。
他重新回到试卷开头,从第一道选择题开始,一道一道检查。修正了两处粗心导致的选项错误,优化了一道编程题的边界条件注释。
十一点五十五分,距离截止还有五分钟。
他最后一次滚动页面,確认没有遗漏。
然后,光標移到页面最下方的“提交”按钮。
点击。
页面跳转,出现一行简洁的蓝字:
“笔试已完成,感谢参与。结果將在3-5个工作日內通过邮件通知。”
林深靠在椅背上,闭上眼。
【摸鱼幣余额:0.76】
哈?
考试也被算在了摸鱼里?
林深几乎在此时拥有了双倍的快乐。
只是,【子弹时间】的后遗症还在,但那种在子弹时间里思维清晰、灵感迸发、仿佛能看见知识脉络在眼前流动的感觉——真的,会让人上癮。
他在椅子上坐了很久,直到心跳慢慢平復,直到晕眩感退去,才开始慢条斯理地收拾东西。
“吴经理,工具包部署好了!”