基础平台研发面经

秋招才刚开始,原则上是不应该放面经的。我个人十分不赞成投机取巧,知识面狭窄的问题,绝非面经能够解决,有时可能适得其反。

无奈的是应该有不少实验室做的研究和业界(客气点说)实在不太对口,相信大家在内推阶段或多或少的遇到过类似的困扰,面试不好并不是我平时偷懒,而是因为面试官只问他们感兴趣的/擅长的,对于自己不懂的,总有那么一点“不屑一顾”的感觉。

我的个人经历证实,这些情况确实是存在的,大多数面试官还是会尝试让你去解释研究工作(虽然对方并不一定感兴趣),只不过此时更多考察个人的表述能力。

从7月初到9月初,各大公司的优招、内推,我基本都参加了,投递岗位涉及编译器开发、服务架构、基础平台研发(网络、存储)等,该拿的offer基本都到手了,所以稍作总结,如果你也是这个方向的,相信是具有一定的参考意义的。

问题大致涵盖如下方面:

  1. 基本算法
  2. Linux命令的使用
  3. 操作系统(着重)
  4. 网络(着重)
  5. 数据库
  6. 编译技术
  7. 分布式

面试基本会涉及如下几个环节:

  1. 自我介绍
  2. 手撸代码(通常是一面)
  3. 领域问题考察
  4. 项目细节考察
  5. 系统设计题(通常是架构岗)

现场要求写的代码都很简单(不知道是不是我遇到的比较简单),涉及一些递归、DP等,不会难于LC的middle级别,所以LC刷个200+就基本没问题了。

基本算法方面考察的主要是算法的应用场景,时间复杂度等,如果是C++相关岗位,可能会涉及一些STL中的数据结构,所以难免会遭遇红黑树。另外,由于B树和B+树在数据库中应用的较多,亦有可能考到。

遇到不会的问题很正常,关键看你怎么回答。若能够跟着面试官的节奏走最好,若是似懂非懂的状态,不要太坦诚,可以把你知道的完整地跟面试官解释一遍,按着自己的节奏走,这样就不会太尴尬了。

如果遇到的全是不会的问题,那么有2种可能:

  1. 你投错岗位了
  2. 你遇到了压力面(压力面当然可以出现在技术面中)

面试过程,更多的是一种技术交流,所以遇到不会的问题,最好请对方给一个答案。另外,你需要清楚,通过面试的关键并不是你回答对了多少题目,而是环比其他面试者,你的表现能排第几,能否挤进HC,当然前提是性格、智商和逻辑都没问题。。。

接下来给出领域问题,绝大多数问题只是大致回答,懒得详细阐述了,答案存在问题是难免的。

Linux使用

查看内存信息

free/vmstat/top/htop

查看磁盘信息

iostat

查看CPU信息

vmstat/top/htop

查看网络信息

netstat -i 网卡信息
netstat -a 连接信息
lsof -i:PORT 查看端口占用信息

proc目录的实现原理

procfs,内部使用sysctl实现

gdb调试,线程信息,线程栈

info stack/bt 调用栈
info threads 线程信息
thread id 切换线程
watch expr 监控指定表达式

buffer、cache和total的含义

IO写入时存放数据的内存page buffer
IO读取时存放数据的内存page cache

操作系统

进程和线程的区别

对于Linux内核而言,区别并不是很大。
进程的隔离级别更加高,可以使用命名空间等,IPC的代价稍大。
线程间共享进程的地址空间,所以数据交互更容易,代价也稍小,但是数据竞争更加严重,且一旦进程crash,所有线程也就不存在了。

进程切换所做的事情

保存寄存器现场
切换栈空间
处理内存页(最好深入一下)

线程同步机制

互斥锁、自旋锁、读写锁、条件变量

列举进程通讯的方式

PIPE、共享内存、Socket、文件、MQ等
其中共享内存最快,但是需要额外的工作才能保证数据的一致性

命名空间及其效果

UTS、IPC、PID、NS、NET、USER

cgroup的功能

限制CPU和内存的使用量/使用频率

VFS文件系统

磁盘中数据的存放

IO调度算法

为何需要IO调度?结合机械硬盘的工作原理,随机读写开销很大,因此可以通过汇总数据的方式实现顺序读写。
Anticipatory算法、Deadline算法、CFQ算法以及Noop(No Operation)算法
NOOP算法是最简单的IO调度算法,适合SSD,只需要将IO请求入队列即可。

虚拟地址、物理地址及其实现

进程中可见的地址是虚拟地址,物理地址对应真实的内存,虚拟地址通过MMU映射成物理地址,Linux采用的是4级页表(PGD、PUD、PMD、PTE),最终对应到CR3寄存器。
转换的方式为基址+“偏移”,由于页表保存在内存中,CPU访存代价过大,因此引入TLB缓存,每次映射时优先查找TLB。

网络

TCP状态图,结合握手和挥手

注意同时打开和同时关闭即可,其余结合TCP状态转移图进行理解。

异常状态的出现场景以及解决方案

大量SYN_RECV状态的连接,大量TIME_WAIT状态的连接等。

长连接和短连接

短连接:数据请求到达后即关闭连接
长链接:多次请求复用一次连接,需要清楚如何保证连接是否存活,如心跳信号等。

TIME_WAIT的等待时间,MSL的意思

MSL(Maximum Segment Lifetime)
TIME_WAIT后并不能保证最终的ACK能够安全到达对端,因此需要预留重传的时间,即等待2MSL。
可以通过SO_REUSEADDR规避2MSL的等待。

RTT如何估计

RTT(Round-Trip Time)
通过计时器获取连接的一次往返时间消耗,之后还有RTT估计器的计算,细节部分参考《TCP/IP详解 卷1》。

开启SO_REUSEADDR后可能会出现什么问题

可能接收到对端传回的FIN、RST等,造成莫名其妙的问题。

TCP如何保证其可靠性

重传机制、流量控制、拥塞控制

IP序号重合对上层的影响

由IP层负责在组包时解决,对上层无影响。

内核如何解决accept的惊群问题

使用了WQ_FLAG_EXCLUSIVE标记,确保只有一个进程会被唤醒。

用户态如何解决accept的惊群问题

多进程抢占自旋锁即可,使用pthread_spinlock或者共享内存+CAS自行实现。
进一步讨论,如何在这个阶段提供负载均衡。

数据库

面试官说我不懂数据库,所以问得很少。。。

悲观锁和乐观锁

SQL中如何使用锁

索引的实现方式和作用

加快数据检索的速度,但是写入时有相应的代价,所以适合读多写少的场景。
内存通常使用B+树实现。

编译相关

解释器和编译器

常见的误区:所谓编译,并非一定要求生成本地代码,只要从语言A转换到语言B,这个过程就是编译。

编译的流程

预处理-词法解析-文法解析-语义制导-抽象语法树(IR的一种)-三地址码(SSA)-优化(控制流图、数据流图)-汇编

动态链接库和静态链接库的区别

虚拟机如何重新加载脚本

关于热更新的讨论

分布式存储

redis、rockdb、leveldb的存储布局

SSD和HDD的区别使用场景

机械结构:主控+多FLASH芯片 vs 电机+磁盘+磁车
延迟:SSD的延迟至少比HDD低1个数量级
寿命:SSD的寿命主要由P/E次数决定,因此适合多读少写的环境
其实,对于顺序读写,hdd的开销也不是那么大,原因自己去计算,另外此处可以结合IO调度算法一起考察。

锁和MVCC的适用场景

视场景而定,如果数据竞争少,则优先使用MVCC,否则老老实实用锁。

HDFS的读写操作

metadata、membership的管理

etcd或者zookeeper,真的很方便哦~

副本一致性(RSM)

通过一致性算法,如Paxos、2PC、3PC、Raft等

主从使用push和pull的优缺点

主节点push可以保证一致性,如果无需考虑一致性,则从节点pull更加灵活,可以支持更多的从节点
仅有一条评论
  1. 虽然和主题不相关,但我还是想说,棒棒哒!

说两句: