从3月开始正式投递,到现在,大大小小经历了十几场笔试,来来回回也算经历了不少的面试,从一开始的踌躇满志到慢慢开始接受现实,这两个月来的经历确实让我开始认清自己,在梦想和现实中慢慢找寻平衡。
深感自己能力的不足,但是又不甘就这样停歇,既然决定将此作为毕生的事业,那就不要抱怨,一心一意,不断向前吧。
分享这几个月的面试经验
腾讯
一开始投提前批的时候期望挺高,结果投了几家公司都杳无音讯,倒是腾讯成为了我的首家面试公司。第一次面试感觉确实很紧张,虽然对腾讯的面试重点有所了解,但是准备依然不充分。面试官还是非常和蔼,这让我慢慢放松了下来,但是最后还是败在了算法题上面
一面
计算机网络
IP报文头有哪些?
当时没有提前准备,凭着很早的记忆勉强说了出来
ttl
的作用生命周期,标记IP数据包转发的最大跳数,防止在计算机网络上无休止地循环
拥塞控制
https
怎么优化(这个确实比较懵)看了一下博客,大致总结这些:
False Start:客户端在发送
Change Cipher Spec Finished
同时发送应用数据(如 HTTP 请求),服务端在 TLS 握手完成时直接返回应用数据(如 HTTP 响应)。这样,应用数据的发送实际上并未等到握手全部完成,故谓之抢跑·启用TLS False Start可以节省一个RTT时间,但是客户端和服务端都需要支持
NPN
/ALPN
,需要采用支持前向保密的密码套件,即使用ECDHE进行密钥交换。减少证书大小,例如 ECC(
Elliptic Curve Cryptography
,椭圆曲线密码学)证书Session Resumption
会话复用:将第一次握手辛辛苦苦算出来的对称密钥存起来,后续请求中直接使用。这样可以节省证书传送等开销,也可以将 TLS 握手所需 RTT 减少到一个。实现方法:利用
sessioinID
判别客户端身份,Session Ticket
是用只有服务端知道的安全密钥加密过的会话信息,最终保存在浏览器端。浏览器如果在ClientHello
时带上了Session Ticket
,只要服务器能成功解密就可以完成快速握手。选用合适的加密算法
实现一个TCP服务器(一开始不懂具体要问什么知识点,面试官再补充了一下才大致明白应该是考察
IO
、socket
这些的…)
要说出连接socket
建立服务端客户端的具体过程
规则:正等待连接请求的一端有一个固定长度的连接队列,该队列中的连接已被TCP接受(完成三次握手),但还没有被应用层接受。注意:TCP接受一个连接是将其放入这个队列,而应用层接受连接是将其从该队列中移出。也就是使用*\.accept()函数来阻塞等待客户的请求**。
应用层指明该队列的最大长度,这个值被称为“积压值(backlog)”,范围为0~5。也就是使用*\.listen(5)函数来指定的队列长度。通常取值5**
当一个连接请求到达时,TCP使用一个算法,根据当前连接队列中的连接数来确定是否接收这个连接。这不同于积压值,积压值说明的是TCP监听的端点已被TCP接受而等待应用层接受的最大连接数。这个积压值对系统所允许的最大连接数,或者并发服务器所能并发处理的客户数,并无影响。
如果对于新的连接请求,该TCP监听的端点的连接队列中还有空间,TCP模块将对SYN进行确认并完成连接的建立。但应用层只有在三次握手中的第三个报文段收到后才会知道这个新连接。另外,当客户进程的主动打开成功但服务器的应用层还不知道这个新连接时,它可能会认为服务器进程已经准备好接受数据了。此后,如果客户程序发送数据,服务器的TCP模块会将接收的数据放入缓存队列。
如果对于新的连接请求,连接队列中已没有空间,TCP将不理会收到的SYN,也不发回任何报文段(包括RST),这是一个软错误,而不是一个硬错误。如果应用层不能及时接受.listen(5)中的连接,达到积压值(5),客户的主动打开最终也将超时
nginx
负载均衡的策略(当时真的没有复习到这..)
weight
权重判断- 时间片轮转
fair
根据响应时间ip hash
url hash
Linux
- 进程间通信的方式,最常使用的有哪些?
- 进程的内存结构,堆栈的区别
- 管道的注意事项
- 如何避免死锁
- 避免多次锁定。尽量避免同一个线程对多个
Lock
进行锁定。例如上面的死锁程序,主线程要对 A、B 两个对象的Lock
进行锁定,副线程也要对 A、B 两个对象的Lock
进行锁定,这就埋下了导致死锁的隐患。 - 具有相同的加锁顺序。如果多个线程需要对多个
Lock
进行锁定,则应该保证它们以相同的顺序请求加锁。比如上面的死锁程序,主线程先对 A 对象的Lock
加锁,再对 B 对象的Lock
加锁;而副线程则先对 B 对象的Lock
加锁,再对 A 对象的Lock
加锁。这种加锁顺序很容易形成嵌套锁定,进而导致死锁。如果让主线程、副线程按照相同的顺序加锁,就可以避免这个问题。 - 使用定时锁。程序在调用
acquire()
方法加锁时可指定timeout
参数,该参数指定超过timeout
秒后会自动释放对Lock
的锁定,这样就可以解开死锁了。 - 死锁检测。死锁检测是一种依靠算法机制来实现的死锁预防机制,它主要是针对那些不可能实现按序加锁,也不能使用定时锁的场景的。
- 避免多次锁定。尽量避免同一个线程对多个
java
hashmap
的内部结构,介绍了hash
算法、rehash
机制
数据库
innodb
和myISam
的区别redis
的数据结构,跳表的实现 随机化层数的算法- 完全二叉树的深度
数据结构
- 归并排序的时间复杂度
- 深度优先遍历和广度优先遍历使用的数据结构(栈)
topK
问题
场景题
两个文件存储qq号,如何去重
bitMap
+ 布隆过滤器分布式ID,最节约内存的方法
如果数据库存分布式ID,如何保证分布式ID的唯一性,(数据库同步)
- 唯一索引自增
redis
自增UUID
- 雪花算法
代码题
两个树,用数组表示,结合成一个有序数组
做的很勉强,其实不用想太多,直接树化,中序遍历
二面
根据一面的情况,自己也感觉应该是挂了 ,但居然还有二面。虽说是二面,实际上感觉就是在刷kpi
,甚至没有给代码题,问的问题都很敷衍,感觉就是根据题库随机抽题问,面完后反手就给挂。,真不理解这样的面试意义何在,从面试者的角度这样从一开始就没有结果的面试就是在挥霍我们的期待,有点败坏好感。
计算机网络
- IP报文头
- 传输层报文头
- 为什么出现IP报文
- 一个文本怎么从一个主机传到另一个主机
linux
基础命令
虚拟地址空间
c文件到可执行文件的编译过程
动态链接和静态链接
系统库和标准库的区别
一个是商家自行开发,一个是语言标准的函数库
数据库
- 查询语句
- 创建索引的sql语句
1 | CREATE INDEX index_name |
web开发
- 你了解过一些安全方面的东西吗
- 怎么调试BUG
情景题
黑帽子白帽子,至少一人戴黑帽子,如果自己是黑帽子则鼓掌,三次开关灯后才有人鼓掌,问黑帽子几顶(想了好久才想出来的,感觉有点博弈论的感觉)
三顶。如果是一个人戴黑的,第一次熄灯他发现所有人都是白帽,所以他必然黑帽;可是没有人鼓掌,证明所有人看到其他人有戴黑帽的,如果是两个人,那么第二次熄灯那两个人会一起鼓掌,因为他们知道肯定不只一个黑帽子,可自己只看到一个黑帽子,所以肯定自己也是黑帽子,以此类推,结果就是,熄几次灯几个黑帽子
两城市距离s,两列车AB相向而行,一无人机速度c,快于AB,飞到AB后返回,问最后AB相遇的时候无人机飞的距离
AB相向而行,距离为s,速度就是
a+b
,时间就为s/(a+b)
鸽子的速度为c,它直到AB相遇消耗的时间为s/(a+b)
那么它所飞行的路程=速度*时间=c*[s/(a+b)]=cs/(a+b)
5月15日更。
正式批明明没有做笔试,结果居然还有电话面。。这个时候我已经没有在准备面试了,所以答得不是很好。。这次的面试官就没有上一次那么亲切了,有点咄咄逼人,不管怎样还是自己技术太菜了。
正式批电话面
- UDP和TCP java怎么实现的?
- 现在for循环10词连接UDP,端口号是否会释放(SQL连接是否会释放)
- 如何实现共享内存?(内存淘汰机制,线程安全性)
- 大文件存放字符串,求出现次数最多的TOP5
- 一张表,时间,用户ID 奖品ID 班级 求 XX时间段中获奖次数最多的学生ID和领取次数最多的奖品ID
1 | SELECT stuId,count(*) as count FROM (SELECT * FROM tab WHERE time < xxx AND time > xxx) GROUP BY stuid ORDER BY count(*) LIMIT 5 |
蘑菇街
蘑菇街是我面试了才知道的公司,确实公司现在的运营也不是很好,但不得不说还是一家标准的互联网公司,在后面也通过一些博客专栏作者比如敖丙了解到了公司的内部情况和未来的发展,不得不说对我的准备和未来规划还是起到了一定的影响。最后终止于二面(话说刚看到公司裁员就收到了感谢信…)倒也没什么遗憾的。
一面
一面问基础问的有点偏。。
Java基础
swap(Integer a,Ingteger b)
如何交换- 使用数组传参(这道题不允许)
- 使用自定义类,
set
、get
(这道题不允许) - 由于
java
中对于非原生类型都说传递引用,而对于原生数据类型都说通过传递值的方式传递参数的,如果仅仅通过传递值的方式来交换a,b的值,在Java
中是不可能实现的 Integer
虽然不是原生类型,但是jvm
对这种类型添加了缓冲池,每次
Mybatis使用原理
- 内部原理
- ${} 和 #{}的区别
Spring
- 事务
mysql
事务的实现原理
在事物进行过程中,未结束之前,
DML
语句是不会更改底层数据,只是将历史操作记录一下,在内存中完成记录。只有在事物结束的时候,而且是成功的结束的时候,才会修改底层硬盘文件中的数据mysql
任意一条DML
语句代表事务的开启,同时默认自动提交事务,如果要开启回滚,需要手动提交事务。事务的提交和回滚是如何实现的
begin
/start transaction
命令并不是一个事务的起点,在执行到它们之后的第一个操作InnoDB
表的语句,事务才真正启动。如果你想要马上启动一个事务,可以使用start transaction with consistent snapshot
这个命令。
已知索引
A(a,b,c)
现在有
sql
语句:where b > 1 and a = 1and c =1
请问是否能应用索引?
现在有
sql
语句:where a = 1 and b > 1 and c =1
请问是否能应用索引?
考的是最左匹配原则
sql
语句优化的过程
项目架构
介绍一下项目
多线程技术的考量
消息队列
如何防止消息被重复消费
如何防止消息被重复生产
仅考虑项目出现重复消息推送,可以加同步锁
Kafka
的消费机制这个算给自己挖坑的。。明明不太熟悉还要提233
总结
- 基础知识掌握不牢,尤其是索引这块具体描述的时候无法清楚描述
- 讲解项目的时候给自己挖坑了
- 情景题的临场发挥能力,一些基础的讲述能力,MVCC完全没有讲好
二面
过了好久的二面。。
问了项目应用
jwt
的原理如何保证数据的一致性
结合应用场景谈谈
redis
如何保障数据一致性我还是没答上来,注意这和重复提交、分布式锁是不同的
文件上传为什么不能放在本地(结合无状态考虑)
FTP协议上传文件
文件存放在本地的话无法通过用户登录知道用户信息(参照JWT)
线上出现数据缓存不一致问题怎么解决?
作业帮
作业帮面试体验还行吧,看的出来问的问题不是很深,和大厂果然没法比,最后收了offer,但是拒了
一面
项目架构
简单讲讲你的项目架构、内容、负责部分
怎么实现的爬取
怎么实现的订阅服务
数据库
redis
的数据结构redis
的分布式锁实现redis
各种数据结构的应用场景redis
自增如何保证原子性redis
是单线程的mysql
事务、ACID
B+树的实现机制
web方面
- 怎么理解restful设计规范
代码
- 回型打印二维数组
二面
- 项目
分布式事务
- 分布式事务了解过吗?
- 分布式事务的特点
- 二段式提交 三段式提交
计算机基础
…忘记了,比较常规
算法
- 排序的时间复杂度
- 递归的时间复杂度
OPPO技术面
真不知道oppo光靠一面技术面还没有代码是怎么选人的。。
数组和链表的底层区别
数组的查询和链表的内存查询有什么不同
在操作系统内存管理方面也有不同。正因为数组与链表的物理存储结构不同,在内存预读方面,内存管理会将连续的存储空间提前读入缓存(局部性原理),所以数组往往会被都读入到缓存中,这样进一步提高了访问的效率,而链表由于在内存中分布是分散的,往往不会都读入到缓存中,这样本来访问效率就低,这样效率反而更低了。在实际应用中,因为链表带来的动态扩容的便利性,在做为算法的容器方面,用的更普遍一点。
mysql
线程是异步的吗
- 部分是部分不是
- IO线程异步的原因是并行执行,同时可以刷新邻页
异步通知会出现什么问题
- 如何保证断电后数据恢复
数据一致性问题
在
MySQL5.5
以及之前,slave
的SQL
线程执行的relay log
的位置只能保存在文件(relay-log.info
)里面,并且该文件默认每执行10000
次事务做一次同步到磁盘, 这意味着slave
意外crash
重启时, SQL 线程执行到的位置和数据库的数据是不一致的,将导致复制报错,如果不重搭复制,则有可能会导致数据不一致。MySQL 5.6
引入参数relay_log_info_repository
,将该参数设置为TABLE
时, MySQL 将 SQL 线程执行到的位置存到mysql.slave_relay_log_info
表,这样更新该表的位置和 SQL 线程执行的用户事务绑定成一个事务,这样 slave 意外宕机后, slave 通过 innodb 的崩溃恢复可以把 SQL 线程执行到的位置和用户事务恢复到一致性的状态。MySQL 5.6
引入GTID
复制,每个GTID
对应的事务在每个实例上面最多执行一次, 这极大地提高了复制的数据一致性;MySQL 5.5
引入半同步复制, 用户安装半同步复制插件并且开启参数后,设置超时时间,可保证在超时时间内如果binlog
不传到 slave 上面,那么用户提交事务时不会返回,直到超时后切成异步复制,但是如果切成异步之前用户线程提交时在 master 上面等待的时候,事务已经提交,该事务对 master上面的其他session
是可见的,如果这时 master 宕机,那么到 slave 上面该事务又不可见了,该问题直到 5.7 才解决;MySQL 5.7
引入无损半同步复制,引入参rpl_semi_sync_master_wait_point
,该参数默认为after_sync
,指的是在切成半同步之前,事务不提交,而是接收到 slave 的 ACK 确认之后才提交该事务,从此,复制真正可以做到无损的了。
延时性·
- 5.5 是单线程复制, 5.6 是多库复制(对于单库或者单表的并发操作是没用的), 5.7 是真正意义的多线程复制,它的原理是基于
group commit
, 只要master 上面的事务是group commit
的,那 slave 上面也可以通过多个 worker线程去并发执行。 和 MairaDB10.0.0.5 引入多线程复制的原理基本一样。
1 | mysqldump用于备份,记录一下 |
redis
锁提前释放了怎么办
主从同步怎么防止锁不丢失
redlock
实现分布式锁的一个非常重要的点就是set的value要具有唯一性,
redisson
的value
是怎样保证value
的唯一性呢?答案是UUID+threadId
如果锁丢失了怎么解决
epoll
和poll
多线程
volatile
和锁的区别多线程中线程出现异常会怎样
- 线程代码中产生异常的话,那么这个线程的生命周期就结束了,这种情况称为线程泄漏。
- 注意,只是这个线程的生命结束了,但其他的线程还是活着的。如果是代码有 BUG,那其他线程走到这一块估计也会挂掉的。
FileStream
阿里电话面
阿里确实要求很高,流程也很长,自己面的时候总归有点放弃的感觉。但是从电话面中我确实体验到了什么叫深挖项目,几乎对每一个细节都进行了深挖,只要自己稍微给自己挖坑就凉凉了。。这也算得到了一种经验吧
心得:主要在于对待架构的需求,为什么需要这样做
做项目的时候遇到什么样的问题?答:跨域
- 跨域问题怎么出现的协议 + 域名+ 端口
- 解决方法:
nginx
或者请求头添加允许跨域标识
分布式锁。单机为什么要用分布式锁?
多个请求同时插入如何保证幂等性
不用
redis
防止重复请求数据库幂等(idempotent、idempotence)
在编程中.一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。例如,“
getUsername()
和setTrue()
”函数就是一个幂等函数.
如何防止重复提交
redis
+计数器,大于1表示重复,问题就转换成如何生成唯一ID的情景mysql
的唯一索引,出现报错就处理返回token
机制:防止页面重复提交。原理上通过
session token
来实现的(也可以通过redis
来实现)。当客户端请求页面时,服务器会生成一个随机数Token
,并且将Token
放置到session
当中,然后将Token
发给客户端(一般通过构造hidden
表单)。
下次客户端提交请求时,Token会随着表单一起提交到服务器端。服务器端第一次验证相同过后,会将
session
中的Token
值更新下,若用户重复提交,第二次的验证判断将失败,因为用户提交的表单中的Token
没变,但服务器端session
中Token
已经改变了。
字节一面
字节确实面的很紧张。一来是因为字节的机遇确实大,只要搏一搏就有很大的希望进去,但另一方面,算法又是我的薄弱项,于是自己总是在不断的准备,犹豫,造成了直到面试也是出现了比以往还有激烈的兴趣反应。这就是自己的心态管理还不到位的缘故。最后期望越大,失望越大。
项目
- 分布式锁实现
数据库
mysql
的事务特性和隔离级别
多线程
- 同步异步、阻塞非阻塞
git和maven
git
怎么修改已提交的文件maven
的多模块是什么
设计模式
- 知道的设计模式
- 单例模式的写法(败笔!绝对的败笔,可见自己平时没有完全理解,一直以为自己能写出来结果在现场却掉链子了)
编程题
- 二叉树求和 回溯
智力题
单极管 两两触碰能指示对方的好坏,好的能指示正确结果,坏的指示结果不确定,现在好的数量大于
n/2
,问怎么将好的和坏的区分出来?时间复杂度多少?只要 和所有比对,好的大于
1/2
就可以确定他是好的
美团一面
美团是我期望最大的公司,我也为此做出了自以为最充足的准备。但是最后依然惨淡收场。虽然算法题没有写出来是最大的问题,但是这次给我最大的感悟是面试官在面试中指出了我的性格问题,这是第一次我被指出技术以外的问题,这个问题也是我一直不自知的。那就是我在面试中体现出来的强答,自以为是在赌运,但在面试官面前,不懂装懂是最大的无知。
知之为知之,不知为不知,是智也。
这次面试是值得的。
hashmap
负载因子?(这个我那时候想错了,是我的失误,但在面试官看来只是我的不懂装懂,因此给他留下了不好的印象)B+树和红黑树的区别
红黑树性能稳定但为了维持稳定需要更多开销,不适合实现快速查找的功能
算法题
- 倒水问题: 10 7 3
头条一面
字节过后的头条,这时的我对面试已经疲倦了,整体的面试状态非常不好,自然没有过
linux
保持后台运行的命令- 把程序放后台运行,简单的话,只要在命令后面加一个“
&
”, 如:php test.php &
- 或者在运行命令后,按一下
Ctrl+Z
,如运行php test.php
后,按一下Ctrl+Z
- 程序在后台运行了,但还是看到输出信息,可以用管道命令把输出定向到
/dev/null
,如:php test.php >/dev/null
- 普通的输出信息看不到了,但还是看到一些信息,如错误信息等,需要再添加
2>&1
命令,如:php test.php >/dev/null 2>&1
- 程序在后台运行了,但退出当前会话,发现程序还是停止了,此时要用
nohup
命令,如:nohup php test.php >/dev/null 2>&1
- 使用
nohup
后,应确保用exit
命令退出当前账户,非常正常退出或结束当前会话,在后台运行的作业也会终止 - 命令在后台运行了,怎么查看?使用jobs命令可列出当前会话的后台任务,
jobs -l
能查看到PID
,进而可以用kill
终止某个任务 - 是终命令可能是:
nohup php test.php >/dev/null 2>&1 &
- 把程序放后台运行,简单的话,只要在命令后面加一个“
linux
查看cpu
使用率的命令java
查看CPU
使用参数的命令mysql
索引查询
算法
平方根
跳台阶 动态规划!!
CVTE电话面
主要是数据库设计相关有点新意
京东电话面
搞突袭,都5月了才开始,着实有点尴尬
自动装箱拆箱
int
存放在哪里常量池 基本数据类型l
创建线程有哪几种方法